 Ja, jeg er her til å snakke om Ember Jens, så jeg frågjorde hva jeg skulle holde opp, og jeg har tatt til å holde en holistisk snak, så jeg skal holde det å flyde, håpelig. Så det ikke blir virkelig hårdkort. Det blir noen baser og noen topikken som du ikke må ha sett før. Jeg har bare holdt en holistisk snak, så min hjertelighet er litt, så jeg er sikker på at jeg kommer inn. Så bare så kjort om meg. Min namn er Joachim, du kan kjenne meg Jo. Jeg arbeider som en indipendent konsulterer, som en frilanser, og det er hvor jeg gjør min mennesker, og så har jeg side-produkter som jeg gjør, hvor jeg høyder det for mye teknisk desang, ofte. Så denne som jeg er her, er at jeg har skrevet Ember Jens en aksjon. Så jeg tror det er den første maten som kommer ut på toppen av Ember. Og jeg har også organiseret Ember Fest, så vi var i Munich senere, og vi går til Barcelona i et par ganger. Tikkertelser har skrevet, men jeg har tikkert om noen vil gå til en veld i Barcelona og hanga ut. Vennerne er virkelig nødt til veld. Så dette er det jeg arbeider på min spærtid. Jeg har skrevet en monitoring agent, eller en monitoring app. Og jeg har skrevet en sort av CMS for Ember Data. Så det er ikke noe som håper kontenten som Wordpress, men det håper dataet, og det blir Ember Data compliant. Og via min lokale libere har jeg tjent til å køde. Og jeg har skrevet en materiale som vi har tjent online. Og vi har bare et brevet klipp om det, når vi prøver å se om Fandom.js, og se og optimisere det. Så jeg begynner usually to explain where Ember fits in the stack. Usually when I got started with Ember a couple of years ago, this is where it fit in. So sorry if you had an application that looked like an application, and it really looked like an application like Google Maps does, and that's where it would fit in. And it sort of inherited that from Sparkor, and with Sparkor it was even narrower up here. But as of the final release of Ember and moving towards the later releases, it stretches more and more out to encompass more types of applications. So there's still single page applications, but they can now look and behave more like a website than an application. So it fits in to a wider array of developers. But usually they are all single page apps. I haven't seen an Ember app that's not a single page app. They're highly interactive, and they often can have that wow factor that you're looking for, that you want your users to have when they use your software. So it really comes from the old age, where we didn't have, we had HTTP requests. And they weren't Ajax, or they weren't Async. They were just synchronous requests. And if you work with websites from the 2000s or from the late 90s, you know the pain points here. You make a request, you have to assemble everything up, package it up, send it to the client or the browser, and the browser would render that. And then there was no dynamicity after that. And then for the next request it had to do the same work, ship it off to the client, and so on and so forth. And then came Ajax, and it promised a whole new world. Now all websites would be dynamic, they would be fluent, and they would be a good user experience. So they sort of promised that you would send the whole package on the first request, and then after that you would only receive partial page updates. But it turns out that this is really, really hard, because unless you really tailor your backend, it's hard for the backend to know exactly what to send to the frontend. So if you have a sort of shopping cart implication and you add something to the cart, you both want to update the cart, but you might also want to update a part of the page that says, you might also want to look at these items. And if you have thousands of clients, just keeping, bookkeeping that state is difficult and it's hard to scale. Most Ajax frameworks, Dojo, and in Java we had a JSF, and we had others in .NET had their MVCs. And what they did was that for each request, they would still just ship you the whole package, and then the client would just pick from your DOM IDs and a cherry pick, and then swap them out. So now you had a client that was more dynamic, it felt more dynamic, and now had 20 times as much load, because everything the user did required a whole new request from the server. So this is where single-page applications come in, and they really follow up on that promise that on the first request you do get your whole application, the whole website, everything, and then once that's done you don't transfer anything but data. And that makes it a lot easier to scale, because the server doesn't really need to know where your client is at. You can be logged in on mobile and on your desktop, and you can have two different sessions, and the server doesn't really care, it just ships the data you ask for if you're allowed to view it. So Ember I think has the most complete MVC pattern, at least for web frameworks, but it also has, if you look at old MVC patterns for framework from Java or .NET, the Ember MVC pattern is also fairly complete. So it consists of views, and views also use templates to help render the DOM tree that the browser gets, so that it has enriched the view layer with a strong templating library. And on the controller side, it has enriched controllers with the Ember router, and the Ember router is really, at least in web frameworks, a game changer in how you can structure your application into separate chunks, and they can be completely separate without you having to sort of write jQuery spaghetti code. It really helps you to separate out your logic into a sane structure, and as long as you don't fight that structure, you'll be okay. Sometimes you do need to fight the built-in structure, but for the most part you can follow along that, and your code will be manageable. And Ember doesn't really have anything for the model, it has Ember object, but Ember data includes a rich model layer that you can tie in fairly easily, or really easily. Så, this sort of structure where your users or your actions go through Ember comes from Sproutcore, I think Eric Ocean, he was involved with the Sproutcore project, coined it the V property. And what it means is usually you start with initiating an action on the view, so the user clicks a button or a timer fires, or something happens on the view, and that fires an action to your controller, or your router, and that again asks for data in the model layer, and then bindings and observers will propagate that back up to your view. And you don't have to start here every time, but the important thing is that if you start here, like if you start with an async call into your model layer, the important thing is that Ember will keep your data flowing the right way, it won't suddenly start doing something in the view and then start this whole process again. Ja, sort of, went through this. So there are three main features that Ember relies on, and it relies on that heavily in its own API or its own library, and we use them often without really thinking about that we are using them. It has bindings, everyone that has used Ember for a while get to know bindings and how they work. And usually, before, earlier, before the first one of the overlays, I had a lot of bindings in my controllers with suffix binding to bind this content variable to whatever this other controller held in its selected notes. But these days I hardly ever use this. It's always bound via the handlebars templates. And then there's computer properties, and those are just, there are functions that can be exposed to your Ember templates. That's basically sort of a short narrative of what it is. And they are kept up to date whenever the values that they rely on update. And there's observers, and they are also normal functions, but they fire whenever some data you are listening to change. In other languages they're called listeners, and observers I think comes from rails. So I'll just talk a little bit about the Ember router, and then I'll move on to something more specific. So the router is the backbone of your application. It defines the logical path that the users are allowed to take throughout your application, as well as it helps structure your application's different parts into separate, containable areas. And that means that if you have an application that does, that has, say you have a photo album application, you can make sure that all the data that belongs with an album doesn't mix in with the data that belongs to your photographs, for instance. So we'll be looking at an application shortly, and it is a photo album application, and it's sort of a minimal styled application. It looks sort of horrendous, but the point is we're going to add some stuff to it. So we're going to add some animations, and we're going to look at binding your, sorry, binding your HTML properties, and some other stuff. Yeah, I'll just skip this, I think. I should have, sorry. Okay, so this is a simplified state chart for Ember data. It sort of looks like this is the normal path that your data has. So the data starts out loaded, meaning that it's come from the server side, and it's loaded okay in your application. So it's loading while it's waiting for it to come in, and then it's loaded once Ember data has completed its propagation into Ember objects. And then typically you'll make some edits to your data, which means that your models become dirty, and then you can save that data, which means it'll send it to the server side, and then it'll be in an in-flight mode until the server responds. So either it times out, and you get an error, or it can't be parsed, and the data is invalid, or it goes back to your loaded. So this is sort of the happy path for Ember data is sort of just within this circle. So I'll just explain quickly. It's sort of an overwhelming slide. I'll explain it in detail. So this is Ember data's view of the world. So Ember data is implemented as an identity map, and what that means is that for every time you ask Ember data for an object of a certain type with a certain ID, you can be sure that you get the same instance back. It won't create a new one, and that has the same data, but you actually get the very same instance. So in this case here you ask to find all blog posts in a blog application, and Ember data doesn't have any data for blog posts at all. So what it does is it creates an empty array and just sends that synchronously back to your controller or to your application. And what that does is that Ember can then start setting up all your routes, your views and templates while it's waiting for the data to arrive. And then asynchronously at the same time as it creates this empty array, it goes asynchronously to the server to get all your posts. And then when the posts come in, it will propagate the identity map, and then it will send that data back to the client. At which point you've bound or you're observing that data, and it will be propagated out to your view and your application will be updated. And most likely Ember has already been able to set up your routes and your templates so that it'll feel pretty snappy even though you're actually waiting for the server. And then each of these posts have a set of comments. And then when you use them on the page, it'll ask Ember data to get those comments. And again it doesn't really have them. So at this point it will just, well, when it came in here, it created these empty objects with just the ID because the ID was the only thing that I actually knew about the comments. So then it'll fetch that from the server side and uses this sort of strange PHP sort of normal structure to get all three IDs, all three comments for the first poster. So it'll return that back and then it'll arrive at your application and your application can display them. And depending on how your application is, you can either do it this way or you can sideload data here. So you could potentially, because you're asking for, you get two posts returned here and there are six comments, so potentially you could also return these comments and sideload them here. And that'll make it into one request instead of two. So depending on your load and how much data that is, so we'll do a little bit of live coding. I want to too much. And then we'll look at Phantom JS afterwards. So just to explain, we have this really badly styled photo album application. And it has four photo albums and you can select one. You get up some photographs and you can select either of these to view the photograph and there's supposed to be some information on the side here. And then you can also select the next photograph and it'll go around if you go, if you go beyond the border on either end, it'll go just wrap around and start from the beginning or from the end. So the first thing we want to do here is we just want to fill in this information that's here. Here we have the data for this photograph. I'll just find the same photograph. So here we have the data that we're going to display. It has a description and it has a name as well. So the first thing we'll do is we'll go into our template here. So it's set up so that each template has its own file and each class has its own JavaScript file and Grant will assemble this in the background automatically and want to make changes. I'll just double check that it's running. So here we'll have that information heading here. So we'll just quickly just add a table with some contents. So we're adding like so. So we're just simply adding the information here. But as you can see here, the text here is sort of not formatted the way we had it in here. We have line shifts and we have a list as well. So we're just going to convert this here which is marked down into HTML. And there's multiple ways of doing that. So you can do it in your controller or you can do it in your model. You can create a computer property that does that automatically. So the easy way is to create a computer property and just convert your markdown there. Upside being that it's easy. The downside being that for each and every photograph you have you're going to do that markdown conversion even though you won't display it on your page at all. So up here, it's hard to tell. It's called Helper. And I'll just create a helper in here. So what I'll do is to write a handlebars helper that I can use to convert markdown into HTML. So I'll just call this Markdown Helper. And then I'll register a bound helper with Ember. So it goes ember.handlebars.registerboundhelper. Is that readable at all on the back? And then we need to give this helper a name. And we're just going to call it Markdown. And that takes a function with a single parameter called a single parameter. We just call that property. So in here, we can put our code to convert the value of this property into HTML. I'll just instantiate a converter. I should also tell inside my index.html file I'm including a library called showdown which is a Markdown converter for the web, I guess. So this is near showdown.converter. Like so. And then I don't want to convert anything if this property is null or if it's undefined because then my whole application will crash. So I need to check if property. And then I'm just going to return new.handlebars.savestringconverter.make.html Property. Like so. So what this does is that we pass in a property. If that property has a value we're going to instantiate a converter. And then we're just going to convert whatever this property has as a value into HTML. And then we use this handlebars.savestring to tell Amber that, hey, I know what I'm doing. I know that this is returning raw HTML and it's going to insert it straight into the DOM. But that's okay. Usually you would need some sort of source checking. Like you only do this if you really have control of what this property is. So if you have a form that your users can fill out this is a really bad idea. So then I can go back into my photo template. And then instead of using the just printing out the description property I can simply not just type in markdown. And then when I refresh my application it now looks like it did when I typed in the data. So I have line breaks and I have created a list. So handlebars helpers are really handy for things like this or if you need to convert numbers into accounting from our sort of dollars and cents or if you have weights and you need to convert them from grams to kilos any sort of like utility function that you would otherwise put somewhere in some controller and just call randomly. This makes it handy. You don't ever call this markdown conversion on code you're not displaying because if you're not displaying it this template won't be executed. So in that sense it's quite handy. Another option would be to create a component and then do it inside the component. But I don't really think that doing this is a component. So the next thing we're going to do is just make these images so that we can see which one is the selected one. I mean we can see it down here but just to have some visual guidance up here. And I've structured it so that this view here is a component. So the component itself, the template is rather empty and contains nothing and the reason for that is that everything is in the component class. So you might ask what the point is to have this as a component if it doesn't have a template and I quite agree it could be a view instead. The handy thing about having it as a component is that it doesn't have access to your controller so that wherever you put it you can be sure that this won't mungle with your controller's context. So here we will bind a CSS property called isSelected so that whenever an image is selected it will add isSelected as a CSS class. So we added the photo thumbnail as a CSS class using classNames and we can use classNames bindings like so. What we're saying here is that we're binding isSelected to something to a function or a property inside this component. So we need to define it and it needs to be a property because it needs to be able to access it as a property. So you have to be able to say .get and isSelected. So if I return true in here and wait a little bit for Grant to do his work. There you go. They all get a black border around them. So in order to only make the selected one have a border we can look back here. This is where we call our component and here we pass in a selected photo and this is the selected photo from the controller and then we pass in the photo that is going to display. So we only need to compare those two inside the component. If this was a view I wouldn't have had to do either that or that because the view would have had access to it via the controller anyways. But it's nice to have it separated out so you don't you have to send in to your component whatever variables you want to use. So in here I'm going to bind to the photo.id as well as the selected photo .id and I'm just going to return true if those are the same. Like so. And the nice thing about having it as bindings is that I don't have to do anything else for it to display correctly. So it doesn't matter if I click the photograph or if I click the next previous button or if I refresh So that's one of the really nice things about Ember and the way it handles bindings and propagates it out to the view. You don't really have to think about how your application or how your web app should handle showing what is selected and what is not. So your views are always consistent with the data that you have in your model layer. Ok. Let's add something a little bit more exciting. So I have this album photo view and that's this photograph here. And it derives its name from the route it's in. So it's in a resource called album and a route called photo. What I want to do is when I click these buttons I want to do some animations here before I switch it out. And I do have actions here in my view. It's usually not common to have actions in your view. So this action could be split up so that the content here could be in the controller and then only the animation is in the view. Just for simplicity I put it here. So this is just the logic for finding out which photograph is the selected one and then moving back and forth when you click on the buttons. And then it has a function down at the bottom to animate out, which currently it doesn't do. It doesn't do anything but navigate to the selected photograph. So here we'll add some animations instead. So what we do here is we're going to get the element ID or the ID that this view has in the DOM. So element ID equals list.get element ID. And that's one of the primary reasons why this needs to be in the view because you need access to the element ID. And the other reason is that you don't really want to put animations in your controllers. It just doesn't belong there. And then we are going to have some callbacks so we're going to have to need a reference to our view. So bar view equals this. And I'm going to use jQuery. So this will fetch the DOM element from the DOM. Problem is that that's this whole area here. So we only want this photograph. And it has CSS class of large photo. So we'll just append that to the CSS selektor. Large photo. And then what we're going to do, we're going to spin it around, fade it out, and then spin it back in and fade it in for the picture. So we're going to toggle. And after we toggle it, we're going to fade it out. So we want to do this. See if we can scroll down. We want to do this animation here first. So we want to do the toggle animation first. And then we want to fade it out. And once that's done, this is the part where we want to swap out the image and fade it back in. So we need to put that code inside of this callback function. So if you put it just below, it's going to do that at the same time. And you're not going to get any effect at all, really. How do I? Thanks. Thank you. And then in here, I'm going to do I'm going to do a variation of this. So I'm going to toggle it back in. And then I'm going to fade it in. And at the same time that I'm doing this animation, I want to I want to transition into a new route. And the good thing is that this animation will continue while we're swapping routes. So that even though we're doing it one after another, it'll look like we changed routes before the animation finished. So then in here, we are going to do view.get controller.tran I'm going to pass in this here. And that's just a a function on my controller that has transition to route and the correct route and with the photo. There's multiple ways of doing this sort of thing. So now hopefully when I do this it'll animate out and in. That was my life coding I was going to do. I'm going to talk a little bit about search engine optimization. And this is something that's really, really important and it's also ridiculously hard. There's multiple steps involved and it's quite hard to make a general approach on how to solve this. Google has recently started indexing JavaScript applications. But it's not complete and it probably never will be as good as it being able to read your HTML right at front. And it'll probably only be best if you use Angular. So search engine optimization is really all about getting your page ranked high in the free parts of the search engines. We do say search engine optimization but we really do mean Google optimization because we don't really care about the other search engines. So there's two parts to optimizing your page. The first is what you can do with your page or with your site. That is you have control of your markup and your content and your architecture. The second part of it and it's equally important is other people's websites. People or websites are linking to yours. So often times it can be financially good if you pay and gadgets to link to your website. That might have a greater effect than anything you can do yourself depending on how many visitors you have and how many other pages link to yours. So the general rule on what you can do with your site is to have good quality content and a lot of readers. So you kind of have to have that up front and then Google will give you a good ranking unless you have a really obscure niche market. And then you need to make sure that every single page has a title and that title has to be give meaning to the page you're on. So you can't have the same title on all your pages because Google will penalize you for it. And you also need to make sure that the text you have on your page includes all the keywords that you think your user might search for. You can't include them as keywords, but they have to be embedded in your text. And the final part is you have to make your site crawlable. Typically JavaScript applications are not at all. Yeah. So Phantom.js is a headless browser. It's based on webkit. What that means is that you can render any web page. You can build up the dump tree of any web page and you can inspect it or you can take a screenshot or you can save or manipulate that HTML. Originally it was developed to help testing, but these days you see Phantom.js used for a lot of different things, including this. In my applications I have a script that I run that will crawl my page and it will help make it as crawlable by Google. So the approach is that I have a hosted version of my site and that needs to be a full version because it needs to have all the data that your production site has. You can use production as well, but then you will put load on your production server. That might be okay or it might not be, depending on your environment. Then you need to have a JavaScript application to actually crawl your websites. What I do is that I load up the index file or index HTML and then I will parse through that whole file and I will find any links that are there and then I will record those links and I will add it to a list of links to visit, links to your crawl. And then it will go through at a certain depth so I can specify 3 or 5 or 7 or whatever. So it will go to a maximum of say 4 links in depth before it will stop. What it does is that it takes the HTML for the page and it renders the JavaScript application and stores that on disk as a static HTML file. The result looks like this. So on disk it will store the structure of your website as static files all the way. And then once this is done, your backend needs to be able to read this and inject it into the page that it serves the client. So if you visit index.hjml it needs to parse this file, get everything that's in the body of that file and inject it into a no script tag on the page that it serves. And that means that for when you request an application you will serve both the markup for your JavaScript single page app and the markup for a static version of that site. And then it will include references to any third party resources CSS and all that. And if you keep it on the same level meaning that if you start all your references with a slash you don't have to do anything else. So, we just talked about that. So it looks sort of like this. This is the website as it is. So it's the title and CSS and Google Analytics. And then down here we have a no script tag. And inside that we have the Ember application. That's the static version of it. So as you can see here, it's complete. It even has class equal ember view. And it has id equals ember 463 and so forth and so on. What it doesn't have is script tags. So it's stripped away all script tags. So all of those script tags that you need for your bindings, all of those are stripped off. In addition to that, you need a sitemap file. And this file here contains just a simple reference to all of your URLs that you want Google to index. If you don't have that, Google will just skip most of your page. And since your phantom script already knows which URL it has visited, it can generate that file for you. Or you can write code to generate it. So this is what it looks like for this website here. It's just a header for the XML. And then it has a location for each and every URL that you want Google to index. And then you need to log into Google's webmaster tools and then you need to tell it where to find this file. So it needs to be loadable on your URL. So usually it'll be your URL slash sitemap.xml And if you're lucky you don't have to tell Google it'll find it itself but only if you have like a couple of million visitors a day. Otherwise it won't bother. So here's the source code for this phantom script which is a crawler. It is a work in progress. And it's very, very specific to this exact use case. It's not intended for you to just grab off and just type phantom.js crawl and it'll work. It probably won't. But at least it's a starting point for to be able to crawl a web page and generate a static version. And then there's the code for the backend here. So inside this application here this is where Amberfest's website is hosted. There's a button here I can click. So whenever I add content I can log in and just click here and then it'll generate that for me. And then I can log in to Webmaster Tools and just say, hey my site is updated. So I'll just show you an example of what this looks like. So here is an Amber application that I've used to document all the material that I use when we have kids at the library that wants to learn how to code. So you usually have some electronic projects that we work around. So this is an Amber app and it works as a single page application. And what if I turn off and this is indexed with this crawler script. So if I go in here and turn off JavaScript so I'll just say do not allow any scripts to run on this site or on this browser. And then I go back here Chrome does this. No other browser does it. You have to really reload. It's strange. But the site here is generated. It has the same. It looks exactly the same. You can browse through it. So I can click here again and I can navigate into that part of the page. Notice there's a significantly longer lag because it actually has to go make a request and get the whole page in return. I can also click here and load that chapter. It takes a lot longer. But one of the upsiders of doing it this way, rather than just hoping that Google one day will index your Amber app, is that now you have graceful degeneration of your site. So you can actually serve your site to users that doesn't have JavaScript, even though your application is really developed with JavaScript in mind. I'll just turn on JavaScript before I forget. Ja, so that was what I had. Thank you. I run it with four sort of simultaneously requests. But I've set it up so it won't thrash the website. So it usually takes a couple of minutes for this site. It has maybe 40 pages. I just set it up so it won't really thrash your page. Because when you make changes, Google is not going to index those pages for weeks and weeks. So it doesn't really have to go instant. No phantom.js will load up the page and it will render the JavaScript and just print out the DOM that's resulting off. So it's the same as loading it up in your browser, clicking view source and then saving it to disk. So it just does it automatically instead of having it be a manual process. Well, it has the same sort of structure as a real browser. So it is a webkit browser. It just doesn't have a view for you. So same as you can do document.ready in jQuery. You can ask for when it's done. Usually Ember will render the parts that it has because the views will be loaded and it will just have sections that doesn't have any data. So for the blog post it will have the content for that and then it's waiting for the comments. So there will just be a blank area and then when those comments are loaded into Ember data, it will just automatically populate it up to the view and then it will be visible on the site. OK, you mean in the phantom script? I usually just put a timeout. Because it doesn't have to be fast you can just set 4 seconds and if it takes longer than that then you should probably rework your site. There's a node app called pre-renderer which we're using with our Ember app at the moment and you basically fire off a variable at the end that says this page is now ready to be rendered so it kind of waits for Ember to finish the page and then it just fires off the pre-renderer. That's a node. Any other questions? Thank you.