 I hope you had a nice lunch and had a fine Drupalcon so far. I must admit I'm slightly, I'm both honored and slightly nervous to see so many of you here. So, what I'm here to do is to try and share some of my adventures into MBJS land and how I've had fun with combining that with my Drupal experience. So, I guess a quick introduction of myself. I build websites like pretty much everyone else here. And I'm from that Nordic country where they swear a lot. And I live in Switzerland. I like to eat. And I work for a Swiss company called Leap. And I build websites for people. So the great question everyone always asks is, why are we here? And I wouldn't go that far as to attempt to answer that. But here are a few of the things I would like to talk about today. I don't expect you to memorize that. That's just the, yeah, expectation management. So the great purpose of MBJS is to build single-page applications. You might have Chrome, of course, this term before. It's the basic idea of not having the browser reload the entire page all the time. It sounds simple, but as many things that sound simple, it actually isn't. And, well, theatrical voice here. As expectations continue to rise, it becomes clear that it is inevitable. I think in the future, what people will expect from internet sites and browser-driven applications is a lot higher. So the old way has got to go. Basically, what we've mostly always done is something like this. So every time the user clicks something, every time something happens on the page, let's just reload the page because why not? Service is cheap. And that works reasonably well when people have a fast internet connection and a pretty fast computer. But since we're seeing more of this and more of these and all sorts of other things, we need something more lightweight. Because another problem of this model, besides the time it takes to transfer all the data, it also takes a lot of time for the browser to pass the HTML and make sure everything is all right and render the CSS and all that stuff. So you can see a slight change here. So instead, the first page will always have to be loaded, of course. But any subsequent clicks and actions and stuff is handled by AJAX requests. And the server then responds with JSON structured data rather than fully rendered stuff. So MVGS is one of the, I think there are three or four really big frameworks out there for building single-page applications. There's Angular, which is currently the most popular one. And there's Backbone and there's React as well. I won't go into those. Those are always also nice. MVGS has a different philosophy. And I'll try to explain what I think makes MVGS great. So one of the things MVGS uses to describe itself is ambitious. And that means this might not be for your blog or something really simple like that. This is probably too much complexity if you only have two pages in a contact form. But if you want to build something more like an application, I think MVGS is a great tool. The main core of MVGS is that it's a full stack MVC framework in the browser. Many of you have probably used MVC frameworks on the server. But it's a bit weird to use MVC on the server. The history of MVC actually goes back to really old-school desktop applications in the 80s, I think. Where the idea is that both the model view and controller is some sort of persistent state you have while your application is running. And not just something you have temporarily on the server while we are generating HTML to throw in people's faces. So this is like a bit of a throwback. If you ever develop desktop applications, some of these ideas might be more familiar to you. Another thing MVGS gets into is something called Web Components, where you have small chunks of isolated functionality. So it could be, for example, a time picker widget or a login form or any other thing that you make into a component that we use across your site or across multiple sites. There's a web standard coming for this, but that's not really well supported or completely done or anything yet. So MVGS has provided an in-between measure, much like Angular also does. When it comes to MVGS philosophy, I think the main point is convention over configuration. So rather than saying that I have this route that wants to use this view and this controller and this other thing, everything is bound together, so if you name your things right, then everything will be automatically loaded. And I'll demonstrate this in further detail as we go on. Another thing that makes MVGS slightly special is that it has a fully class-based object model. When you work with MVGS, basically every object, everything you encounter will be a subclass of what is called ember.objects. And there's a lot of functionality built into this, so it becomes much more powerful than using plain JavaScript objects. And one of the consequences of this is that we can use two-way bindings everywhere. So if you have a, say, you loaded some data from the server, it could be a block. Well, a comment on a news story. And someone is editing that comment in a form somewhere, but you also have that comment displaying in a sidebar somewhere. And normally you'd have to be aware that this comment is also displayed here and make sure to re-render that because it was changed in the form down here. But with two-way binding, you can simply say this, I want to display an attribute of an object in my template. And whenever that object is changed, no matter where it's changed, the template will automatically update itself with new data. And that applies not only to template, but anywhere you can bind a value in ember.js. And that gives you the ability to make something called computed properties. So to demonstrate. Basically the idea here is that you have a person object, and it has a first and a last name, like most persons do, I guess. Well, at least in Europe. And then you have this full name property. And you define that as a function, and then you call the property function on that function, which turns it into a computed property. So whenever you later have your object present, you can say, I want to get the full name, and then the full name will run your function and return whatever. And since it's marked as a property in the property class, I say this property depends on first name and last name. It will be smart enough to know that once the first name changes, the value of full name changes, or the last name for that matter as well. So it's pretty intelligent that way. That of course has a subtle unfortunate consequence, and that is that we need to use these set and get functions everywhere. Because if you access an attribute on a JavaScript object directly, then that might not even be available in the namespace you're in. Or you might just get whatever value it has right now, but you won't get the updates. And last but not least, when you set a value on something, you need to use the set function so the whole MBGIS framework can react and say, hey, this value was changed. Let's let everyone know. So I'm going to try and talk you through how an MBGIS application is constructed. This probably looks pretty confusing. Because it's hard to represent. It's somewhere in between. Some of you can construe this as layers, but it's not quite layers because some of, yeah. So we're going to try and explain instead. The main entry point of everything is the routing. So my example application here is a bookmark system. So at the base level of the app, you can see the path parameter up there starts with a slash. So that will be the first thing you see when you open the app is the bookmarks resource. And that will simply be a list of bookmarks. And then there's a couple of sub pages or sub routes for that. So you can go and edit a bookmark or you can delete the bookmark and both have their own URLs. So to show how this works in practice, I have here my example application. You can see there's a bookmark here for MBGIS. And if you see the URL here, it's actually updated the URL to be bookmarks less four. So if I press cancel here, you can see it goes back to the root of the domain. So MBGIS works with the browser URL, but I'm not tricking you here. There's no page reload. So we click into a page and we can edit it here. And we can say, and when I go back to the front page, it has the new value. Similarly, I can add a new bookmark and all this happens completely automatically. And the code that is required to do this is something like maybe 40 lines of code or something like that. MBGIS is really, really powerful for this kind of thing. And I'll show you the code later. That's pretty dark. Wonderful. Yeah, that doesn't really fit on the screen. That's wonderful. The naming conventions are such that when I have a route named bookmarks, I can make a route class called bookmarks route. And the controller corresponding to that will be bookmarks controller. And the view corresponding to that will be bookmarks view. And the template corresponding to that will be bookmarks surprise. So all this works nicely together. Another important point is that all these layers are optional. So when I define a route, I don't have to define a controller. I don't have to define a view. I don't have to define all these things. I can just define a route and a view. And even though I don't have a, no, I can define a route and a template. And even though I don't have all the components in between, Ember of JS will make reasonable assumptions about what you wanted. So you don't have to define all these boilerplates whenever you want to have a URL. So you don't have to have an empty view for every URL you have if you don't find you need a view in this case. So the router itself, it handles the URL changes. So whenever you go to a new URL, the router, you can have a router class implementation for this route. And say for this route, I want to check that the user is logged in or I want to check that this is Thursday so he can see this page or some other stupid logic and you can decide to redirect him. And also this, the route itself is responsible for loading the data that's required to display the page. And because the router, the route is a part of the routing system, it has access to the whole router hierarchy. And also at all layers of the stack, you can handle user events. Because some, some elements might be relevant to the router. For example, when the user clicked the next page button, then the router needs to react and say, hey, how do I go to the next page? But some other actions might be more logical to have in the controller. For example, when the user clicks the save button on a form, then we need to update our data in the controller handle sign. So a router, the router itself looks like this. You can see the first one we have, I took a small copy of the routing I showed you before. And then we have the router class itself. And it has a whole bunch of methods. And one of them is model. And MGS calls that when it's ready to, when it's determined that we're going to load this route, then it'll call the model function on the route to say, hey, load whatever data you need to load. And in this case, I will use, go into the data store and find the bookmark that matches the bookmark ID parameter from the URL. Not rocket science, I guess, hopefully. Another very nice feature of MGS is that it has this full built-in model system. So just like you're used to if you ever use something like Doctrine or a similar object relational mapper in your whatever programming language you have, you have these objects that represent the data objects, which can know everything about the data, know how it's saved, know how it's validated. So you have this encapsulation. So wherever the model data goes, the logic that belongs to the model goes with it. And a simplified example of how a model looks is this is our bookmark model. And it has all these attributes that are strings, so the URL and the title and the description. It has a couple of dates. And it also has this display name. And you can see I've made something slightly clever here because if you, in your template, I just want to display the name of this model. And I don't really care about the logic of this model. That's the model's problem. So the model gets to decide how it wants to present itself. And in this case, I've made it so that if there's a title filled in, I will use that as the name. But if the user was too lazy to fill out a title, he just wanted to bookmark this URL and move on, then we'll just display the URL instead. Again, you can see I'm using the property syntax here, so this display name. I hope this is large enough that you can see it in the back. So in the case that the URL of the title changes, this display name attribute will change with it. The controller object itself is more concerned with what data do we have on this page and what actions can we take on that data. The controller is what you can access from your templates. So it's a bit like you get in Drupal 8, you have this context in your templates. The controller is what serves as that context in MBJS. So when the route sends some data along to the controller, so in this case our bookmark data, then that bookmark will be available through the controller in the template. And like the route itself, it can also handle user events. And in this case our bookmarks edit controller looks like this. It has a couple of actions that can be triggered. So in case the user presses the cancel button, there's a small little trick here. We can say on any model object we have, we can say roll back. Because MBJS, as it's called, keeps track of what data do I have on this model object, what part of it was loaded from the server, what is not saved yet. So when you call roll back on a model object, it'll simply just throw away all data that was changed. So instead of, because that's the problem when you're dealing with persistent state in the browser, normally when you have a JavaScript object and someone edits it, and you then need to have a cancel button, then you would have to keep track of yourself, what was the original values and replace those on the JavaScript object. It gets really, really messy, so it's really nice to have a framework that handles this. And the other thing the cancel button does is go back to the bookmarks route. And here we call it by name, not by URL. So if you remember the routing slide I showed, bookmarks is like the front page. So whenever you click cancel, we go back to the front page. And as for the save bookmark action, it's very similar, as you can see. We just call save on the model instead of roll back. So the save function then persists this. And embedded data will then transmit the save, the updates to the server, and everyone will be happy. The view is one of those things I actually use somewhat rarely. I don't have an example for it here. But basically the idea of a view is that if you want to have funky JavaScript behavior that reacts to whatever happens on the page, that is not related to the data, but more visual things, you could use a view for that. And unlike the controller and the route, the view actually has access to the DOM. So it can fiddle with the HTML on the page so if you want to manually animate something, or something crazy like that, that's what you use the views for. But the application I have doesn't actually have any views, because I didn't need that functionality. So if you don't implement a view, embedded data will simply substitute its standard view, which does some back-behind-the-scenes things, but have no obvious functionality. And also the view can also, like the other two, handle the user events. So if you have a click event that you want to have something visual happen, but not actually change anything, that would often be where in the view you would implement that. None of it is set in stone, of course, so you can do whatever you want to. But I try to keep those things mentally separated. So I need to know when I go to the router, it's because it's about where are we and where are we going. If I go to the controller, it's about data and data manipulation. And if I go to the view, it's about the visual stuff. The templates themselves. MBGAS uses a templating system called handlebars. And you'll see why it's called that in a second. It's very similar to Twig in many ways. The syntax is very similar and having filters and actions and stuff. And much like Twig, it is a logic-less templating system. So it's immensely hard, if not impossible, to make logic inside your template besides if this has a value or make a loop over this or really primitive things, but you can't really write code in there. And that's by design. Keep the templates simple. And again, displaying an example template. This is our bookmark editing form. And here you can see I'm binding values into the template. So I'm editing bookmark and then I'm calling the display name. And as you saw before on the model object, the display name is a computed property that displays either the title or the URL depending on what it has available. And then we have these URLs. And you can see MADS has these nice plug-in helpers for forms. So instead of making my own input tag, I use the input helper and I say value-binding URL. And that means this form element will be bound to the URL attribute on my controller and the controller wraps the model. So basically this field will automatically update the URL field on the model object. And vice versa. So if I change through some other means, change the model object, then this field will also be updated. So that's the two-way binding part. And I do the same for title and I have the buttons here. And this is another mpgs helper. That's the action helper. So instead of having binding the click events on some sort of class or having a JavaScript thing on your buttons or something like that, mpgs simply has this helper in the template. So whenever this button is clicked, it calls the action object and it throws that up the chain so the view gets its first and then the controller and then the route. So they all get to react to this event. And you can actually bind the event in both contexts. So you can bind the event in the view object to change something visually and you may be able to disable all the form elements while you're processing something and also bind it in the controller to fetch some more data or whatever you need to react to the user. And that's basically all there is to handle bars. And another very useful thing is that you can write your own helpers. So if you have a common logic you often need in your template like how to display something or a date format or helper or something like that. Again, very similar to Twig. So why did I decide to use Drupal for this? Because there's lots of, you know, this is like, the thing about Headless Drupal is that it takes away all the, you know, it takes away all the Twig. We don't really care about having a theme or having templates or anything in Drupal. We just care about getting data from Drupal. And lots of other frameworks do that great. But here are a few arguments you might want to consider for choosing Drupal. One thing that Drupal actually, you know, one of the unsung heroes of Drupal, I guess, is how Drupal handles users and permissions and password recovery and all that nonsense. Because that's actually a lot of work to implement on your own. And Drupal does it really well. And say you want an easy administration UI, you just want to go, you know, want to have somewhere for the admins to log in and see whatever data is in there. You could do that with Drupal in like half an hour. And I guess it gets even easier with Drupal 8. And, yeah, I haven't actually played that much with what's coming in Drupal 8 yet. But it looks very promising. If you want to try it out on your Drupal site, there's a module called REST WS, which pretty much is the same, or it's the base of the services, or not services, but the REST API stuff that is in Drupal 8. Another aspect of modern web applications is that you often need a CMS anyways. Because you have your nice application, but you also have support pages and a FAC and a contact form and all these other things, you know, about the company and whatever. And, you know, so if you need a CMS anyways, Drupal does a pretty good job there too. And another really great thing about Drupal is like, hey, I need PayPal integration. Oh, that's a module for that. I need, I need, you know, if you've been to the Drupal org site properly and seen how many modules are available. And I think if you're considering making a web app, you know, try to keep it focused on what you can do that's different than the others, because if you're selling something online, you know, everyone needs a checkout flow and building checkout flows might be fun, depending on your inclination. But it's not really where people are not going to come to your site to see your awesome checkout flow. Of course, it has to work, but it's not where you're going to attract new customers. So I see Drupal as one way of getting all the boring and all the common stuff that every website, every web service does out of the way. So you can focus on what it actually is that makes your website special. And another good point, of course, if you know Drupal already, it's always easier than having to learn some new funky stuff. So how to handle the integration with Drupal? I haven't been able to come up with the final answer to this, because originally my plan was to do it on Drupal 8, because I hope that Drupal 8 would be a lot farther along when we had this. But that's proven to be slightly futile. So I have a halfway working implementation on Drupal 7, but basically it's all res-jason, so it's not rocket science, but it does take some effort into getting to work, because the EMBAT data system is really, really powerful, but it also demands a lot from the back-ends. So my idea is to try and maybe build a module for Drupal or something similar during the sprints tomorrow, and maybe later, to try and have some sort of generic tool you can use to integrate your MBTS application. SEO is another great question when it comes to handling MBTS applications. Because SEO is tricky, because when your entire application is rendered in JavaScript, currently none of the search engines will actually execute your JavaScript, so if you do nothing, you will just serve a blank page to Google, and that's probably not what you want, at least if you want your website to be found by anyone. So if you want to have a secret tool hidden from Google and everyone, it's a great way to go. And of course, this is of no concern if what you're doing is behind the login anyways, and you don't want it indexed by Google, then you can just ignore that. But there are quite a few ways to do this. One of them, which I find really awesome, is a service called PreRender, which basically renders your entire page, loads all the HTML and JavaScript, and runs it in a virtual browser, and then saves it to disk. And then when Google comes and asks for a page, your server catches it and says, hmm, that's Google. We better send them this pre-rendered page instead of the dynamic version we serve to everyone else. And they do this as a service, but it's also open source, so you can run it yourself, depending on your inclinations. Another small important point about this is course. It's short for cross-origin request service, or something like that. And it's basically, you know, normally in a browser, if I am on Drupal.org, and I try to load a web page, you know, something with Ajax from Google.com, that will not be allowed because the browser says, hey, your JavaScript is not from that domain, you cannot call it another domain. But what course is about is simply allowing, setting a policy for allowing that. So this is the course module for Drupal, and you have this long, gnaly line. And basically what I'm saying here is, if the URL starts with bookmarks to bookmark, you can see there's a star here, then mirror, which means send back, well, that's probably too complicated for now. But yeah, it's what you want if you want everyone to be able to access this domain from outside. You could also specify a specific hostname. If you have a CDN serving up your JavaScript, you could specify that hostname here and say this CDN is allowed to make request to this server, even though... So the browser, when loading JavaScript from this CDN, is allowed to make Ajax requests to this server. And then the get post put leads is the HTTP verbs we allow. And finally, content type is one of the HTTP headers. So you can make a list of HTTP headers you allow. So if you have some sort of, if you use the services module in Drupal 7, you would need the XCSRF token header, which that needs to send. So basically this needs to define everything that we allow the browser to do. And to show a little bit about how that works in practice, let me just switch to the other tab here. So, hold a second. It has to stop this. So I mean, it's going to switch branches on my little example app here to actually make it communicate more with Drupal and just restarting the EmberJS server. So let me just switch this to... Yeah, that's better. So now you can actually see the URL. You can see this application runs on localhost port 4200. But our Drupal side is actually over here. So normally our localhosts application will not be able to communicate with Drupal. And here you can actually see this is the quick administration interface I was talking about earlier. This I made, you know, in half an hour with Drupal entity APIs and views. And that's really stupid. You know, I can go and edit something here. You know, that's really basic standard Drupal UI. Not very exciting. But if I go over to my application, turn off your alarm, someone. Oh, that's not very useful. Oh, well. How do I get back? Yes, always wonderful. So where's my other Google Chrome window? Great. No swearing on stage? Great. So let's try and reload the page and then see in our network inspector over here what happens. And you can see this is all fetched from localhost. This is not remarkable. But this one is fetched from the other domain where my Drupal site is running. And this is the data that's not interesting on its own. But course basically looks like this. So the browser sends this header saying, hey, will you allow localhost.htp42 to access this resource? And the server responds with... Where is it? I can't actually see it. Well, the server responds correctly. Anyways, it wouldn't work without course enabled. Take my word for it. So a more complex example is if I want to add a new bookmark. You can see in this case there's two requests. One of them is an options request. Because this is a post, the browser will first need to verify with the other server, can I even send this post? Because with a post request you can actually modify data. So you don't really want that to go through. So the browser says, can I do this? Yeah, right, right, sorry. The server says, yes, you can send this header and you can do these methods and you can do it from this domain. And that's basically what mirror means, is that the server sends back the same hostname as the one you requested from. So the browser asks this, can I do this? And the server says yes. And that's basically the course handshake. And then the post itself goes through after that. So basically this is enforced by the browser. So if the browser doesn't get this response back from the server, no, this response, then it'll simply refuse to carry out the post request. But because the server responds in the correct fashion, then it'll go do this. And if I now go to my Drupal page, you can see the new bookmark I added is here. And if I go back here as well, it's also here. So, hey, it works. And yes, I'm not surprised. So if I look at the markup of the page, this looks really complicated because Mbadeus has these metamorphs, as it's called, all over the place. And that's a feature that's going away soon in Ember, but it's still so now because it needs to keep track of where is my dynamic placeholders. So every time you have a view or something inside Ember, it uses these metamorphs to find it. So in Chrome or other browsers, there's this nice Ember inspector extension. So you can see what's going on with your Mbadeus application. And you can see here is the view tree. So we have, out of most, we have the application view. That is the total thing. Application is like the root object in an Ember JS application. And inside that, we have the bookmarks view. And inside that, we have the bookmark index view, which is actually what contains all the markup. And similarly, I can see all the routes here. There's a bunch of bookmark routes. And interestingly, there's a few. You can see there's a few that I haven't defined in my router. There's loading and error and a few other things, if I could. And that's basically routes that are always there. And so you can add something to your loading routes. So whenever it's loading data, you could displace by flapping its wings or whatever stupid thing you could imagine. And similarly for the error page, you probably, if you want to ever have a production Mbadeus application, you need to put something in there so people can see, hey, what's going on? Yeah. Ember CLI is... I'm going to try and tempt the demo gods here slightly. Ember CLI is a tool used to mess with your application or work with it. So if I'm saying I want to generate a route, and I'll call it a low, it does what I asked it to. So you can see here it'll generate a route for you. The route class itself starts out empty. You can also delete this file if you're not going to expand it. And it'll try to add the template here. So I'll just say h1. Hello, Drupal. Another important point is that if you look in your router.js file, you can see, because I used the Ember Generate, you can see there's a little plus sign out here at the side. Can you see it on your screen? No, you can. Well, my editor tells me that this line was just added. So when I did the Ember Generate, it added a new route to my application. So when I now go to slash hello, nothing happens because I tempted the demo gods. I wonder if I did something. Well, in essence, that should work. So I'm not going to bore you with trying to figure out why not. But you're quite right, sir. Thank you. I should, of course, have started with a small h. And basically, Ember CLI is really great for avoiding to have to write all this nonsense. As you might have noticed, if I go back and open the route again. Hello. You can see this is actually ES6 syntax. So I'm saying here export default Ember route extend. And this is the new module system that's coming in the next version of JavaScript. This does not work in current browsers. It will eventually. But the magic of Ember CLI is that when I do this in my application, it will transform it into one huge JavaScript file with everything compiled correctly. But you can actually keep, so you have a nice clean file structure. So you can see this is my Ember application. So I have the models in one file and the controllers in another file. So here's my bookmarks edit controller. And it uses the same pattern here, so export default. So that's a really neat system. So that's basically what I'm using over here. That's probably too tiny to see. But you can simply run Ember server on your command line. And then it'll start this file server that serves up your Ember JS application and reloads automatically whenever you change a file. Which is why I didn't have to restart when I added the hello Drupal. So that's if you ever want to use Ember JS, do check out Ember CLI. Ember JS components is a huge chapter of itself. I really would like to show it to you today, but I fear we lack the time. But check that out if you ever mess with Ember JS. So, questions. I hope that makes sense. So if anyone wants to know more, please step up to the mic over there. So everyone can hear you. It's slightly crowded in here. Sorry. Well, that's fine, okay. I was wondering about Drupal as your aliases and can you wrap that to Ember routes or how would you do that? At least in my case, in this example, the Ember JS application runs in a completely different domain name. So Drupal does not interact at all directly with the Ember JS application. So any URL aliases you define in Drupal doesn't really have anything. I have tried experimenting slightly with embedding Ember JS inside Drupal. But the problem is that Drupal wants to output all this junk and JavaScript and old versions of jQuery. And that's a bit of a headache and not really what you want if you have a single-page application. So at least what I imagine is that you would have your www.myapp.com which would be a static file server. Another feature of Ember CLI is that it can compile it all into static files. And you can just stuff that up on some random Apache server. So that would be what you had on your main domain. And then you would have admin.myapp.com which is the actual Drupal site where you can log in and mess with stuff. Does that answer your question somewhat? A little bit. Is it possible to have dynamic routes or something? Have a web service that will configure your routes for your application? Well, I'm not quite sure what you mean with dynamic routes. But the Ember JS router is fairly flexible and you can use wildcards. And you can also say if you can have a wildcard and then you can handle it all in your routing class itself if you want to do something really magic. So I think it can do mostly everything. Okay, thanks. Hi, you touched on using pre-render for SEO purposes. Would an approach like that be suitable for providing an accessible fallback for an Ember app as well? Yes. Okay. Well, I think Ember JS can be accessible on its own because most screen readers, as far as I'm aware, still execute JavaScript. So your HTML will still be on the page and you can use Viaria helpers to make the screen reader aware that you should read this and not this. Sure. When I say accessible to be clearer, I was thinking about four users who didn't have JavaScript at all. Oh, yeah. In Maya, you know, there's a nice domain at enabledjavascript.com. You could link people too. Because the application part, the clicking and the interacting and all that stuff, that wouldn't work in the pre-rendered version. The pre-rendered version would just be a static site. Okay. So people wouldn't really be able to enjoy your application. Fine. All right. Thank you. All right. Anyone else? All right. I remember there's a spent tomorrow. So if you want to... Hey. If you want to help me build some of this or work on something completely different, then, yeah, it's the time to show up. And if you enjoyed this presentation, please leave me a few kind words on the feedback form. Thank you.