What do you want to learn? Leverged jhuang@tampa.cgsinc.com Skip to main content Pluralsight uses cookies.Learn more about your privacy Application Building Patterns with Backbone.js by Rob Conery In this production we build a single page application with BackboneJS that breaks the bonds of the "silly demo." No more To-do lists - we're building an Open Source MongoDB document explorer, a perfect use case for a Single Page App powered by... Start CourseBookmarkAdd to Channel Table of contents Description Transcript Exercise files Discussion Recommended What is BackboneJS? Who Cares? What is BackboneJS and Why Use It? Welcome to Playing With Backbone.js. In this production, we're going to go deep into building a single-page application with Backbone.js, creating a data explorer and administrative tool that sits on top of MongoDB. We'll be using Node.js as our web server as well, completing the hipster hat trick of using JavaScript on all three tiers of our application in the database with MongoDB, on the server with Node, and on the browser with Backbone.js. We're also going to do something a bit different for this production. We'll be using Node and Mongo on Windows 8 with WebMatrix. Now, I'd heard a lot about Node on Windows with WebMatrix and so I figured it would be interesting to take a look. So, let's get to this straightaway. Why do people use Backbone.js and what does it do? Let's consider our use case. We need to create a data administration tool that sits on top of MongoDB, allowing you to admin databases, collections, and documents. In terms of functionality, it's nothing terribly special, but consider that MongoDB is a document database with a somewhat loose structure. How do you display records in a stored document? Our answer was to plug in the Ace code editor that powers sites like Cloud9 and JSFiddle. It's fast, it's intuitive, and it also provides you with some interesting code checks if you use their JSON plugin, which we are doing for this episode. This app was a lot of fun to create. But, fun is not a particularly compelling argument for selecting a technical approach. So, let's get to that straightaway. First question is obvious: Why use JavaScript on the browser for such a complex process? In the years past, this wasn't even considered for a second, but with new organizational techniques, frameworks like Backbone.js that allow you to structure your code elegantly, the creation of a single-page app has become quite compelling. Consider the amount of code necessary to manage the application that you just saw. If you use an MVC framework like Rails or ASP.net MVC, you're looking at five or more controllers, 30-40 views, routing logic, model code, and more. That's a whole lot of code. A single-page application allows us to focus our efforts on user experience, putting presentation code down in the browser where it should be, leaving application code in business logic back on the server. Now, if you haven't created a single-page application before, this might sound like pure insanity. Using JavaScript to structure a complex application might sound crazy, but stay with me for just a bit longer and you'll see how easy it's become with Backbone.js. So, what is Backbone? To understand this, consider your typical MVC-style web application, say something like Ruby on Rails or ASP.net MVC. You have some data that gets dumped through your application that is then rendered out into HTML for the user to interact with. The MVC structure of Rails and ASP.net help you, the programmer, but what does it do for your user? That's where Backbone comes in. These frameworks help you as a developer put things in their proper place so that you can maintain your app through the years and scale its complexity without creating a complete mess. Backbone does the same thing, but on the client end. It allows you to create a user experience using JavaScript and Ajax that, same as Rails on the server, allows you to scale complex user interactions. It does this by adopting a bit of an MVC pattern, sort of. Backbone is a collection of tools that work together to fetch data, impose client validations, render views, and manage and page URLs. Each one of these elements has a job to do. If you let them work together as intended, there's a lot you can do in a very short amount of time. But, I'm not going to lie. At first, the concepts take some time to sink in and it can be rather frustrating if you don't know how to do a particular thing. Many developers think Backbone is just plain overkill for, well, just about everything. We'll come back to this discussion after we've finished building our application. For now, just know that we'll be spending time explaining patterns and concepts that will, hopefully, push you into an "A-ha" moment quickly. So, let's take a look at a few more advantages of flexing the power of the browser in terms of a coding surface. With the onset of HTML5, the browser and the DOM have become a lot smarter. Flexing the power of the DOM can make a huge difference when it comes to the usability of your application. Given that we have such powerful browsers at our disposal, it only makes sense to separate what the server needs to do from what the client needs to do. Why do we need to tax our servers with a mundane task of looping over strings to build an HTML page? And, the answer is we don't need to. Many sites are choosing to flex new browser abilities by creating more complete APIs in the back-end and consuming that data on the front-end using a framework like Backbone. This type of approach isn't ideal for simple brochure sites, but if you have an online application, it could make a lot of sense to expose the functionality in one place, like your API, so it can be used by all kinds of clients like mobile or other desktop clients or web clients like Backbone. Many people want to know which client-side framework is the best. And, choices tend to revolve around Backbone, Knockout, Ember.js, and Angular among others. Each of these frameworks have their advantages and each has a particular conceptual weight that you'll need to deal with. What you see here is my completely non-scientific, subjective illustration of what I call the conceptual weight of the larger JavaScript frameworks that I've used. There are quite a few others out there, but I haven't used them, so I can't really speak to them and I've just left them off. Basically, Knockout.js is a very straightforward tool to use. It makes things flash, appear or disappear and is very easy to get up and running. Backbone.js is slightly harder. Knockout has the notion of a view model, whereas Backbone has a model, collection, router, and view. Four times the amount of concepts. Then, we come to Angular, which is basically Knockout and Backbone combined, elevating the DOM into a very smart code surface and it does rendering just like Knockout does right in the DOM itself. The intricacies of this framework are interesting, to say the least, and they're also very powerful. Finally, we come to Ember.js. I've worked with Ember three times and each time I am amazed at the engineering prowess of Yehuda Katz, the maintainer of Ember, and the other collaborators. Ember is basically an opinionated, highly-engineered version of Backbone with a built-in templating engine, some proxy classes, and bindings of all sorts. It takes time to understand all the concepts that go into Ember, but if you have a very complex app that needs some engineering, Ember might be a very good choice. Installation and Setup Okay, now that we know what Backbone is, why we might use it, and how it stacks against other frameworks, let's install it and get started. So, installation is pretty simple. Head over to Backbonejs.org, grab the two JavaScript files you're going to need, underscore.js and backbone.js. Underscore is a neat utility library that brings some Ruby love to the JavaScript language and helps you work with arrays and objects in a nice, clean way and has a simple templating engine that we will be using. Backbone uses Underscore, so be sure you grab both libraries. Now, let's get set up. I'm hoping you'll want to play along with me here, so let's get you started with the tools that you need. I'll be working in Windows for this. If you're on a Mac or a Linux, I'll add some details for you as we go along. First, head over to nodejs.org. Here, you'll need to download the installer for Node. This goes for both Mac and Windows. It works great on both counts, but I've had some weirdness where I've needed to install Node twice on Windows in order for Node's executable to get picked up in my path. If you see this problem, just run through the installer again. That's what I found fixes it. You'll know if everything works by hitting the Windows key and typing CMD and then Enter and then the words Node into the command line. You should see a JavaScript console pop up if everything worked or an error if it didn't. If you do see the console and you're inside of it, just hit Control+C to exit. Next up, let's go grab Twitter Bootstrap. You don't need to do this, but I find that a little styling really helps me see the functionality come out of what I'm trying to build. Now, you can download the files right here and then open up the zip. We'll be putting these files in our public directory of our site following the structure that you see here. And, don't do this just yet, however. We're going to let something else build the structure of our site for us. For now, just review each of these files to be sure that you have them. If you want to use a CDN for jQuery, go for it. Or, you can grab those files out of our code download. Next up, MongoDB. Download the files, whichever one works for your system. Once downloaded, unzip and open a new window. I typically put my MongoDB installation in the root of C, renaming the directory MongoDB. Next, you'll need to create a data directory called "Data". Inside of that directory, create another one called "DB". This is where your data will go. Now, let's make sure it works. Open a console. This is Console 2, by the way. And, head over to the C prompt. Type in mongodb\bin\mongod. This is accessing the Mongo daemon inside the bin folder. It's just an executable. You should see everything up and running. If it crashes here, it's for one of two reasons: It can't find the data directory or you grabbed the wrong install. Maybe you grabbed the 64-bit instead of the 32-bit, for instance, if you're running a 32-bit machine. Leave this running inside the command console here. We will need it to access later. Okay, we have Node, we have Mongo, and we have some slick CSS. Let's get our site up. Normally, if you're going to work with Node, you would want to use the Node package manager, NPM, to install a web framework that you could work with, something like Express. This is the command that you would use for that. The -g flag here means it's a global install. Sort of like sticking an assembly in your GAC if you're a .net person. After that's done, you would use the Express module to create a site with the Express command. Here, I could create the project "Congo". But, you don't need to do any of this, however. Let's use WebMatrix2 for this. You can create a brand new Node site by opening up templates and selecting Node and then Express. It's not terribly clear what Express means here, but it's simply an empty Express framework site. What is Express? Well, the short answer is that it's a very lightweight server framework built for Node.js. If you know what Sinatra is for Ruby, you'll know what Express is for Node. There are no conventions here. It has a very simple routing system and abstracts away core HTTP stuff and that's about it. So, let's run this and see what it looks like. And, there it is. Everything's working and we are on Windows. WebMatrix works happily with Node.js. There's syntax highlighting for the Jade view engine, which I love, and modules for working with Node directly on top of IIS, which is something I'll talk about later in another episode. Getting Started I'm not going to focus on Node server bits too much. I'll give a quick explanation of the code we're going to use and I highly recommend you take this start directory that we have offered in our code downloads and drop the files just directly into WebMatrix from there. Or better yet, just open the Start folder and the code download as a site in WebMatrix. Let's take a quick walk through the code so you're at least familiar with what we're doing on the server. If you don't understand what you're seeing here, that's okay. This is simply a website that's exposing data from MongoDB via JSON. It's not critical to completing our mission of creating a Backbone app. As you can see here, we have our script file style sheets and images sitting happily under the public folder. If you're wondering what those green checkmarks are, that's a Git plugin I've installed with WebMatrix. It's really handy. Next, let's take a look at the lib directory, specifically Congo.js. In here, I've added some routes to our application that Backbone will use later on. Routes are defined much like Sinatra where app is our application, get or post is a method invoked based on the HTTP verb, and the route matcher is the string value that's passed into that method. Parameters are preceded with colons and then a callback handles the response. The rest of what you see is simply accessing Mongo using Mongoskin and Node.js driver for working with MongoDB. I'm not going to spend any time on this, but I do encourage you to check out the project on GitHub or explore the code here in our application. So, let's run this and take a look at the initial app, making sure we don't have any 404 load errors and that our CSS is correctly applied. And, there we are. We're up and running on Node. Now, I have to say I'm happily surprised at how well Node works with WebMatrix and the IIS Node module. There are some great advantages, mainly that IIS Node handles the Node process seamlessly for you. Now developing directly against Node.exe, you have to restart the process every time you make a change to your application. You can install washer programs that reload things for you, like Supervisor, which is a nice Node module. However, many of them don't work on Windows due to using Unix-based file monitors. Anyway, we're all set up and rocking WebMatrix, so now let's write some code. A Simple View Getting Started and A Simple View Welcome back to Playing with Backbone.js where we build out a MongoDB using Backbone, Node.js, and Mongo, all running on Windows. Last time, we tried to answer some basic questions straightaway. Particularly, why you might want to create a single-page application and why Backbone might be a good choice. We then took a look at what Backbone is and what it does. And, finally, we set up our application. We didn't write any code, however, so let's fix that now. Today, we'll write our first bit of Backbone code, creating a simple view to handle our breadcrumb navigation. We'll take a look at what a view is, what it does, and some of its core pieces. And next, we'll wire up some events for the view. And, finally, we'll clean things up a bit so we don't make a complete mess. To get started, I'm going to create a directory called Congo inside the public JavaScript's directory. I'll also create a file and call it index.js. Now, I could call it app.js, but index is more in line with the way modules are handled with JavaScript. Next, I'll create a global object called Congo. The idea here is that all the code I write in the future will be attached to this object, in a sense, namespacing it, which is a really good habit to be in to avoid JavaScript's notorious global variable naming issues. I also want to have an init function here so that I can explicitly call it when I want my application to start up. Some people name this thing "Start". Personally, I like "Init". Call it what you like. So, let's do the simplest thing first. This is a mockup of what our app should look like. If you were to look at this as a desktop programmer, you might identify three different regions that need to be bound and rendered. Those could be breadcrumb or a navigation region, the list region or details region, and then an options region. In Backbone, each of these regions are considered views and each of these views have views inside of them. Nested views, if you will. So, what is a view? Well, a view in Backbone is responsible for rendering content to the DOM, wiring up events on that content, and also receiving user input and then passing it on to the rest of your application. Typical view in any framework. The best way to understand how it works with Backbone, however, is to see it in action, so let's write some code. I'll start by creating a view for the breadcrumb navigator and I'll create a container for it with the ID of "Breadcrumbs". Now, let's take a quick second. This is the Jade view engine markup. At first it looks weird if you're not used to it, but give it 10 seconds and it'll start to make sense. I'll be working with this a lot today, so let's take a very, very quick tangent into the rules of the markup engine. First, there are no angle brackets in Jade, as you can see. It uses white space and indenting to figure out parent/child DOM element relationships. In addition, if you don't specify what tag you want, Jade will assume you want a div tag, like in the HTML that you see here. In fact, this HTML is exactly what the Jade code translates into. Note how much more readable the Jade is once your eyes get used to it. Also notice that the notation really isn't anything cryptic. It's the same convention that you use with CSS: dots signify class names, tone symbols signify IDs. Now, I know my HTML friends out there are going to say, "Hey, man, I can read that HTML just fine", and so can I. But, the reason that I like to use it when working with JavaScript, I like the look of Jade, especially when you're working with JavaScript template engines. Now, HTML tags are recognized as being the first items on a line in Jade. If one tag is indented under another like our unordered list here, then that tag will be wrapped by the outer tag, as you can see. Finally, JavaScript works the same way. Just use a script tag and indent the JavaScript under it. It's a very simple markup to understand. And, after a while your eyes definitely get used to it and what you see here is pretty much the extent of how we're going to be using Jade. Okay, back to the code. I need to add a reference to our Congo code, so I'll do that right below our markup with a script tag in Jade. Finally, let's add some Backbone code. There are a few things to notice about this code, so let's take a deeper look. First, the declaration of the view is extending Backbone.view. This is a type of inheritance of JavaScript. There are no classes, but you can think of them as classes. What you get back is a prototype of a function. We are extending that prototype using the underscore library with the extend method and we're adding in our own functionality. A big stumbling block for Backbone users the first time they use Backbone is understanding the difference between declaring a view's prototype, as we're doing here, and using it later on as an instance. We'll do this in just a second. The object literal we're passing in has a function on it declared render. You can call it whatever you like, but by convention, your view should have a function called "render" that puts some HTML on the screen or in the DOM. So, we need to render elements to the DOM. That's what a view does, but how? In short, every view has a DOM element that it renders to. You can specify that DOM element manually or you can let Backbone do it for you. This is the one most confusing thing about views. I'm going to come back to it many, many times, but whenever you see this.el or just the word "el" inside of a view, just know that you're referring to the view's DOM element. We have wrapped our view's DOM element in a jQuery tag and are simply injecting some HTML. We're going to see this more coming up. So, let's take a look at how this all rolls together. I have my console open here. So, the first thing I want to do is to explore the Congo object to make sure everything is planted as I expect. We can see our breadcrumb view and that is great. Let's set an instance of that view to a variable so that we can use it. There we go. Now, let's try and render it. And, nothing. But, why is that? Well, because we haven't set the view's DOM element. In other words, when we render the view, it doesn't know where to render it. It doesn't know what to do. You can set the DOM element for the view by sending in an object literal with the property "el". Notice the pattern once again where we send in an object literal for setting properties and base methods. Again, this is the Backbone pattern that you're going to see a lot of. Here, I'll set the DOM element to breadcrumbs as that is the DOM element that is on my page. Now, let's render it and there we have it. It seems like a lot of machinery to just render some stuff to the DOM, doesn't it? Well, let's keep going. We're going to change the code a bit as we'll need the database's text that we put in and we need it to be a link. And, we'll need some more styling as well. Okay, I've updated the styling and at the bottom of the page there, I have output the code that I was using in the console and basically just put it at the bottom of the page so the view will automatically render. Now, you might be wondering if you need to embed HTML in your view the way that I am here. And, the answer is absolutely not. In fact, you probably shouldn't be doing it this way. I'll show you a better way later on. However, don't be thinking I'm showing you that dumb of a demo. If this does the job, then why not just leave it? Indeed, this is the same code that's in our final example. That is why I have it this way. And, it works just fine. As for other things, we will improve upon all of this greatly. For now, this is a functioning view. And, there it is. Wiring up a View Event Why all this ceremony for displaying HTML? Well, we have a link that we've embedded. What happens when you click it? Right now, nothing. And, since this is a single-page application, you don't want that link to be working because you don't want to be navigating the browser away and refreshing the page, thus restarting your application. So, what do you do? Well, you wire up an event to handle that. And, let's wire it up and see how that works. To set up DOM events for a view, you wire them up by sending them in with your object literal when you declare your Backbone view. Here, you specify the selector syntax for the event, then the name of the function you want to invoke. This needs to be a string, by the way. Don't pass a function reference here for the event or Backbone won't understand what you want. Next, you have to declare the function to be called. Here, I'm just going to pop an alert box. Let's see how this works. Refreshing the browser, clicking the link, and boom. Now, you may be wondering, "Who cares?" Well, you do. Wiring your events to dynamic DOM elements can be tricky, especially when you have dynamic elements all over your page and they're working with other dynamic elements and underlying data. Now, it's not impossible to do this to be sure. All you need is a bit of organization. And, that's precisely what Backbone gives you. A little bit of organization. It's not a big library at all. Just over 600 lines of code. Organizing and Summary We've covered some ground so far showing how to render a view to a page. We've talked a bit about the view's DOM element, el, which we will talk about more later on. And, we've wired up some events. We've also started to create a bit of a mess, so let's take a second and organize things. People have different approaches to organizing their Backbone files. Personally, I like to organize them by purpose. We're working on navigation. So, let's create a file in the Congo directory and I'm going to call mine nav.js. In here, I'll put the code for the view. Basically a wholesale copy and paste. Next, I'll put the wire up in the init function inside Congo.init. So, in here I will instantiate my view and then I will render it immediately. Finally, I'm going to go back here and add a reference to my new script and then wire everything to startup when the DOM loads using the JQuery's document ready function. Let's see if it works. Refreshing our browser. And, everything's working just fine. Checking our console to make sure we don't have any errors and we do not. We got our feet wet a little bit today by rendering out the very first view. It was incredibly simple. But, that's okay. We're going to get more complicated later on. We introduced some concepts here that if you've never seen Backbone, it might seem a little bit weird, so we needed to take it slowly. We also wired a simple event to that view to pop an alert box. And, we've kept things organized. In the next part, we'll do it all over again, but we're going to transition to nested views backed by some data that render in response to the events on that data. That's the end of this episode. I'll see you again next time. The List View Creating a List View Last time we did a really simple thing, which is building on our breadcrumb view here. We need to make views that are a lot more complex. So, spinning through our application, you can see how this thing changes so much in all the interactivity we need. Specifically, we need views that have lists of things like our database view here. And, that is what I'm going to focus on today. So, let's take a look at what we already have. And, I'll run this site and there is our breadcrumb view. And, clicking on it, we have wired the click event to pop up a message box that says, "Hello". Next, let's create a database list view. To do that, I'm going to add a file here called "Database". Again, I like to name my files based on purpose and what they do, not like views and collections and so on. I find that it's easier to find things and that's just my preference. So, let's call this view "Database View" and it's going to show an individual row that will represent a database. And, I will stub out a render function. And, this is a good habit to get into. Whenever you create a view, next thing, just create a render function. So, that's going to be my item view. Now I need a list view. To keep things simple, I'll create another one and I'll call it "Database List View" and, once again, I'll just extend Backbone.view and I will stub out a render function. So, last time we discussed how each view has a DOM element that it will render to. You can be explicit about this and pass it in, as we did last time, or you can let Backbone handle it for you. That's what I'm going to do this time. I'm going to specify what type of tag I want Backbone to use by using Tag Name in the initializer here. And, I want my list view to use the UL, or unordered list tag, and then I want my item view to use the LI tag. Now, what we can do is when we operate on this.el, we know we're going to be using a list item. So, I can simply tell it to pop some HTML, it'll just be "DB Name" for now, into the element. That element, once again, is going to be a list item. Finally, when I'm finished, I will return this. Once again, that is always a good habit to be in whenever you're working with Backbone views. Always end by returning this. Primarily because you don't know if the view you're writing is going to be top-level, bottom-level, mid-level, whatever. We'll talk more about that later on. Okay, so in the render function here for my database list view, I'm going to keep it simple as we don't have any hard data to work with just yet. So, I'll do a for loop and I'll loop it five times. And, what I'll do inside my loop is simply create an instance of my database view. There we go. And then, what I need to do is I need to now append a return of that item view's render function. And, I'm going to take its el and append it onto the element of my list view, the unordered list tag. Let's take a second and dive into this code a bit more. I know this is probably confusing for you if you've never used Backbone. It was really confusing for me when I was first learning it. What the heck is this "el" thing? Recall from last time that this.el is the DOM element that is going to be rendered to by the view. It contains the HTML and the events. In this case, we're taking the item view, we're rendering it, we're grabbing its element, and then we're appending it to the element of the list view. If this looks confusing, stay with me. It'll become clearer in just a moment. All right. The final thing that we need to do in our render function is, of course, return this. We're going to return our list view back to whomever is calling it. For this demo, however, I'm going to do something a little bit simpler just to drive the point home. I'm going to render directly our element here. I'm going to render it directly to an element called database list that I'll select with jQuery. Next up, I just need to get the HTML from our view element, this.el, and I'm going to take that and I'm going drop it into our database list. But, there is a problem here. Can you tell what that problem might be? Well, we'll find out soon enough. For now, let's see if this will actually render to the screen. Before we do that, I have to go into our views, to go into index.jade, and then I need to make sure that our database list exists. So, let's add a new row. By the way, I want to mention, if Jade looks weird to you, again, give it some time. It'll start to make sense. I've had a few comments already that Jade is too weird, why don't you just use HTML? Now, I could, but there's a good reason for it and you'll see that reason in just a little bit. So, there's our database list. My next step is I've got to include our brand new script file, database.js, and we should be good to go. Let's refresh. And, I'm going to pull up the console. And, what I need to do in here is just make sure that everything is referenced, and it is. Good. I'm going to set a variable to our brand new congo.databaselistview, just instantiating our outer list view. Then, I'm going to call the render function. And, whoops. I have an error. Usually when you see something like this and you know it's defined, then you probably have a namespacing problem and that is my first guess. So, if I take a look here, it is defined. I can see database view, which usually means in my code I reference it without using the namespace. And, I did. I said just database view. But, you've got to have the namespace in there. All right. Let's do that all one more time. I will refresh and I will up arrow and reset my variable. Now, we just need to call render. And, fingers crossed. Hey, there we go. We have a list and I'll put "List". That's great. Have you figured out what that problem might be that I mentioned before? All right, well let's see if we can do a bit more work here to make that problem come out. You might also be thinking why do I need an item view and a list view? The simple answer is events. What if we wanted to have those things be links? Let's do what we did before. We'll put a click for every anchor element in there and I'll say "Hello" and then, once again, I'll do the exciting thing of punching out a message box to the screen. Assigning events to items in a list view is one of the most powerful features of Backbone. We have access to all kinds of things that really makes working with lists very, very simple. Okay, so I need to now make this an anchor tag. And, I'll just do that really quickly by popping in some HTML right here inside of my render function. And, if this looks gross to you, hold tight. We're going to talk about templating in just a bit. So, let's refresh and I'll just hit up arrow once, twice, render it out, boom, and nothing. Wait a minute. I'm clicking, but nothing's happening. Why would that be? Well, this is the problem that I mentioned before and it all has to do with grabbing HTML from our element. We don't want to do that. The events are assigned to the DOM element, but our list is not working with the DOM element, it's working with just straight HTML text. So, we need to just append the element as you see here. Then, we get all the events, everything else, jQuery will know what to do. Refresh again, up arrow once, up arrow twice, render it out to the screen, boom. That's how we solve that problem. But, is calling append in a loop as we're doing, is that a good idea? Well, some people think that that is not a good idea. Whenever you do an operation like we're doing here in a loop and you don't know how big that loop is going to be, it's probably a good idea to think about the memory footprint in your browser. One habit that I'm always in is to create an array as I'm doing here. I'm going to call it "els". And then, instead of using append inside the loop, I'm just going to push all of those elements into the array. There we go. And, then what I can do is I can simply pass the array in because, again, jQuery's smart enough it'll see all those DOM elements in there, it'll know what to do. It could be an array, it could be a single element. It doesn't really matter. Okay, let's go back and make sure that this works as we expect. Refreshing and up once and twice. And, here we go. Let's click it and boom. That works great. But, we still have a problem. This one's a bit more obscure. Let's inspect the element for the page. And, if I scroll down here, look, we have our LI tags right inside of our div tag, but where's unordered list, the UL? Well, the short answer is, we're ignoring it. We appended all of our item view elements straight up into the database list and we don't want to be doing that. We want to append those elements to the list view. So, we just say this.el.html is els. And, then inside of here, once again, this.el. Here we go. So, let's save this and go back and refresh and, once again, going over to our console. Once, twice, boom. I can tell already that looks better. There we go. And, if we inspect, we have a UL tag. You might be thinking this doesn't seem very important. It would be important if you wired events onto our unordered list tag. It'd be completely ignored. And if you didn't do what we just did. Well, let's refactor this a little bit. And, I want this to be a table, not an unordered list. And, I also want it to have some styling. So, I can do that by switching the tag name and then adding a class name variable here. So, I'm going to use bootstrap stuff and I'm going to say "table" and then "table-striped". And, then up here on my item view, I'm going to make this a table row. And, then I've got to come down here and I've got to drop in a TD tag. Yes, our HTML is growing inside of our JavaScript function. This is ugly, but I'll refactor this in just a second. Refreshing one more time and doing our little console dance to bring up our view. Look at that. It looks much better, Using a Template but I don't like that we have HTML inside of our function. That's usually just not something you want to be in the habit of doing. So, let's talk now about templating. In general, the best views in Backbone are the ones that are simple. These are simple views. I like them. But, sometimes you need to do a little bit more work. What if we wanted to add a button? What if our HTML is starting to get complicated? That's the perfect time to use a template. To do that with Backbone, I will simply use the built-in templating engine inside of Underscore. To do that, I just need to create a script tag and I'll set it to type to text Backbone. So, as long as it's something that the browser won't render, we're in good shape. Then, I just paste in the HTML. You can think of this as a view engine inside of JavaScript, complete with the gator tags, as you see here, and I'll output something here called "Name". And, I also need to use some convention. I want to make sure this has database list template. You can't have two elements with the same ID on the page. Well, now that I have this, I can go back into my class and I need to ask for the template. Specifically, I need the HTML out of the template, so I'll use jQuery and I'll ask for the database list template and then pull in the HTML. Now, I just simply take that HTML and hand it off to Underscore. It's the first time we've used it. See that? That's an underscore and that is a global object for accessing the utility library. And, I simply call the template function and I pass in the source for the template and then any data to be used in the template. Remember how I used that variable name inside the gator tags? Well, this is how I'm going to set that variable. And, then I hand the whole thing off back to jQuery. Okay. We should be good to go doing that. Let's go back to our page, refresh it, and I will up arrow once and twice, boom. Just that simple. We are now using a template. And, the nice thing about using a template is we'll be writing HTML where a lot of people believe that HTML belongs: Inside the view. We've taken it right out of our Backbone code. So, to show how this might work, let's go and add some HTML for a button using some styling from Twitter bootstrap. And, we will also add an event for that button that we just added. And, we'll say click of any button and it's going to, let's just call the same function, "Say Hello". Okay, let's head back over to our page and refresh. Oh boy. We have a problem. Jade does not like the indents that we are using, which is okay. We shouldn't be having those indents anyway. I said I was going to mention why working with Jade is nice. Despite Jade getting a little bit confused about our indenting here, I find that reading HTML inside of our client-side templates, like this right here, makes it a whole lot easier to discern that versus the server-side template, which is outside of it. I know that the server-side stuff is Jade. I know that my client-side stuff, well, that's Underscore. So, for me personally, I like the difference. Okay, we fixed it by tightening up our indents. And, if we refresh this, great. It seems to be working. Let's go up once, twice, good. Hey, and we got a new set of buttons and I click and "Hello again". Well, hopefully you're starting to see the way our process is taking shape for wiring up events and rendering things to review. We're going to do this many times. Organizing and Summary For right now, let's take a look ahead at what's coming up next. And, I want to show you if I go to the Mongo-api DBs, well, there's the databases that are inside my local MongoDB instance. That is some really nice JSON that we can work with. But, how do we work with it? Well, next time we're going to tackle working with data and I'm going to show you how to marry up the data with our view. For now, I'll give you a sneak peak. Let's create a brand new object called Congo.databases. And, I'm going to extend a brand new thing we haven't worked with called a Backbone.collection. And, it is going to have a URL to it and it's the URL that we just entered. Next, I'll add Congo.database, which is a model. Use the two bits of data constructs that Backbone gives you. Then, I've got to tell my collection what model it's going to work with. And, can you guess what that is? It's the database. So, Databases is a collection of our Congo database model instances. Whoop-de-do. Who cares? Well, you do. Let's go back to our favorite tool here, our console. Refresh. And, inside of here, I'll create a brand new variable. I'll create it to our collection databases. And, then I can use a simple method here called "Fetch". Fetch is going to go out to our URL and return some data. If I drop this thing down, well you can see it's just an Ajax, Ajax call object. But, if I say dbs.models now, I have two objects in there. Let's drop those objects open and take a look at what those are. Take a look at the attributes and boom. There's a URL and there is the name of a database. It is just that easy to go grab data. That's coming next time. We will wire up our collections and our models and you're going to start seeing the simplicity and power of Backbone emerge. Collections Working with Collections and Data Well, one of the things that I had to keep doing in the last episode to get the view to render was to instantiate it in the console and then call the render method explicitly and then, boom. We had our list view. Now, of course, that is not the way your clients are going to be using this. So, what I'll do just to make sure this thing renders every time our app starts is to pop the instantiation of the list view here inside of Congo.init. And, then I will call render explicitly. At least now this will keep me from having to type this over and over again in the console. But, even that's silly. Let's see how we can change this. And, we're going to do this by starting to work with data. Right now, I've got nothing out there except for templated name. I need to be working with collections. I showed you collections at the end of the last episode. To work with them, you just need to instantiate a new collection. In our case, we're using our databases. And, I can use to JSON to show the objects that are inside the collection. I don't have anything there, but if I use the fetch command, it'll go out to my server and it will fetch those objects. Here, I'm displaying them as JSON using the toJSON method and pull up the console so you can see it. Inside, I have two objects with a URL and a name. That is what is handed back to us from the server. Now, I want to be able to plant that in our list. And, how do we do that? Well, I can start off by instantiating that collection. Let's call it "DBs" for now. And, we use a new keyword and then say Congo.databases. But, now what do we do? We have our collection. What're we going to do with it? Well, as you might've guessed, we can just pass it straight into our list view during the instantiation. All we need to do is specify that the collection is DBs. There's that Backbone pattern again of passing in an object literal. And, then hopefully we can use that in our render function. So, coming down to our database list view, yeah, there's our for loop, completely meaningless and pointless. We can now replace this, given that we have a collection, using this.collection.each. In addition, now that we're iterating over our collection, I can take that iterated item and pass it straight down into my database view. Let's head back over to our database view and instead of planting templated name, I can now use the model that we just passed in. And, I can say this.model.toJSON. And, that will pass the JSON straight into the template engine to be rendered. Let's take a longer look at this code and what we've just put together. Initially, I had a for loop that was looping five times, if you recall. And, inside that loop, we rendered the item view and stored the rendered DOM element, events and all, into an array. Finally, we handed that array of DOM elements to the containing view's DOM element, in our case, our list view here. Now, it doesn't make sense for us to use a loop, of course. We need some real data so we'll loop over our collection. What collection, though? Where did that come from? Well, we passed it in when we created the list view. And, once again in the Backbone pattern it was sending in arguments because an object literal is in play here. In this case, we just assign the collection to the DBs variable that we created above. We can now reference the collection using this.collection and then we can use a built-in method on that collection to iterate over it, each. Now, you might be worried about the use of this here if you're familiar with getting bit by JavaScript, but don't worry. Backbone takes care of all this scoping for you, which is really, really nice. But, before we get to the each method, let's take a look at the common settings on a view, which you might reference from within the view using this. We've seen el, it's the view's DOM element. We've also seen tag name and class name. We've used events already, as well as the render function. Now, we are using this.collection and this.model, the data that backs the view. Typically, a view only has one of these at a time. Okay, back to our code. Where does each come from and what does it do? Well, if you recall, Backbone requires the Underscore helper library and each is a method on that library. The underscore that you see in the code example above is the global underscore object that you can use to do all kinds of interesting things, which we're going to talk about later on. The thing you need to know for now is that Backbone views, collections, and models implement various methods from the Underscore library. Collections, for instance, implement each as a method, making things a bit easier for you to loop over the models that the collection contains. There are all kinds of useful methods in the Underscore library for working with Backbone collections and basic JavaScript arrays. If you're a Ruby developer, you'll recognize many of these method names. Some of them have actually been formalized into the CoffeeScript language, created by the exact same person who created Backbone: Jeremy Ashkenas. In addition to collection and array methods, you can also use some very useful object methods and general functions. One set that's particularly useful is the is functionality, which allows you to interrogate an object to see what it is and what it can do. IsArray, IsObject, IsDate, IsNull, IsUndefined, and so on. Another bit of functionality we'll be using a lot of is the template method, which, again, you've already seen when we render our database item view. And, you can think of this functionality as akin to server-side view engines, except they're just running on the client. You pass in an object literal or a bit of JSON as some data, and the template method will inject it wherever the property name matches the data, just like you see here. Okay, the final piece of the puzzle comes from instantiating our item view. When we iterate over the collection using each, we are actually iterating its collection of models. What model is this? Well, if you recall, we specified which model to use when building our collection when we declared our database collection. So, that means for every iteration we're handed a database model. We can then pass that model off to our item view when we instantiate it, as you see here. Finally, in our item view codes render function, we'll use that model and turn it into JSON using toJSON and then we'll pass it off to Underscore's template method to be used in the rendering of our template. All right, our views are all set with data. Let's go and refresh. And, nothing. Why is nothing showing up? This is actually quite common in Backbone. You'll see nothing very often. Well, the answer is we never fetched the data from the server. If we don't fetch the data from the server, we have nothing to show. So, I will invoke the fetch method here and I'm also going to create two callbacks. One for success, again with the object literal stuff. And, the callback for this takes the collection response and any options that are passed back. So, this is the function that will get fired if everything works out. If things don't work for whatever reason, we can also use an error callback. And, once again a collection, if it exists, will be passed to the error function response, as well as any options. So, I'll move our list view instantiation to success. It doesn't make sense to have a list view if we don't have any data. And, if we have an error, well, just console.log. Oh no. Well, at least this looks like it'll work. It's not the best way of doing things. Refreshing our browser and, hey, we have got data showing up from our server. Well, that's a big step forward for us. bind() and an Event Driven Model Well, it's neat that it works, but it really is not very good code. There is nothing responsive or event-driven about this process. If you look at the code inside the initialization of our app, I am synchronously fetching the data and then I'm instantiating the list view and telling it to render. And, it's just not a good thing. So, what can we do instead? Well, let's take a look once again at our database's collection. So, if I come down and select databases, now we can work with it and I can bind an event to our databases. Let's bind a reset event that gets fired whenever the data is, well, completely reset inside the collection. And, in this case, I'll just pass in a callback function that's going to log something to the screen. So, whenever the collection's reset, we should see console.log. And, how do we reset the collection? We call fetch. And, there it is. "I been reset". That's good. That's what we want to see. Let's bind something else. In addition to binding collections, you can also bind models. We'll be doing this a lot in this production. So, I'm going to bind the first model inside of our collection and I'm going to bind the change event. And, once again, I will use an inline anonymous function and I will just log something out to the screen, just say "model reset". Well, how do we fire the change event on the model? Well, we can just reach into the models. Again, I'll take the first one and I'll use set, that's how you set a value on a model, and I'll set the name to Steve. Boom. The change event gets fired. In fact, you can do an event binding on a collection for a change event on one of its models. In this case, let's just have a change event be fired if the name is changed on a model that the collection contains. And, once again, I'll log this out. My model has been changed. The binding is set. So now, let's set the name once more and we'll set it to something else like Bill. Notice that two events were fired. The model was changed and the model was reset. So, as you can see, there's lots of different event bindings that you can set up for your models and collections. We'll talk more about those event bindings later on. Well, this is good news for us. That means we can clean things up here a lot. So, let's get rid of this fetch method. I'll need to, of course, instantiate the view and also our collection. But, I want to get rid of everything else. And, what I'll do is I'll go down to our database list view and I'll create an initialize function that gets fired a bit like a constructor. It gets fired whenever the database list view is instantiated. Then, inside of here, what I'm going to do now is I'm going to bind some events. So, just like you saw me do in the console, I'll say this.collection.bindreset and then I'll bind that reset event to this.render so the view will render itself. I'll do the same thing for add and remove. Add will get fired whenever I add a model and remove will get fired, you know, whenever I remove a model. We've introduced a new concept here. So, let's take a second and dive into it. We managed to avoid a very important method that you'll be using a lot of: The initialize method of the view. As you can imagine, it gets kicked off whenever the view is instantiated. And, you can do all kinds of things in here, but mostly you'll be wiring up events and various settings. In our case, we know that we're going to have a database collection backing this database list view. The view is useless otherwise. And, we can use that collection's eventing to cause our view to render itself. Now, for many web developers, this is a backwards concept. We're used to shoving HTML around in a purposeful way, telling things where to render, how, and when. We don't necessarily write code that reacts to events on other objects. Which brings me to Rob's rule of Backbone development: Views respond. If you've ever done any kind of desktop development, well, you know that responding to events is key to making a scaleable application. Backbone works the same way. You don't orchestrate what, when, and where, and how a view renders on a page. The view does that in response to a change in underlying data or some input from the user. When I was learning Backbone and single-page app development in general, this was a key bit of understanding for me. These apps share more with the desktop development experience than they do with the web development experience. And, if you don't quite get what I'm talking about, don't worry. I'll be touching on this point repeatedly throughout this production. It will slowly sink in, I promise. For now, look over the code above and see that we're binding the reset, add, and remove events on our collection to the render method of the view. That means that every time we call fetch, every time we add a model, and every time we remove a model, the view will render itself. The last "this" that you see there is simply to make sure that the scope is set properly for the binding, which is the current view. We're going to talk more about that later on. Binding events to view is key to a clean, well-coded Backbone application. We will be revisiting this topic many times. For now, it bears repeating: Views respond. They respond to events that you wire up for the user and events that you wire into the underlying models and collections. All right, well, we have bound our view to render itself when reset is called. How do we get it to be called? Well, we simply call "fetch". Now, if we go back and refresh, look at that. Much cleaner. That is the Backbone way. Refactoring for Clarity Things are rapidly starting to take shape with our app and when that happens, I always like to do a little refactoring to make things a bit more clear. So, instead of databases, let's call that "Database Collection". And, I will change that here in our init function. And, instead of DBs, I'm going to plant those on the Congo namespace. I'll call it Congo.databases. And, I'll make sure that I update the variables in kind. There we go. We'll keep going here with the renaming and let's also put our breadcrumb view on the Congo namespace. So, I'll call this "Congo Navigation View" and I'll remove the render invocation. We don't want that in our init function, which means I need to go down to my breadcrumb view and I'll use initialize here. And, instead of binding anything to an event, we know that we always want the breadcrumb view to show. So, it's going to be shown by default always, so I could just say this.render. We'll head back and we'll do the same thing with our database list view. And, I'll just call it "Database List". Oh boy. I'm starting to smell something wrong here. I think I'm writing some silly code. Let's continue with our refactor and I'll come back and take a look at naming in a second. So, I'm doing two things in here in init. I am initializing the values that we need and I'm also starting the app off. And, that's two things in one function. I don't really want to do that. So, let's get explicit about it. Let's just call Congo.start to start things off. And, in here I will just say databases.fetch and you come back up to the init function and inside here I'll just call Congo.start. I don't like initialize calling start, but in the next couple episodes, I'll refactor this out in using a different mechanism. Well, I mentioned before something didn't smell right about my variable names as I'm refactoring. That's because I'm using proper casing and that's something typically reserved for prototypes and, well, classes, if you will, even though JavaScript doesn't have classes. So, let's use lowercase or camel case. And, there we go. Congo.breadcrumbs, database list. This keeps us in line with better JavaScript naming. And, I'll add my little comment back here. Well, as long as I'm organizing things, I'm looking at this, I'm initializing the views up top. And, really a good habit is to initialize your data first because, well, the views need the data. So, I'll move the collection and model instantiation as it is up to the top. We can add a few comments to make things a little bit more clear. Now, that is a proper wire up for Backbone. All right. Well, let's check everything out and make sure we didn't break anything. And, hey, look at that. Everything works. That's pretty exciting stuff. Things are coming together. Our app is taking shape as an application. We're using good habits and we're keeping things clean. Next time, we'll wire up that start function in a better way using the router. See you then. Models Wiring Up Add() Functionality Well, we've come a long way, but let's take a moment and review what we need to do next. This is the completed application as you can see here. I'm adding a new database and I can also delete a database. So, we lack the ability to add and delete. That's what we're going to be adding in today. This is what we have now, which is just a bunch of placeholder stuff, a button that says "Click Me" that doesn't really do anything. So, I'm going to start off by adding in a section here using some bootstrap styling so we can have add form. And, I'll drop the form right in here. And, just with the power of editing, have some HTML. There we go. So, this is a simple form in the Jade view engine that's going to allow me to add a database. Refreshing. And, there it is. Let's also take a second and pretty up our database table here. And, I'm going to change out that HTML. I'm going to change it to use Jade. And, yes, Jade will work inside of a script template. Interesting stuff. So, there's our Delete buttons. Let's change the height of the names. There we go. I'm going to change those to h4s, as you can see. That looks much better. Okay, well let's flip back to the code and I need to create a new view for our database options area there. So, I will extend the Backbone.view as you've seen me do before. And, as we watch this process unfold, it's going to be the first time I mention Boilerplate. Code you write over and over and over again. Initialize and render. You start to see these patterns emerge more and more. We're going to talk about that in a later episode. Just keep it in the back of your mind for now. Well, for the render function to work, I'm going to be sucking the template out of a script tag like I've done before. So, I just need to create that really quickly and make sure, once again worth mentioning, that you set the type on the script tag so that the browser doesn't render it. In this case, I'm just calling it text/backbone. Then I just move the Jade right into our template just like that. So, now our form should be working fine. Switching back over to our code, we can finish off our render function. Again, we need to use the HTML method, jQuery's HTML method, and drop in our compiled template into this.el. Now, that's not going to work, of course, unless this is a jQuery object. So, we have to go in and wrap this. Now, this used to always be the case. You have to wrap this every time with jQuery and it became a bit of a bore. That is until Backbone decided to give you a shortcut: this.$el makes the DOM element, this.el, into a jQuery object, which is really handy. One other thing to notice while I have this zoomed in is that in our initialize function, I am calling this.render. So, whenever I instantiate a new database option view, it renders itself. I will take advantage of that here in my database view because we want the option view to always render when our list view renders. So, what I'll do is I'll create a brand new function called renderOptionView. And, here I am simply going to instantiate a brand new database option view. Then, I'm going to pass in the element that I want it rendered onto. So, in this case, I just need to go back over here and there it is: DB Options. So, I'm passing in the element this time. I'm not letting it create its own element. Okay. So now that I've done that, I just need to call it. And, I will call this.renderoptionview from initialize. So, let's go back and see if it will work. Heading back over to the browser, let's refresh. Whoops. Well, if you see an error like this and you know it's defined, that typically means you have a namespacing problem. And, indeed I do. I forgot to put Congo. and so let's refresh this. And, there it is. Okay, well. Being good programmers, you might be thinking, "Is this really how it's supposed to be done?" And, the answer is not really. I'm going to talk about that later on in this episode and also in future episodes. You've got to build the case for it, though, right now, so hang tight. So, let's wire in the submit event for the form. You've seen me do this before. We just have to wire up submit and then the search element form. And, then I'm going to create a function called addDb. And addDb, for right now, what I'm going to do is something rather simple. When you handle the submit event of a form, well, it doesn't mean that it intercepts it, if you will. You still have to cancel that form submit. So, that's the first thing we're going to do. It's a jQuery event and so the event information will be passed right in. So, I wanted to make sure I use event.preventdefault. And, a lot of people return "false". That's not a good idea, that messes up the event chaining. But, right now if I click addDb, the form isn't firing, that is step 1. That is something you'll have to do a lot of when you bind to the submit of a form. Once again, Boilerplate. Well, again, we're going to talk about Boilerplate more in later episodes. The next thing I'm going to do is create a brand new model. So, the newDb equals a new Congo database. And then, what do I pass into that? Well, what we're going to do is we're going to use jQuery to pull out the name. So, I will call it newDbName, put it into a variable, and I'll use jQuery to take a look at our form input, which has the ID of newDb. So, using that, I will pull out val and that will pull out the name of our brand new database that I've entered into that input. And, inside here, I will just specify inside of an option I want name set to newDb name. And, that's how you new up a model in Backbone. So, let's take a look at what that model looks like. I will just output it straight to the console. And, heading back over to our page, let's refresh and I will enter some silliness, and there is our model. And, you can see it's got a bunch of stuff that Backbone has put onto it including attributes. And, one of the attributes is a name and that is the name that I entered. So, everything is looking as we might expect. Big deal. Well, let's play around with our console a little bit more. I'm going to instantiate a brand new Congo.database and let's call it "Steve" for right now. And, the first thing I'm going to want to do is send it to JSON so we can take a look at the object itself. There it is, name, Steve, okay. So, let's save it. Backbone allows us to just call a save method. And, it should propagate it back to the server, but it doesn't. Uh-oh. A URL property or function must be specified. Okay. Well, we already did this for our collection, so the model needs a URL as well. That way, Backbone knows where to send it: Back to the server. All right. So now, let's try this one more time. I'll instantiate a brand new model and then I'm going to call save. And, we get an error. It's a 404. Can't post to the URL that we offered. Why is it trying to post? Well, because it's brand new. Backbone uses the same RESTful convention that Rails and other frameworks use. If it's a new object, meaning the ID is not defined as you see here, well, it's going to try and do a post. Many frameworks lean on this RESTful style of pivoting on HTTP verbs. Backbone is no exception. Whenever you have to create a record, a post is sent to your server. If you're updating one, well, it's put and then also destroy fires delete. This is going to influence how you set up your routes on your back-end. We're going to see more of this in just a second. Now, we have a problem. If I go to our Mongo shell and look at the routine I'm using to pull back the databases, well, databases don't have IDs, they just have names. So, looking at this list, what uniquely identifies our database? Well, it's the name. So, how do we tell Backbone that? Well, we can reset this, and often you find yourself resetting what Backbone considers to be the ID by using the ID attribute. And, this time we'll set it to "name". If you don't specify this, Backbone's convention is to look for a thing that says "ID". Okay, let's do this again. I'm going to create a brand new Congo database and, look it, our DB.ID is "Steve". That's what we want to see. So, now if I call save, oh, close. Now, notice that it does a put because it has an ID. It uses the convention of using the put verb, the HTTP verb, if the ID exists, meaning it thinks it's an update. So, let's head back down. We can see, there it is, app.put, that's our routine. It's expecting a database name to be sent in through the URL. We don't have a database name as part of our URL. So, what I need to do is I need to set URL to be a function that is going to return a string. Well, what string? Well, let's return Mongo API DBs, but this time, I'm going to concatenate in the ID. And, you might think this looks nuts. Well, it kind of is. But, it's a pattern that you'll get used to when you're working with non-Railsy, if you will, applications that have different ID names other than just plain old "ID". Okay, well, that is our fix for now. Let's flip back over to our browser, refresh it, reload all of our DOM stuff. Once again, I'll create a brand new model in the console window and I'll hit save. And, boom. Look at that. I think it worked. I'll refresh the screen. Hey, there's Steve. Steve got popped into our database. Although probably not exactly the way Backbone wants us to do it, that's okay. The goal here is to show you how the mechanism works and also that you can get around it if you need to. All right, so, in my addDB function, I am going to just save my model. And then, when it's saved, I am going to call Add on our collection and add in the model to our collection. Now, why do we care about that? Because when we add a new item to the collection, well, guess what's bound to it? The render method of the list view. Remember how I always say "Views react", so our view is going to react to a brand new database, it's going to re-render itself. That's exciting. So, let's go and keep with our guys' names from the 50s. I've added it and then, look at that. It shows right up. That's exciting. So exciting, I'm going to do it again. Joe. Woo-hoo. Adding a Delete() Function Okay, so that works, but now if we want to delete these silly names out of our database, well, we can't do that. Let's wire that up now. And, what we're going to do is head back down to our database view. This is the item view, if you recall. Each one of these views represents a table row. Inside here, I'm going to create a function called "RemoveDB". And, inside of RemoveDB, we are going to reference this.model. Now, if you've been wondering "Why am I jamming out an item view per row? Wouldn't it be better just to have a chunk of JSON that goes in and gets iterated over?" Well, no, because we want to have events bound to each item. We also want to have a model associated with that item so we can call this.model. In our case, we're saying this.model.destroy and then we're having our collection remove that model. Before we demo this, though, let's be good programmers and throw in a Confirm box and make sure that the person wants to delete the database because, well, that's a big operation. Okay. Refreshing and, hey, look at that. Delete this. Oh, yes it works. That's good, but, wait a minute. Uh-oh. It only works once. That's strange. Did you spot the error? This happens all the time with Backbone. You'll look at something and, rejoice, it works and then something strange happens like our little event craziness. Oh boy. We have a problem. Let's go and take a look at our list view. I'll explain this in a second, but do you see what the problem could be? Let's clean this up a tad and we'll remove the comments. And, what I'm going to do at the very top here is I'm just going to make sure that we know that this render function is indeed called. That's the first tip. Is render being called right? Okay, so, we'll refresh this and, yes. Out on the log it says "render called". Good. So, when I add a new database, render should be called as well. So, I'll just put in "Where is delete". Yep, boom, render is called. Oh, we can't delete. That's not fun. We have our first Backbone mystery, one of many to come. It's incredibly easy to get sucked into the mental void that marks the intersection of JavaScript and basic DOM manipulation and frameworks pretending to work like they're on the desktop. Every mystery has a solution, however. So, let's take a look at the clues and see what we can solve. Well, fair warning here, if you're new to jQuery, JavaScript or DOM events in general, this just might hurt your brain. So, let's take a few steps back and understand what we're doing. We encountered a bit of weirdness with our render function. Every time we added a new database, we could immediately delete it. But, then we couldn't further delete any other database. If we refreshed our page, the same thing, we could delete exactly one database, didn't matter if it was new, and then no more. So, that's our first clue. This has to do with the way the events are being handled for our item view, which again, handles the events for the delete button. Our render method doesn't like being called more than once. So, our item view, if you recall, is being rendered in line right here, then added to an array so that we don't have a memory problem if our list becomes very large. We're using the DOM element returned from the view: render.el. But, what exactly is that thing? Let's dive in. As we've mentioned, el is a single DOM element that the view renders to. When our item view is rendered, we get back this blob of text, which is how you can think of a raw DOM element that also has some events attached to it and that's about it. So, everything looks okay so far. Nothing stands out as problematic. After the array fills up, we're adding it to our parent view's el, but we're using a jQuery function to do it. This.$el is a special jQuery element provided by Backbone for you to use to do operations, well, just like this. It's a replacement for how you'd normally have to handle this.el with jQuery in every single view. So, you can think of it as a convenience method. So, to recap, el is just a basic DOM element. $el is the view's DOM element wrapped in jQuery and scoped to the current view. Using $el, we can access jQuery's HTML method, which then it adds the child table row elements to the parent element "our table". Again, nothing extraordinary here. Everything is rendering just fine or so we think. And, this is where things get smelly. We are onto something. It's confusing to be sure, but let's see if we can take it apart piece by piece. We're using jQuery's HTML method to append our view's DOM element, our table, to the database list div tag. This works just fine, but breaks down when render is called more than once. But, what does the HTML method actually do? Well, reading the jQuery source, you can see it's pretty much a convenience method for calling to other methods: empty and append. When you call empty on a DOM element, everything inside that element gets erased: Text, child elements, and of course, any child element events. This is the behavior that we're actually seeing. I think we're onto something. We're losing the events and the child elements of our table, but how can that be? We're re-rendering and re-outing them with every render method. Or, are we? I can actually fix this problem by clearing out the database list div tag at the start of our render method. In fact, this is a rather common pattern that you'll see in Backbone: Clearing out the view's elements when render is first called. But, this feels really messy. Why should I need to call empty at the beginning? Doesn't the HTML method do that for us? Moreover, this is a clue. The only way any of this could be possible is if our view element, our table tag, is not being cleared out as we thought and, instead, lives on as a child of the database list div tag on every single subsequent call of the render method. If that's the case, then when we call the HTML method here, we're dropping and reloading all of the table rows. And, those rows, along with our table, still exist on our database list div tag, our container. So, really, we could just stop right there. We don't have to do any further attachment or rendering or anything, but we do it anyway, we call the HTML method on our database list container. That empties and appends our table. On the face of it, that should be okay except that all of our events that were attached to our child elements just got wiped away. Remember, they're children of our view's element, the table tag, as well as the database list div. So, in essence, we are wiping out the elements and their events and then adding them back again, which, to me, shouldn't work, but it does. It's also making me see that this isn't a Backbone problem, which is nice. It's bad code on my part on many levels. So, how can we fix this? Well, for one, we can stop using HTML and we can use append because append does not strip the events away the way HTML does with its call to the empty method. And, I know what you're thinking. That's what I still think. But, there's a better answer to all of this. Just hold tight as I think it's very important to understand the problem here, so let's dive in just a little bit more. If we're calling jQuery's append method, won't it keep appending the child elements? The short answer is no. jQuery is smart enough to know that we've already appended our table element so it doesn't append it again. And, that's because it can't. It's already in the DOM and it already appended it. I know this can be a mind bender, but if you consider this in terms of instances of DOM elements, it starts to make a bit of sense. Then, appending a DOM element instance in one location means that you have to remove it from another. And, that is exactly what's happening here. But, we're using the HTML method with our table element. Well, why doesn't that pose a problem? Well, the short answer is that we're generating all of the child elements in our loop. A new table row is created for every element in our collection and this happens every single time render is called. As far as our DOM is concerned and jQuery as well, these are brand new elements. Our parent element, the table tag, is not new. So, HTML is safe to use here and proper. If we use append then, yeah, we will load up on table rows and keep repeating them. Okay, well I mentioned there is a simpler, more correct way to do this and solve this whole problem and that is that you don't want to be in the habit of rendering directly to a DOM element from inside your view. That's actually considered an anti-pattern and a code smell, if you will. It seems like a good thing to do as it can keep things simple, but you just saw what happens if you're not careful. So, in the next few episodes, I'm going to orchestrate things a little bit better. We'll put the pattern that you see here into place, but we need to do a few more things before we get there, however, so I'm going to ask you to be patient. Otherwise, I would just do it right now, but there's a few more concepts to go over. My thanks to Derrick Bailey and Dave Ward who helped me solve this and understand this problem at a deeper level. Well, so let's switch this to append. I'll say right here, right now, I still am not sure exactly what's going on. That little spiel I just gave you is my best guess based on a conversation with Dave Ward and Derrick Bailey. All right, well, here we go. Refresh it. Now we can hit Delete as often as we want by using append. And, that makes us excited. And, I'll also once again say that the way I'm rendering this thing out is suboptimal. I will be changing that in a later episode to use better patterns. Using Validations All right, well, let's continue on here. You might be thinking, "Well, that's kind of silly. What if someone puts in silliness for a name or nothing at all?" Well, the neat thing is that models have the ability to validate information and you do that by passing in a validate function. That function will receive the attributes of the model. So, what we can do is we can interrogate these. And, we can say is the attribute name empty? Is the attribute's name null? Is it defined? Well, this gets pretty tedious rather quickly for what is really just a check to see if the thing is even there. Well, the good news is we can use underscore and we can just say _.isempty and we can check for the attribute's name. Working with validations in Backbone can be really confusing. At least it confused me when I started working with them. It's tempting to think that you're working with the instance, that you should be able to say something like this.name shouldn't be empty, for example. But, that's not what you're doing. You're actually extending the Backbone.model.prototype and instead of working directly against an instance, you're handed a variable. In this case, a bunch of attributes that I've named "atts". But, it gets more complicated still. Atts only contains the things that have changed. It does not necessarily contain all of the information on your model. You're just handed stuff that's changed. In our case, since I've just added a name, the name should be on there and I can check it using _.isempty. We will come back to validations later on. That is just a simple primer. Okay, so, I've got this in here. Now, let's take a closer look at our validations using our console. All right, well ,I'll start by creating a brand new instance of our Congo database. And, we'll ask if this thing is valid. And, like we expect: False. There's no name present. So, it's not valid. Can we save it? Let's go to db.save. Uh-oh. That should be false as well. Refreshing and, oh no. DBs. Can you spot what the problem is? Let's go back and create a new database instance again. We're going to say db.set and we'll set the name, in this case, to "null". Let's see what happens. False. It wasn't set because it was null, which means it was empty and our validation got fired as we'd expect. db.getname, there it is. It's undefined, it's not there, it was never set to begin with. db.isvalid, false. The way Backbone works is that if the record's not valid, an error will be thrown and save will not be called. That's the way validations are supposed to work. You can trap that error like I'm doing here. You can say db.on error, let's bind the error event, and I'll just output that to the console. So, let's try and set one more time. We'll set the name to "null" and, boom. We need a name. You've logged that out to the console. That is everything you would expect to see. Now, when we try save, error gets thrown, but the object still gets saved back to our server. Welcome to the Backbone weaves. What's going on here? This is completely unexpected. This goes totally against the way Backbone should work. Save should never be called. Let's go and click on our undefined here. This is our post off to our server. Yep, it's doing a post. As you can see, it's pulling out the URL. It's passing undefined to our server. So, why is our server entering the term DBs? Well, looking through the routes, we can scroll on down. Where is app.post? Something that listens out for a post request. Aha, I see it right there. That is the route that is trapping our errant request. And, it's pulling in the name as DBs because, well, it's part of the URL. And, the way that Mongo works, if the database isn't present when you request it, it will make it for you. Well, if the thing isn't valid, then why in the world is save even firing? Well, let's go back down here and we'll take a look at the source code of Backbone. I have it in the project as Backbone_dev. Here's the save function and you could see that it's doing some operations on setting the attributes of the object. And, if we look up a few lines, we can see that it's validating the attributes as set unless it's the key. Oh boy. Do you see the problem? We have named our ID attribute to name. We also have a validation on name. Do you see the problem yet? In Backbone, the ID of the object needs to be able to be null or empty. If it is, that means it's going to be creating a record. Now, you might be thinking, "Rob, why did you just show me all of this? Why didn't you just show me how validate is supposed to work and we move on?" Well, the simple answer is this is the Backbone development process. For some reason, people seem to be prone to falling backwards into these crazy errors. Trying to bend Backbone a little too hard and, boom. What we did today was we tried to do two things that countered the typical patterns you see in Backbone that, frankly, just aren't discoverable easily. We screwed up our rendering of our view, which clipped our events and caused us to lose some time until we figured out how jQuery works. And, here we screwed up the validation process because we decided to set our ID attribute to name and then set a validation on that, which, again, is countered to the way Backbone does things. Now, we're going to be working with these functions later on, but we're going to know what to do. My way of thinking, understanding the pitfalls before you actually start writing code is usually the thing that, well, helps you write good code. Well, thanks again for coming along with me on this journey today. I hope you learned something and Backbone is starting to get a little bit more complex. See you again next time. Refactor 1 Refactoring and Using Inheritance We're starting to write some boilerplate code as evidenced by our render function here. We'll be writing this a lot more, looping over collection, rendering the itemView, pushing it to Views element, and then passing it back out. That happens a lot with Backbone, so why do it over and over again? Let's refactor a little bit and use inheritance. Inheritance is a weird thing in JavaScript. You don't really inherit like you do in objects oriented programming. What you do is you extend the prototype, which basically means grafting on functions and objects onto another function to extend it. In this case, we're going to make things easy by using underscores extend feature, which is part of Backbone. So to start things off, I will create a Congo ListView. This will be a base class, if you will. That's going to extend to a regular old Backbone View. What I'll do is I'll just Paste in all of our database ListView code and slowly work the refactor, and I'll have our DatabaseListView extend Congo.ListView. Now, to kick things off, and make sure everything works, I will add our base class, if you will, our base library, here into our Index page. Let's Refresh and make sure everything works, and it does. Our extension and inheritance scheme, well it works with our hardcore dump of code into the base class. So let's refactor things a little bit. I'm going to get rid of the option rendering stuff. We don't need that here in the base class, of course. Then I'm going to take out a few properties that I can pop into our inheriting class, our DatabaseListView. This is going to specify I want a tagName and className specific to our DatabaseListView. I don't want that on the base class, of course. I'll Refresh this, and everything works as expected. The next thing I need to take out of the base class here is the reference to our Congo DatabaseView. I want to be able to pass that in as an itemView property, if you will, that I can pass down into the base class, and inside of here, I can just say new itemView, because that will be passed in from our inheriting class. I also need to get rid of this hardcoded call to the jQuery element, the database list. I'll do that in just a little bit. Let's take one step at a time. So if I go back and Refresh, ai-yi-yi, this is why we take one step at a time. I have an error. The first thing I'm going to do, I don't like the camel case here. Let's just set this to proper case, if you will, because I'm dealing with Views, it just seems to feel better. It's not going to fix anything. And looking over our code, can you see what the problem is? Saying itemView is undefined. Have we seen this before? It's our old friend, scoping! Yes, anytime you have a loop, and you're trying to operate on things inside of a loop, you will lose scope, because you're inside of a different function, var self equals this to the rescue, and we'll Refresh, and BOOM, there we go! Okay, well that seems to be working, let's continue on. We have our ListView, and we've removed a lot of code, and that's nice. Let's now go and we'll do an ItemView. And the ItemView will abstract away, well, the basic view mechanics that we have for our table rows. So once again, I will create an object called ItemView, and I'll extend regular old Backbone View. I'll rip out the render code, because the rest of this stuff pretty much is stuff that's special to the inheriting class. There we go. I have render. Now, I need to take out our list template reference, because I don't want that hardcoded in there. In fact, I'll take out the whole entire line. And now I'll reference this.template. This template is a property that sits on Backbone Views. I can set template up here, specifying a jQuery selector. Finally, I'll reset this from Backbone View extend to Congo ItemView extend. And we should be good to go. Let's go over to our browser, and I will Refresh, and, no, whoops. Forgot a step in my class here. Forgot to actually pull in the template html. I need to do that of course. I want the source, I don't want the actual selector, and so I'll pop the source in there, in our template function. And, wahoo! Alright, that's working. Starting to save ourselves some code here. So, in looking this over, this render function is pretty standard. It's what you see in just about every View out there, so let's just call this a Congo View. It doesn't need to be an ItemView. It can work for any View in our scheme here, and that means that we can go back and we can change a few things out. So, I'll go back, and just have this inherit from Congo.View, that's our DatabaseRowView if you will. And then for our option View, I'll do the same thing, just say Congo.View.extend. (Typing) And I'll also remove the render function. And then set our template for Congo View right here under initialize. And there we go. Let's go and make sure that this works, but there's kind of no way to tell. The optionView isn't showing up, it's because we've kind of dismantled everything we're doing. If you recall, we ripped out the render optionView function, as we split things apart and started to refactor. This is where things start to get a little complicated. So, let's take out our hardcoded reference here to our database list, and what we should've done before. View should not be appending themselves directly to the DOM. That is not a very good habit, although some people do it, because it's the simplest thing to do, and that's all they need. Typically you want to always return this to some higher level View, but doing that, well it leaves our screen blank. What's supposed to happen? Let's go back to our Jade page here, index.jade, and let's setup a little bit more structure. Typically in a Backbone application, you'll see a single div that contains everything else, called something like app. Inside of here, you might find some basic styling for areas of the site, we'll come up with some good naming in just a second, but you'll see things like nav for navigation, and you might see another one called details. Again, this kind of structuring is incredibly common, and one rule that I typically follow is any time you see a pound symbol, well that should very well be a View, and in our case we need an app view, and a details view. We'll talk about the app view in a later episode. Next, I need to remove those database list specific tags there. I need to remove those into their own template, because they're going to be rendered into our details view, so let's put them in their own template. And I'll do this, as you've seen me do before, just create a script tag, give it an ID of db details template, and inside there I'll pop in our containers for our list and our options. And finally, I'll make sure that I render the breadcrumb view to the nav element. Refreshing, and yeah, everything looks pretty good. Things got jockeyed around a little bit with the Twitter bootstrap styling, but I'll take care of that in a little bit. Right now, what I want to do is I want to create a view for our details, but what kind of view are we talking about here? This is just a view that contains other views. If you think this is a bit of a View explosion, well hang tight, you'll see the good reason why we're doing this. So inside here, I'll create a single render function. This is a different kind of View. Again, this is responsible for rendering out other Views. So let's start out slowly, and then I'll refactor this out. We know that we need to render our database list, and we also need to render our options view, and we want to do it as part of rendering this View. So the first thing I'll do is I'll just instantiate a brand new DatabaseListView. This is the one that we've used before. And then I'll do the same thing for an optionView, I'll just new up Congo.DatabaseOptionView. Again, you've seen this happen before. Finally, I'll just take the rendered elements from those views, and append it to detailsView's element, and then return the whole thing back. Now again, this is just hardcoded. I just want to be able to contain our OptionsView and our ListView in a larger View. So to see this, make sure it's working, I will just create a new instance of the DetailsView here, and I'll also pass in details as the element that it should render to, because details, once again, is the container. Alrighty, well how is this thing going to get rendered? Well, I'll go down here, and in an initialize function I'll just call this.render, so right when we instantiate it, BOOM, it'll throw itself out onto the screen. So Refreshing our browser, ugh, we got an error. Can't call method toJSON of undefined. Ah! So it doesn't know what this.model is. Let's head back over to our View, our Congo.View, and it makes sense if there's no model, we shouldn't be trying to call it to toJSON, so let's just do a quick null check operation here, and I'll just say if this.model is null, or if it's not null, excuse me, then I'll set data to this.model.toJSON, and then I'll pass that off to the template function. That should work. So, let's go back and Refresh our stuff here, and hey! Look at that, sort of. It rendered! That's good! We have both Views rendered out, but if we go and take a look at the HTML by trying to Inspect the elements, yuck! We can see that our table is being directly rendered inside details, as well as our options for them, so let's see if we can fix this. Let's go back and take a look at our View page. Inside of here are the two div tags that were supposed to be rendering our database list to, as well as our options form. In looking at our View code, well, we're just rendering our form straight into the details views el, this.el. That's not going to work. We need to be rendering that into our database list tag, this guy right here. So, let's just use jQuery. I want to do the simplest thing possible to get this out on the screen. Also, let's rename this so it's consistent. We're going to name the options one to database options. Okay, so I'm just going to grab this with jQuery, and I'll do the same with dbOptions. I'll just grab that element, and wrap it with jQuery. And then we can just use append on dbDetails, and append on dbOptions, dropping in our listView, and our optionView. That should work, and have everything work nicely, and then finally I'll just say this.el.append dbDetails, and then dbOptions. Okay. Well that should work. I know it's ugly. I'll be fixing this all up in a minute. I'm just trying to go slowly. That is the key to working with Backbone, go slowly so you don't end up in the weeds. Let's Refresh this, and there we go. Nothing! And no errors! Welcome to Backbone. Again, this happens quite often. Nothing will happen, and you're completely stuck. But we do have a friend, console.log, so let's drop out dbDetails and make sure that we have a DOM element that we can work with. And what's this context document selector database list? That's not right. That shouldn't be the case. It should be details.database list, and we can do that. Backbone scopes this to the current view, so we can just use this, and then $database list, and there we go, we can see the selector's been updated, and the search path is confined to the details tag, but we still have nothing in our View. Why would that be? Well, if we head back over, we can see that we have a details div out there, and we have our database list and database options inside of a script template that we are never actually calling. So, we actually need to render that template, and add it to our DOM element here on the details view. So, as you've seen me do before, I will say templateSource. I'll use jQuery, and go grab that template, and then finally, append it to our details views DOM element. And we'll simply call _template's function, and pass in the templateSource. Now, our template, templated divs, live on our details views element. That means the rest of our code should hopefully work. Let's Refresh, and there it is! Playing with DOM elements, woo-hoo! Unfortunately, we have a bit of a rendering problem, but that's okay, that's just some bootstrap styling we can really quickly fix that, as you've seen, I've just done. And let's Refresh. Yay! It works, and it's laid out nicely, but it's really ugly! We did clean up the code for our DatabaseListView. It's all of three lines, which is great! We also removed the direct call to database list, but we just moved it under the covers. It's now hardcoded in our details view, which is never a good idea, of course. So how do we fix this? Well, we're going to need a strategy. Talking about Views that contain Views, ListViews that render ItemViews. We're starting to get a lot of vernacular, a lot of structure flying around. Maybe it's time we take a step back, and put on our thinking hats, be good engineers, and see if we can approach this with some sanity. Naming: Concepts and Conventions I promised that we'd move quickly from the basics into more complex issues, and here we are. As we start laying structure and abstraction into our application, it's important that we start using appropriate naming conventions. This is a great exercise, because if you're having a hard time naming something, well, usually that means the concept you're trying to work isn't very clear to you, at least that's what happens with me. So let's take a second and work up some naming. The first thing I like to do when thinking about structure and abstraction is to ask, has somebody else already thought about this, and dealt with it? And our answer here is, yes! As I've been saying all along, Backbone is a great framework, but it leaves a lot to you when it comes to abstraction and structure. Given that, a number of frameworks have popped up over the years that offer the structure we're looking for. Marionette.js from Derick Bailey is one such project. It's quite popular. It's a framework created in the tradition of all great frameworks, including Backbone itself. It was extracted from real world projects, and the patterns that emerged from working with Backbone day in and day out. Now, I'm not going to plugin Marionette.js just yet, as I don't really have a need for it. After all, we've just gone through some basic abstraction, why plugin a framework on top of a framework unless our complexity demands it? In a few episodes we'll revisit Marionette. For now, let's take a look at some of the structure it provides, and see if we can steal some of it. So Marionette.js is based on a set of patterns from Microsoft called Prism that Derick Bailey used while developing Windows Desktop Applications a few years back. These patterns seem appropriate for complex, single-phase Backbone applications because, well many of the interactions are the same; Composition, Layouts, Event Handling, and Messaging to a remote server. Now initially the terms you start to use come off as a bit, well, jargony, something that application astronauts might use in the architecture cafeteria while running code reviews, sipping their cappuccinos. To me, terms like Event Aggregator reek of nonspecificity, bordering on project manager speak. But what are the alternatives? I could name something Steve and Bill, I suppose. But as I looked around, I found that the lingo Marionette uses makes fine sense as long as we all agree on a definition for these rather bland words. So let's get to that. First, we know what we have been dealing with Views, Backbone Views. These Views have taken on various duties in our application, and have been assigned certain roles. Our breadcrumb navigation is always present, and lets the user know what they're looking at, and also provides a bit of history that a user can go back to. We have a list of databases, and finally a form to add a new database, which we've called our databaseOptions. Abstracting these out a bit, patterns are starting to resolve that we can write code to. We have a Navigation View, our breadcrumbs, a List View, and Item View, which we've already extracted, and finally, an Options View, and that's all good, but we need more. To get these Views to show up properly, we found ourselves hardcoding jQuery calls, as well as positional, and event information into our Backbone code. It's not a good idea. It's becoming apparent that we need some level of View management. A typical thing that Backbone developers do is to use an Application View, the mother ship, if you will, that contains all the other Views. It's responsible for rendering and placing things in response to user interactions in a global sense. But we need a bit more fine-grained control than that. We need another set of Views which can manage when, and where the navigation is shown, as well as the detail information of our app. These are called Layouts. Right now we're only showing a List and some Options. That might not always be the case, so encompassing everything in a single Layout, a Details Layout, makes good sense. Finally, the Views inside a Layout are referred to as Regions. These are generic placeholders for things that go inside Layouts. So let's recap our new set of jargon. An App View contains everything. Then come the Layouts, which contain Regions, and Regions contain the individual Views, like Lists and Forms. A nice way that you can conceptualize this is using a bit of HTML with some id tags. One thing I like to keep in mind is that if I create a tag with an id, it should be a Layout, or a Region of some kind. Here you can see how I've translated our new jargon into something useable, and recognizable. And you might be wondering what the benefit of all this structure is. Well, having a nested structure like this allows you to have complete control over what views are rendered, where they're rendered, and how they are rendered without hardcoding DOM information deep in your application. For instance, you might have a View that needs to have the entire application space on a page. You can do that easily if you have a top level Application View. Okay, now that we have our jargon down, let's get back to coding. A Cleaner View Structure Alright, armed with the knowledge of people that have been doing this for a long time, let's see if we can implement some good patterns. I'll rename our details view to layout, following Derick Bailey's Marionette convention, removing all of the hardcoded stuff from before. Alright, we know that Layouts need to work with Regions. For our purposes, I'll just assume that regions is going to be an object literal with various properties on it that have selectors and names for the regions. And, because we'll be using a loop, we got to do our old favorite thing, var self = this. Now if you're wondering why are you looping over this stuff, this doesn't make any sense. Hold tight. Hopefully this will make sense in just a second. So what I really want to do is I want to have these regions be exposed explicitly as jQuery objects. So what I'm going to do is loop over each of the region settings, and I am going to drop on a property to this View based on the name, and I'll have that value be the selector. You'll see what I mean in just a second. Finally, I want to have a method to call, like an event callback. I'll call it layoutReady. If there's a callback set, then I'm going to call it directly. Basically, I'm going to have my Layout View here just essentially prepare itself for where all the sub-views are going to go. This looks odd. I'm going to cover this in detail in just a few minutes, so hang tight. Okay, so now that we have a Layout, let's implement a Layout View for our database, and we'll call it a DatabaseLayoutView, surprise! I'll set the template to be our details template, and then I'll declare a property on this thing called regions. Regions is just going to be an object literal, and you can loop over object literals, and pull out the keys, and the values. In this case, I want to have keys and values that identify what the regions are. Our first region's going to be a databaseList, and it's going to have the selector of database list, and you can guess the rest. Well now that we have our regions, it's time to write that function that I set up as a bit, well, an event callback, layoutReady, meaning that the regions have been turned into jQuery selectors, and so in here I can simply create our Views. Just like you saw me do before, and I said it was hardcoded, well it doesn't matter if I do this in this class, because this is a dedicated Layout View for our databases. So I'll instantiate the ListView, and instead of setting the collection to the global Congo.databases, I will set it to this.collection. This is always a good idea if you can avoid direct calls like that. It keeps your Views a little bit more nimble. And I'll set our optionView to a new instance of our DatabaseOptionView, and it has nothing that needs to be sent in. Well now that we have our Views instantiated, what are we going to do with them? Where do we append them into the DOM? Well that's what we did in our Congo.Layout object. If we go back and review, this code this starts to make a little bit more sense. We are declaring self name, or popping a property on, that's going to be a jQuery object. So, in our case here, databaseList is now a property on our View. Same with databaseOptions. The value of that property is the jQuery selector, so I can say this.databaseList and .append, because this value is a jQuery selector, dbListView.render.el. The same pattern that you have seen before, except we're being a lot more explicit. And same thing with databaseOptions, do .append, and then the optionView, we'll render it out, and drop in the element. That looks pretty good, so let's go and wire it up, and see if everything works. Now head over to index.js, where our Congo app is declared, and let's clean things up a bit. I'll remove Congo.details because we don't have that anymore. I just blew it away. So, what I'll do is I will be explicit about where I want to do here, which is to show the databases. So I'll create a brand new function called showDatabases, and inside this function I will be free to declare and manipulate whatever I need to show those databases. So, first thing I'll do is instantiate a brand new dbLayout View, or DatabaseLayoutView. One last bit of refactoring, it doesn't make much sense to fetch the databases in start here. I mean, it would still work, but I'd rather do that fetch routine inside of our showDatabases function, and then, in start I'll just say Congo.showDatabases. That is much more readable and conveys a lot more what the app is supposed to do when it starts up. And then Refreshing our browser, and look at that! It works, sort of. We got a bit of a spacing issue in there. Let's shrink a few things, and KABOOM! That works pretty nice. But, does the functionality, did we retain that? Let's go and add a database, and I'll just put in one that is called works, and yeah, look it shows up, and I can Delete straightaway, so no eventing problems. Everything works the way we expect. Developing with Backbone gets complex rather quickly, so it's important to drop some structure in when you need it. In our case, we needed a little abstraction so we stopped writing the same code over and over again. My thanks to Derick Bailey for helping me out, showing me some sensical patterns, giving me a lot of ideas. Alright, we'll see you again next time. Routers Introduction to Complexity We're at a turning point in our application. Things are becoming more complex, and we're having to think ahead just a bit more. We're juggling concepts, and trying to make everything work happily together without piling on a ton of technical debt. So far, things are working okay. But that's about to change. In this episode, we're going to crank up the complexity even more, layering in new concepts, like navigation synchronization, and the use of a controller, of all things. Well my personal goal with this series is to rapidly move beyond the typical, hey, this is a Backbone Model, and this is a Backbone View, type of screencast. And we're kind of here. Don't get me wrong. Simple demos have a place in that they convey concepts quickly, and allow you to muse on how you might use a given tool. But I find that this is just not enough when it comes to working with Backbone. When building something real, many developers quickly become frustrated when working with Backbone. It's tempting to blame the framework, but consider what Backbone is trying to do. As we've seen, Backbone sits right in the middle of three nebulous, tiring, and frustrating bits of technology, the Document Object Model, or DOM. Evented programming is expressed through the DOM, and the JavaScript language. These technical domains are incredibly frustrating on their own. Putting them together is a perfect storm of insanity. The fact that we've come this far is a testament to Backbone's capabilities as a client side framework. So let's put the pedal to the metal, and see how well Backbone can handle the stress of our added complexity. But before we get to the next tasks, let's talk about where we've been. In the first six episodes, we introduced the core concepts in Backbone, Views, Models, and we've refactored a little bit as well. We started to work with each of these, and came up with a simple rule, Views react to changes in data, as well as user interactions, such as the click of a button or link. We've also seen how simple it is to wire up events to our various data objects, collections, and models. And finally, we refactored our work a bit, and added some abstraction to help reduce code duplication. Simple stuff. And we've manage to stay afloat during this process by following some simple rules, and good practices. But as I mentioned, this is about to change. Up until now we've dealt with simple concepts, but now we need to layer in some orchestration, navigation, and state. Now those words are a bit vague. Let's break it down. Orchestration is the process of getting things to change and work together in harmony. We've touched on this concept briefly with our Layout View, but what do we do with multiple Layout Views, and how do we get the data to change in each of those Views as we need? We'll be moving between Views, and we'll need our data to sync properly, and so we have some thinking to do. We're also going to need a mechanism so that the user can navigate our application. This will kick off the orchestration. Now it would be ideal to have everything handled by a single View, but that's simply not going to happen. Multiple Views have links and buttons that can move their user around our application, and we're going to need an elegant way to handle all of this. Finally, we're going to introduce the concept of state to our application. We're going to navigate around it, we're going to orchestrate some changes, and we want to have the ability for a user to remember where they were. This is probably the single most challenging concept for us, as state is just not a word you can casually use when working with the web. It just doesn't exist. The web is stateless. We want our user, as I mentioned, to be able to navigate to a database, a Mongo database, and see the various Mongo collections in a given Mongo database. And we want them to be able to return directly to this place, and have it look exactly the same as when they left it. We can achieve this in Backbone by manipulating the browser's URL, which will allow the user to use the browser's bookmarking system. Hopefully you're starting to understand what I mean by layering in complexity. The good news for us, well we don't need to create any of this by hand. Backbone gives us a mechanism that can handle these tasks, and it's called a router. The job of the router is seemingly simple, route client URLs to a specific action, or a specific event handler. That's all it does. But it can do so much more. Which leads us to troubled waters. Wouldn't be nice if everyone agreed on what a router should do? Are you kidding me? This is computer science. The Backbone router started life as the Backbone controller. The idea was that the router would act, well, just like a controller, receiving user events from event triggers, or URL routing matches, and then it would orchestrate a response. Unfortunately, things are never that simple. Letting the router control your application builds in a heavy reliance on its functionality. And much like controllers in an ASP.NET MVC application, or a Rails application, well they can quickly takeover everything and start doing way too much, and now you have a problem. The kicker of all of this, most of the time you probably won't even need a router at all. If we remove the requirement for state, and to have a URL as a bookmark, the router's job becomes unneeded. We can handle navigation in a much simpler way with a navigation model. And in fact, this is the first thing about routers that I'd like to convey. Don't use them unless they're necessary. Now, you might be asking, Rob, why do you say that? That's a good question. Let's find out. By using a router, you're having to maintain the idea of state in your application. This means that a user has the ability to come right back to your application and see exactly what they saw before simply by using a URL, or a bookmark. In addition to this, you need to be sure that you're standard navigation, clicking a link, or a button, will do the exact same thing. This can be a huge headache, and the only way you can get around this is by using the router as a centralized routing, and eventing mechanism. In other words, a controller. Now that could be okay, but the router isn't meant to be a controller. It can actually cause a bunch of headaches. So the question has to be asked right up front, do you need to do this? How many desktop applications that you know of have such an idea? Well, not many that I've used. There're no URLs with a desktop application, and haven't we been following the whole desktop application idea? So remember how I said before that Backbone's just right in the middle of three frustrating technical domains? Well, let's add a fourth, URLs and state. So far we've been following, as I mentioned, the desktop development style of building our application. But a URL is a web concept, and a highly charged one at that. It simply does not make sense to have this unless you fall back to the idea that we are, after all, building a page on a website. Do you see how this is making things a lot more complex? This complexity needs some justification, so rather than just nod your head when your PM, or your dev lead says, let's be sure to give this a route, make sure there's a justification. More code is involved, and more code means more support, more tests, and of course, more maintenance later on. So for now, let's just pretend there's a justification for using URLs, that you're going to need a router, we have to see how this thing works after all. And we want to be able to bookmark a database, or a given collection. So now let's get on with our work. We're programming on top of an evolving process. Patterns are emerging, and we're slowly abstracting things away to reduce code duplication. It's critical that we pay attention to what's happened before, all while embracing the idea that layering, and too much abstraction at this point will cause confusion and stress, and probably unneeded work. Now it's tempting to see these patterns resolve into a higher order, and being the good plumbers that we are, we'll probably want to extract it all so we can reuse it later on. Now I'm going to ask you to hold off on that as many people have already done exactly that, including my friend Derick Bailey. Many of you have asked me if we would be covering Marionette.js, and yes, but not just yet. I've maintained that our application is a bit too simple to introduce a library on top of a library, but with our latest changes, who knows. Marionette handles all of what we're about to do, and it does it elegantly, but I kind of want to do it myself. I don't think I need another library just yet. I might change my mind soon, however. So let's get to it! Today, we're going to pick up the speed a bit. I won't cover concepts that we already know. Instead, I'll push past the basics of creating Models, Collections, and Views, in favor of working with our router. I'll layer in orchestration, navigation, and state, and I'll handle it with the router. Finally, I'll try to walk the line between building technical debt versus a noodling on abstraction. We're working with some high concept stuff, and there is more than one way of doing what's needed, to be sure. So at the end of today's episode, you'll have a lot to think about, as will I. Let's get to it. Adding in a Router So I've added a bunch of things, and let's get you caught up. First, I added in collections.js. These are Mongo collections, not Backbone, and with a snap of my fingers, KABOOM, you can see the code that I've added in. Now I won't drag you through all of this again. We've already covered these concepts, and you know what these things are. I created the same set of Views, and Layouts, and ItemViews, and ListViews that I did for databases, because I'm doing the exact same thing. I'm just showing a list of Mongo collections. Next, I have refactored out an ItemView, because before we were just using a regular old Backbone View, but that would result in code duplication because we would have two remove routines, and so I wanted to refactor that out so we can put remove on the base class. And there you go, and that means that I can now go over to our databases file, and I can change the Congo.View to Congo.ItemView, and then I can take out the removeDb function because that has now been abstracted into our ItemView. (Typing) So let's make sure everything works. This is a key with Backbone. Go slowly. Take small steps. And I click on Delete, and yep, there is our new message. Let's go ahead and add a new DB in, and make sure our new dialog works, and it does. And we'll Delete that back out. We are good to go. But, if we click on a database link, well nothing happens. Let's wire that up. What we want to see is a list of Mongo collections for that database. And once again I'll write code for the click of a link that is in our ItemView here. So, what this will do is every time someone clicks on a database name, it's going to fire a function. I'll name that function showDb. And then we'll add that function down below here. Now the question is, what am I going to do when that thing is fired? Well the first thing is, of course, I want to pass in the event, because the last thing we want is for the anchor tag to behave as an anchor tag. We want to prevent the default click from happening, because that's just going to throw a pound up in the URL, and then the whole page will Refresh. The next thing I'm going to want to do is pull out the database name. I have put that in a data tag, an HTML data attribute, and I've named it db. So assuming that we get the DB name out, what do we do next? How do we get to show the collections? Well, step one is to have something to show. Heading over to index.jade, I have added a bunch of templates in, and these are basically just flat duplicates of what I had before for databases. As you can see, I have db details, and then new db template, and then I also have a new collection template of collection details, and so on, and they are literally just copies. Now, of course, you could call this a bit of a smell, as having duplication is something we've been trying to avoid. But I think we're going to end up customizing the user interface a lot in the future. So, for now, I'll leave it the way it is. Okay, so where does that put us? Refreshing the page, clicking the link, nothing happens. And this is sort of what we would expect. We've just wired the click event, but we haven't told our application to actually do anything. So that is our next step. And I'll head over to index.js, and this is where I'm going to create my router. Router is sort of an application-level concern. Where you put it, well, it's up to you. Typically, I will put it in the global app file, because I feel, as I said before, it's kind of a global application concern. To create the router, you simply do Backbone.Router.extend, which is what you've seen before, and low and behold, there's an initialize event. Again, you've seen this before. So the router's sole purpose in life is to respond to URL links, and to also navigate the application. So for that, we're going to need a set of routes. And this is just an object literal that we're going to specify here, and the default route is an empty string. And when you have a default route, you have to give it, well, a default function to navigate to, so let's create that function and we'll call it index. You can call yours home, or if you want to be purpose driven, call it whatever you like. So the index function is going to do a simple thing. In here, I'll just do console.log and "The index route!" If I've done everything right, this thing should fire immediately whenever we Refresh the page. So up in our init function, let's start off by initializing the router. Just as we've done before, I'll tack it onto the Congo object namespace, and then I'll just say new Congo.Router. There's nothing I need to pass in. Well that's it. Let's go play with this thing! Let's go Refresh the page. And now, just in the console here, say Congo.router. Let's take a look at what we got. A little letter d. We've come to see that before. It says you've got a Backbone object. So, I'll raise this thing up so we can see a little bit better, and I'll use the method that you're probably going to use most on the router, navigate, and I'll just put in blah. And if I hit Return, undefined, nothing, again. There's also an overload we can pass in there. It's just a boolean, and again, undefined. What's going on? We have a router. It's not working. This is a gotcha with Backbone. I hate to say it. If you don't instantiate the history API, well then the router won't work. Well, you might be saying, what the heck is a history API. I'll talk about that in just a second. So we have to start up the history so we can record where we've been and what we're doing in the app, Backbone.history.start. This is going to allow us to use the Back button, Forward button to move around the application. So once we start recording, if you will, now we can use the router. And look at that! The index route! BOOM! Things are starting to work. Let's navigate somewhere, Congo.router.navigate, and then I'll say BOOM, and look at that. Up top there, you can see we have BOOM tacked onto our URL with a hash-bang. That's interesting, but we don't have any way of handling BOOM, until now. So when they navigate to BOOM, let's goBoom and see how this whole thing works. We'll give it a function. So the router is going to respond to this route by firing goBoom, and for how we'll just do an alert box just so we can see how this whole thing works. Heading back to the page, we'll start again at the root. We're at the index route. Now we're going to navigate over to BOOM, and let's give it a shot here. Ergh. Undefined. Nothing. But our URL changed! How confusing is that? If you answered very, you'd be right. Routers are confusing beasts. Let's go back though, and you can see that we have retained history, and that we can go backwards and everything is fine, and we're back at the index route. So the Back button works, the index route got fired. What are we doing wrong? Well the answer is, we forgot to pass the boolean argument true when we use navigate. If you do that, that means yes, go ahead and fire the function associated with this route. If we Refresh, it gets fired automatically for us, BOOM. Is that confusing? Well it confused me the first time I started playing with it, so let's look at it again. We're going to navigate to BOOM, and we're going to say true, yes, go ahead and fire the function associated with this route. And it does! But if we don't pass true, then that function won't be fired, and believe it or not, there are times that you're going to want this. When we Refresh and come back in, well, this is first time that we're coming into this route, as far as our app is concerned, so by default the router will fire that action that is associated with the route. Welcome to stateful programming on the web. If that doesn't make much sense, well let's dive into it a little bit more. How do we know when things are firing? How do we know when the page is loading? What's going on here? So let's Refresh the page. I've tacked in a PAGE IS LOADED console log for whenever the page is loaded. That's fired by jQuery. And notice that when I navigate, the page doesn't reload itself, DOM doesn't load itself, so everything is fine. When I use navigate and pass in true, the function associated with the route is fired, but the page is not reloaded. In other words, the DOM is left as it is. Now if I just do a straight Refresh, well, as you can imagine, the DOM is loaded, and the route is honored. If you had trouble following any of that, I really suggest you rewind a little bit, watch it all over again. Routes can be confusing to be sure. We'll be playing with the router enough today that hopefully, after a little repetition, if it's confusing to you, it'll all start to make sense. So we're going to treat the router as a bit of a controller. The first thing, of course, I want to do is remove some of the mess that I just put in for the demo. And instead of using our global application object to do things, now that I have a controller, if you will, I can use the index action to start showing all the databases. I'll also take a second to move some things around. Before, our Congo global app, if you will, was responsible for doing a little bit more than it should. Really, it should just do some initialization, and have some basic settings attached to it. Now, we're separating things out a bit, and we're embracing our router as a bit of a controller. Here in our start function we're going to start off by initializing things, and then finally we're going to start the history. That starts to make a lot more sense. Now, I could put Congo.init in the initialization of the router, but that's a little bit backwards. I'd rather have my global app object tell the router what to do. That's an architectural decision, and we're going to talk more about that in the coming episodes. Okay, well let's now wire things up so when the route is clicked that we show a database. Our route is going to be :db, and colon anything means this is a parameter. And when that route is matched, the showDatabase function will get fired. So what I'll do is I'll just log something out to the console and say that this database was selected. But which database are we talking about? Well, when the parameter is matched, in this case :db, that parameter is passed into whatever function is handling that route. In this case, it's just going to be a single value that we have labeled db. And so we can be sure that everything works out, I am just going to log that out to the console. Let's go back into our databases.js file. We now know what we need to do. We need to tell the router to navigate whenever that event is fired, the click of a link. But where we going to navigate to? How does this work? Let's take a look at our route again. It's just expecting a single entry, a db, a database name. The default route is empty. That's the root of our app. If we pass anything in there, well that's going to be a single parameter, and it's just going to be the name of the db, DbName. So let's take a look at how this might work. I'll Refresh the page, and click a link, and it kind of works. Our URL changed, but where's the console log message? Oh, right. I forgot to make sure that that function fires. It's another little gotcha from Backbone. Oh, geesh. So let's Refresh, click it again. Hey look at that, database selected. That's what we want to see. Baby steps. That's what it's all about. One thing at a time, go slow, make sure it works. Alright, as I mentioned, I'm going to treat our router as a bit of a controller. For smaller apps like this one, that idea works just fine. So I'm going to move the body of showDatabases off of our app, down into our controller. This is, well, orchestration if you will, and that's what a controller's supposed to do. And given that I'm going to be doing just about the same thing to show Mongo collections, I'm going to move that entire method body up into showDatabase. Inside here, I'm just going to change a few variable names, so we have a collectionLayout, and it's going to instantiate a brand new collectionLayout that I've made previously. I showed you that in the very beginning. Its right over here in collections.js, here's our CollectionLayoutView, and our OptionView, our ListView, this is all the same stuff you saw before with the database work that we've done. And I'll go in here and I'll change our collection to be, hmm, I haven't really created anything that we can work with. Well, I'll call it currentCollection, because that indicates that it has been selected, and I'll deal with that in just a second. Next up, we just need to tell the Layout to render, and then finally stick the element of the Layout into details. And then of course, since we're doing a transition, that details needs to be emptied out straightaway. So let's do the same above and below. We have to empty out the details element so we can append something in so it doesn't get doubled up. And then finally, we'll kick it off calling fetch on the collection. Well, alright, I'm kind of doing things in bits and pieces, and I'm sort of throwing stuff against the wall. Let's have some organization to all this. This is what init function is all about. It's initializing all of the things we're going to need for our application to work, including Layouts, bits of data, and well, different Views. So let's figure out what this current collection is going to be. I want it to be a brand new MongoCollection collection, yes, that's a hard thing to name. If we head back over to collections.js, well you can see I just made it plural. Again, these are exactly the same setup as the Mongo database stuff I did before. So, I'll just set this to be a brand new MongoCollections. And then I'll do the same thing for databases that you saw me do before. I'll put the Layout here, and we'll call it Congo.dbLayout. Finally, just need to be sure that our namespace is applied to our variables down below. This code is kind of looking repetitive isn't it? Well, I might have to take care of that in just a minute, but first, baby steps. Let's go back, Refresh our page, and it lays out. Good. And we click the link, and well, we're almost there. There're no collections. And taking a look at our OptionView for adding a collection, well that's there, so that's a good thing. But now I want to go backwards, and how do I do that? I could hit the Back arrow, but, well that's what this breadcrumb thing is there for, and it just pops a silly thing, so, bleh. The App Layout and Reducing Duplication Okay, well before we do anything else, I can't stand this duplication, so let's address that now. I mentioned in the previous episodes that I would be introducing the concept of an AppLayout, a governing view, if you will, that contains all other Views in the application, and that seems to have presented itself to us right now. And we don't need to do anything fancy in here, really. We know that our application consists of two Regions, or two Layout Regions, if you will. We have Navigation, with our breadcrumb View, and then we also have Details. So I'm going to be explicit about this. Our AppLayout actually doesn't need to do much other than render the Navigator, and render the Details, and help us get rid of some duplicated code that is now in our router. So I'll just Paste that code in here, and let's see what we can do. So the first thing I'll do is get rid of the hard reference here to Congo.collectionLayout. We can probably pass that in as an argument. But we need to have a place to put that, and I want to be able to specify the region in which these layouts are supposed to be rendered. And right now that is, well, #details, so let's handle that in initialization. So I come up, and in our init function, where everything is supposed to be initialized, I will initialize our AppLayout. First thing I'll do is I'll tell it which element to append itself to. I really don't know if I need to do this. I could go by convention, and just say the AppLayout should always use #app, but this works out okay. Then I'm going to tell its detailRegion is #details, and we can now use this in our AppLayout removing this hardcoded reference to #details in our AppLayout. And the way we reference that is by saying this.options.detailRegion. But what the heck is that? When you pass information into a Backbone construct, like a Model, View, or a Collection, it gets tacked on to the options object that every Backbone construct has. So, in our case here, I told our view what detailRegion it belongs to. To access that information, I have to use this.options. This can be really confusing, because you've seen this structure before, but we were using it in a different way. Let's take a look at what I mean. This is the code for our DatabaseLayoutView, and if you notice in here, we're adding ad hoc things like regions, and databaseList, databaseOptions, and so on, and later on in the code, we're referencing that without having to use the options variable at all. What's the difference? Well, in this code here, these are Settings. Notice that we are just declaring what a DatabaseLayoutView is, we're not instantiate a new one. With our AppLayout, however, this is an instantiation, and we're passing options in. We're using a built-in option, el, and we're also specifying one of our own, detailRegion, which again we need to access from this.options. If this isn't very clear to you, that's okay, as I keep saying, we're going to keep doing this over and over again, but it's important that you understand the difference, because they look so much the same. Okay, well let's go back and finish up our render details function. I will use the same accessor here, this.options.detailRegion. I'll empty it out, and then I'm going to append something, and that something is going to be the detailView that I pass in as an argument. Final step is to call render on our detailView. Looks simple enough. Let's clean this thing up a bit. Very nice. Alright, let's see if it works. I can strip out all this unneeded code, which makes me happy. I'll just comment that out taking small steps, making sure I can go backwards. Now, I can just say Congo.appLayout.renderDetails, and then I'll pass in the dbLayout. I think that reads pretty well, don't you? Let's make sure it works. Go back to our browser, Reload, and look at that! That worked pretty good. So let's strip out our commented code, and I will Copy what we did here, and then I'll head back up to showDatabase. This is starting to look more and more like a nice, clean controller, that's what I want to see. And then we'll say render the details, and use our collectionLayout. Let's Refresh, and we'll click on our Shlonk database, and, well, we're almost there. This collection should be showing up, but they're not. Well, why not? Let's head over to our collections.js, and in here, well there's our problem. In order for our collection to load itself, it needs to understand what the current database is, and we're not setting that anywhere. Where do you think would be a good place to set that? Logically, put it in the controller. So, we just need to say Congo.currentDatabase, and we'll set it to db. I really don't like using global settings like this, but, well, as you can see, it works! It's not so bad, but I'll make a mental note, this might be something I want to clean up later on. Let's go and make sure that our collections work as we expect them to. After all, we basically just copied and pasted everything from databases, and yay, we're able to add a collection in, Refresh it, and it's there, and look at our URL is routing as we expect. We Delete that. We have state, if you will, sort of a state, and yeah, so collections work. And, yecch, our breadcrumb navigation does not, and well, I'll be honest, this is where things start to get a little complicated. I'm not really looking forward to this. So our breadcrumb navigation has to basically cycle itself with where we are in the application. Right now, we are simplistically rendering the thing when it's initialized. But, that's not really what we want to do, because this thing is now governed by our AppLayout. And, well, so what we should probably do is pass this thing in, and say our navigatorView is Congo.breadcrumbs, so our AppLayout knows what to do with it. But as we start to solve this problem, things just kind of stop making sense. I find that when you're inner dialog starts going off, and you're looking at something, and it doesn't feel right, test it out, make sure it works. Sometimes that's just the way you got to do it. Other times, there's probably a better way. So let's run this whole thing through. Basically, I'm just moving things around here. I'm sweeping things under the rug, if you will. I'm simply telling the navigator now to render on the initialize of the AppLayout. That sort of makes sense. It's a global navigator. It's always going to be there, so why not? Let's make sure this works. I'll still pass in the el, that's kind of what I needed to do. I'll go Refresh this, and it works, but, as I mentioned, I'm just not happy with it. So let's keep going. I'll build out our breadcrumb View. Right now, it's not doing anything, which makes sense. So, the breadcrumb is going to change based on what we're looking at, and what route we're using. So, I'll devote the render function to render specifically for each route. So renderIndex, well that should just show a list. It shouldn't be linkable, because we're already on the index page. So I want to show that thing straightaway, and ooh, I can just use initialize, and renderIndex. No, this does not feel right, because we can initialize the breadcrumb View from just about any URL. Rendering Index by default, that breaks. This whole thing is starting to collapse in on itself, but I'm glad we saw it through. Now, I want to do something completely different. And if you remember, Rob's golden rule of Backbone, Views react. We're not really reacting to anything here, but we can. We can react to changes on the router, specifically which route is fired. We just have to specify a route:, and if we switch back over to our router, you can see we have two routes the find, index, and showDatabase. So, we can say, whenever the index route is fired, we want to renderIndex. We want that function to be called. Also, as a side note, it's good to be in the habit of passing context along whenever you fire events like this. In this case, we'll just pass this, so the context is retained. Alright. Let's go back to our page and Refresh, and nothing. This happens a lot with Backbone. Well, let's put our debugging hats on. Let's see what is being fired and what's not. For this, I'll just use some simple console.log, and let's make sure that the index route is indeed being fired. So, I'll Refresh this. Yep, there it is. So, we know that the index route is being fired. Of course it is, because everything is showing up as we intend, except for our breadcrumbs. What's going on with that? Well that tells us that it's likely something to do with our event getting picked up, so let's go down to renderIndex and see if that's being fired. And, I'll save this, and I'll give us a better prompt, and I'll Refresh. Ahh, nothing. It's not being fired, which means our wire up is probably, d'oh, I can't spell, that's the problem. Now, it's worth it to go through a nice debug exercise anyway. Refreshing this, and look at that, we have got breadcrumb! That's exciting. Had I gone a little bit slower, and tested things out along the way, using baby steps, I might not have gotten bit by that. Okay. Let's clean this thing up, and have it show a database when a database is selected. So, now I can do renderDatabase as a standalone function here. And I can basically just Copy and Paste some code above, and create a new route for which route? Let's go back over, and the showDatabase route, that's the one I'm most interested in. When that route fires, I will have our renderDatabase function fire. And here's a neat thing, the route information is also going to be passed in. Whatever parameters that you specified in the route, well those will be passed along to any event handlers that you wire up. And finally, I'll output some HTML. I could use a template for this. Since I am just writing stuff in line like this is much easier, especially if you only have one or two lines, and this will work fine for us right now. If it gets crazy, I'll change it later on. Alright, let's comment out our event, and I don't want to hook up the event just yet, I just want to make sure everything's laying out. Again, I want to take baby steps. Yes! And the layout is working as we would expect. However, clicking on DATABASES, that's just a regular old live link. It takes us back to the home page, and well messes things up. We want to intercept that click, so let's go back and wire up an event. And looking at this, well, we're just handling the click of a link. Let's be a little bit more specific. We'll throw an id in here, and I'll call it summary. It's going to take us back to this summary, or index page. And I'll handle that down below, and then call navIndex. What's navIndex going to do? Well, you've probably guessed already. We simply need to tell the router to navigate us back to the index route, and we do that passing in empty string, because that is the matter that the router is looking for. Finally, let's prevent the default click action from moving the browser around. We do not want that, so I'll Refresh it. Let's pick a DATABASE, and, oh boy, that looks like a big fat mess. I've got things rendering everywhere. Oh boy. I think I broke my rule about baby steps. Well the first thing, take a look at that. Our breadcrumb is double rendering, and that usually means you forgot to empty an element, and I sure did. So let's Refresh that and see if we can fix that problem first. Clicking on a link, and clicking Back, yep, we empty out the element, reappend DATABASES in there, and we're good to go, but what about the rest of this stuff? Well, let's use our trusty console to see if it can help us figure out what's going on. So we know that our dbLayout looks pretty bad. Dropping it open, ew, we've got a double render, looks like a double render problem there. The same thing is being rendered twice. That's not good. Inside of here, we have our list, and we have our options, and inside options, that looks okay, I guess. No, that's double rendering, and that's not good. You can see there're two forms in there, and there're two tables that contain the lists of our databases. Usually when you see a doubled up thing like this, well, it's usually because you forgot to empty a layout, just like I did before. And looking at the render function of our Congo.Layout base class, indeed, we are not emptying that thing out. I'm not sure how that code escaped my eyes, but yes, calling myself a toad, it usually works, and we should be able to solve this problem by saying this.$el.empty. And what a silly error. Almost had a good demo there, almost! And we click Back. We have breadcrumb navigation. It looks pretty good if I do say so myself. Well that brings us to the end of this episode, but before I let you go, I'm going to assign you some homework. Let's head over to our nav.js file here, and take a look at what we've done. And it works, which is good. But is it elegant? Is it the right way of doing things? I don't know if there's a right answer here, but I do know that I just wired up a View to listen to events on a thing that I'm calling a controller. If we're adhering to MVC, that is a pretty big no-no. Now working code is working code, and that's something we have to pay attention to. However, in the long run, as complexity grows in this application, will what we've written here scale? That's your homework assignment. I know of at least one or two different ways to handle navigation, but I'd like to play a little game of what if. Let's say Derick Bailey comes in, takes over as a senior project manager of our Mongo Explorer, and says, I hate routers! Get that thing out of here. I want you to write a different way. That's your assignment, deal with Derick. How would you rewrite this? What problems do you think you'd run into? That's what we're going to tackle in the next episode, and I'm very interested to see what you come up with. Thanks for watching. Talk to you then. Going Around Backbone, Part 1 Introduction and Adding in Mongo Documents-Dev Speed At some point when working with any framework, you find the edges of what it can and can't handle. In this episode, I'll pick up the pace, and I'll cover familiar ground once again. I think repetition is a good thing, as it gets your eyes familiar with the process of working with a tool, or a framework, like we are with Backbone. So rather than listen to me drone on, I invite you to watch the code come together at dev speed, if you will. See if you can follow along with the process of adding in the concept of a Mongo document, where we add a List, Detail, and Layout, Collection, Model, and so on, just as we've done before, but this time a little bit faster, and a little less talking. We'll transition to working with the Ace Text Editor. It's the perfect fit for what we need, but unfortunately, it's also rather demanding of where, and how it's rendered. My goal today is simple. Accommodate this editor, and just get it to show up. I tried for hours to get it to render properly inside of a Backbone View, and all I can tell you is that it just wouldn't! I thought it might be interesting to find out why. There's no errors, no logs, no nothing. But I decided I didn't want to derail our process entirely here by focusing on the editor. This is the Backbone production, not the Ace Editor production. I'd just rather get the thing to work! So, I decided to go around Backbone entirely in an effort to get this thing out onto the page. In part two, next week, I'll focus a bit more on interacting with the Ace Editor, and our Backbone Models and Views. For now, let's just see if we can make it show up. (Typing) Editing Documents with the Ace Editor Well, to drop in Ace, it's pretty simple. Created a directory called ace inside JavaScripts, and I dropped in a few files in there. The ones that we're mostly interested in are the ace.js file, and the mode-json. You'll see why those things are important in just a bit. For now, well, you'd think I'd be able to come over and create a new template in which to drop our Ace Editor. I mean, it really should just be a nice WYSIWYG code editor, everybody's seen this thing in action. Ah, well, wouldn't it be fun if it worked that way? Ideally, inside of our editor template script tag here, I could just say something like, oh, I want the editor to show up right here in side of our editor id div tag, and I want it to just span the entire width of the document. Well, let me just tell you right now, it doesn't work that way. The Ace Editor, unfortunately highjacks your DOM, and unfortunately for us, that means that it doesn't play very well with Backbone. I'm getting a bit too far ahead of myself. Right now, let's just know that we've added Ace in, and we've added the JSON mode in. We've Refreshed. We have no errors. Everything is loading right. It's all good. So let's keep going and plug this thing in. I have a simple goal, which is when you click on the link in the DocumentView that you can see the editor pop up. So that's what my show function is all about here. You click on the link to a given document, and it's going to hopefully navigate us over to that document, so then we can see the editor. We just want to put the JSON for that document into the editor. But I don't even want to go that far! I just want to see the editor pop up. Seriously, that's all I want. I want you to trust me and now that that took me a couple hours as I was preparing this demo, just to get the editor to show. It was not a fun process. But now let's take our baby steps, as I show you how to do this. Got to make sure we got the right route. I'm logging it out to the console. Baby steps. It's working nicely. And I'll just tell the app to navigate off to our URL that is now going to include our id for our document. Over here in our router, well, as you probably have guessed, I just need to create a route that is going to pick this thing up. And it's going to take a db parameter, collection parameter, and then a parameter to hold the id, and I'll call a function called showEditor. And just like before, I will have to set the state of the application, setting the currentDatabase, selectedCollection, and a new variable now, selectedDocumentId. The reason I have to do this for every single route, because I don't know if they're coming in from a URL, or if they're being navigated from inside the application. So I have to set the state every time a route function is called. Alright. Well, you're just going to have trust me when I tell you that the Ace Editor does not like to be rendered inside of a dynamic element. I have tried and tried. So, what I need to do is to go around the Backbone abstraction entirely. Sometimes it just happens that way, and you got to roll with the punches. So here, I have created a div that is going to hold our editor, inside it's going to hold the editor options, like Save and Delete, as well as the Ace Editor itself. I wish I could put it inside details, but unfortunately I can't, and here it is, showing up below, and since it's not governed by our details layoutView, ergh, we're going to have to manage things. But that's okay. Let's go back down to our Application Layout. We want to deal with editor explicitly, and hey, that's why we have an AppLayout so it can handle all this stuff. So, let's start with the simplest thing. Want to take baby steps again. Want to make sure that this thing is hidden every time the details gets rendered. So I'll just do this manually right here, right now. There we go. So that's hidden, and that's good. And if I click on our link, hurrah! Our URL is showing up as it should with the id of the document in the URL. Great! Alright, well let's go back and deal with this AppLayout. I clearly don't want to be talking directly to the jQuery selector like that. I also want to have a very specific render method for rendering the editor, and in there I will need to hide the details view, and then show the editor view. Typical toggling back and forth that you do in a Backbone application. I wish it didn't have to be so manual, but as I said, I have to work this way because the Ace Editor doesn't want to play friendly with me. Alright, well let's create a function called hideEverything. That would be the easiest thing. I'll just hideEverything on the page, and then each one of these functions will render what it needs to, when it needs to. It'll just call, they will each call hideEverything to make sure it's all masked. I also want to work with a notion of an editorRegion, and have that explicitly set when I set up my AppLayout, so I'll just follow what I did for details, and I'll just set this thing to be #editor, and so that means back inside of our base class here I can refer to this directly without having to use jQuery selectors in my code, which makes me happy. And now to render out the editor, well, I'll just drop in some code that I got from the Ace Editor site. You just have to tell Ace what div you want it to render in. In this case, its ace-editor. And we're going to set the editor to a variable, and then we're going to make sure it's using JSON mode, because that's what we're going to be working in. When you set the value, it gets automatically selected, so the very last line of code there, I want to clear that selection. Speaking of setting values, what is the value we're going to be working with? Well the Ace Editor is simply a text editor. And if you thing about what it is we're doing, we're going to be getting a document coming back to us from Mongo, and that is going to be in JSON format. So, we're going to have to do a little bit of a stringify action, because we want to turn that document into a string so we can show it into the editor. So, what I'll do is I'll just pass a value into the renderEditor function here, and then I'll use JSON.stringify with some formatting options passed to it. This is going to turn whatever object we send into this editor, into a big old blob of formatted JSON that's a string that we can show straightway. Alright, let's take a look at where we are. We'll Refresh this, click on Users, and then click on our document, and goody, we have a URL, which is what we want, and there are no errors, which is good. And it looks like our hide routine is working as intended. Okay, that means we get to take another baby step. Wish I could work with Backbone and have Views react like I keep telling you is the golden rule. Unfortunately, right now we have to take this step, which is tell the editor to render itself directly. The last thing I need to do here is to tell the editor what to display, and I'll just pass in a simple object with a message that says, Hello! I'll set this to work with a document data in the next show. Okay, let's click this thing, and look at that! Yay! We have our Ace Editor working and displaying properly. Believe me, I'm saving you from some pain that I had to go through to get this to work right. I still don't know what the problem is, otherwise, I'd share it with you, but the whole show is not about the Ace Editor, so, I figured I'd save you from the pain. Well, let's go back into nav.js. Let's make it so that we can see the navigation, and we know where we are. Right now it's not even displaying, because it's not reacting to our routes. The first thing we need to do is to wire up our showEditor route, and then, can you guess what I'm going to do now? That's right, I'm going to Copy and Paste, and format this thing, and rename it, again, stuff you've seen me do before. And as I'm looking at this, I'm really wishing there was a better way to do it, because that is a lot of HTML that is consigned to being hardcoded in our function here. I don't really like it. Maybe I'll talk to Derick Bailey, he can set me straight. Okay, there it is. It seems reasonably formatted, and it's doing the job, and I've also added some data tags so that I can decipher the route when the whole thing is clicked. Okay, next thing I need to do is create the nav function here, so I can navigate back to the collection from the selected document. Again, this stuff is the same pattern that I followed before. We're going to prevent the default. We're going to pull out the name of the database, and the collection from the HTML5 data tags so we can use them to build our route. Alright, well let's set the click event of the collection details tag to navCollection, and we should be pretty good to go here. Double checking our showEditor, calling renderEditor, and now Refresh. Yay! Look at that, we have navigation straight down to the document level, clicking users, clicking the database, clicking the collections, and the document itself. Ohhh boy, Save and Delete aren't hooked up yet, but we can do that in the next show. This is looking pretty good so far. Now I just need to figure out how to get this editor to play nicely with Mongo DB. You'll find this kind of thing happens a lot where you have to go outside the Backbone abstraction to get your application to work friendly with another library. The downside to that is some of those other libraries, like the Ace Editor, will really dominant the DOM. It will dominate the events, and a bunch of other things, and just impose themselves on your code, which unfortunately, is what happened to me here. Which I don't really think is that bad of a thing actually. You can't really work with an abstraction, or any kind of framework, without having to go around it from time to time. Some frameworks make it easy, others don't. I hope you've seen that Backbone sort of made it easy to go around it, and help us deal with this Ace Code Editor, and, well, we didn't really have too many problems. We're going to continue down this path in the next episode when I have to plug in the document that I get back from the database, and show it here in the editor, and Save it back up, and even Delete it, so that's coming next time. Thanks so much for watching. I hope you enjoyed it. Going Around Backbone, Part 2 Cleaning Up: Paying Down Some Technical Debt Today we're picking up where we left off last time, working with the Ace Text Editor in an effort to get it to play nicely with our app. I mentioned in the last episode that I tried everything to get it to work within the Backbone structure, but it just wasn't possible. Well, I've since found a way to do it, and although it's not technically within the Backbone structure, I've made the Ace Text Editor work, well as closely with our application as I think is possible. Finally, I don't want to dig myself into a nasty hole with regards to technical debt, so I'll clean things up a bit as I go along. This is the last episode before we push everything into Marionette.js with Derick Bailey, and I don't want to make Derick mad. First thing I want to do today is to pay off some technical debt. One thing I know that is if I keep on coding this application in the style that I've been doing, well pretty soon all this crappy code is going to, well, it's going to pile up on me. So let's refactor our navigation stuff. Our breadcrumbs are fine. I hate all this HTML that is embedded in the code, and I can clean that up with some code. Now it's been suggested to me that I could just use templates, using the underscore templating library, but I'll tell you what, all those script tags on my View page, it's starting to get to me. I'm not a big fan of it. In this case, it's really simple stuff that I'm doing. I have a couple of listItem tags, some span tags, I can do this programmatically quite simply. So I have three methods now, Crumb, CrumbWithLink, and Separator, and they're just going to output this stuff for me. You can see its working just fine. But I want to keep going because I have a ton of repetition, and I hate repetition. It's really good to pay off the technical debt when you can. In this case, it's just some simple refactoring. So, I have a specific need where I need to show some links. Number one, I need to show home link. So, I want to show the word databases that will link back to the list of DATABASES. I need to show collections, and I also need to show individual documents. So, let's be explicit about it. I can use my refactored stuff here, and now I can just say showHomeLink, and showHomeLink is simply going to append a crumb with a link to the DOM. There we go! So, well, I've decided to spell DATABASES right. And making sure that this all works. It does! That's good. So we can keep on going here. I have showHomeLink, showDbLink, and showCollectionLink. These are going to take the repetition out of the code down below, and that makes me happy. So using the power of video editing, let's just fast forward into the future, and now you can see how this has tidied up a lot. I'm sure that if I sat and thought about this long enough, I could probably come up with a better breadcrumbing system, but as I mentioned, this is working. It's not repetitive. Refresh, take this thing for a spin. I click on the links, and make sure that the navigation is showing up as it should be, and it is. I can click the links, move around the application. That is all I ask, and it's good, and it's working. The next thing I want to take care of is I have these Congo.Router.Navigate calls sort of spread out throughout the application, and I'd rather have it be explicit. So let's take them out of here. I'm going to put them on index.js in our Congo application itself. My goal here is to centralize how the application, well, moves between state. Since we're invoking the router, and we're firing the routes, that is essentially changing the state of the application. Having said that sentence, it seems to make more sense to put this on the application object itself. I can also take the additional step of accounting for when a database, or collection is not specified in navigation. It's logical to assume that if someone wants to navigate to a database, well if they haven't specified which one, well, then we're going to go to the currently selected database. Same with a collection, so I can account for that here. This is going to free up a lot of code. So, heading back over to nav.js, I can take out all the dbName, the collectionName stuff, just remove it from each one of these methods, and simply call the counterpart on our Congo object, Congo.navHome, and Congo.navDatabase, which, you know, is always going to be the currently selected database, so I can just leave this empty. And then I can do the same for collection, Congo.navCollection. Once again, I don't need to specify the database, and I also don't need to figure out which collection, because this is always going to be the currently selected collection, because if the link is visible, we're just going backwards, which means the user has already selected the collection they're interested in. Sure enough, giving this thing a test run, it works pretty well. Getting the Ace Editor to Work Better So we've paid down a little technical debt. Let's go and see if we can tackle the next bit, which is this editor code. I mentioned in the last episode that I couldn't get this editor to work nicely with Backbone. I have since found a way, and I'm happy about it, sort of. To start things off, I'm going to create an editor template, and this is just going to be a basic underscore template that I am going to pop some code in here. So let's just Copy and Paste from our editor tag, and I'll drop it down below here inside of our script tag. Still planning on rendering the editor to the Ace Editor div tag here, but I want to use the Backbone mechanisms to do it. I'm going to go really slowly, so let's refactor this step by step. So step one, I removed the Ace Editor markup from the DOM, and I put it inside of a template. I'm calling it directly from the renderEditor method on AppLayout. Let's see what breaks, and BOOM. Cannot read property env of null. This is what happens when Ace can't find the div tag that you've told it to render in. In our case, it's the Ace Editor div tag. So let's go and create a View. We need to have a place for this editor to be rendered to, so inside of document.js, I will create a new View called Congo.EditorView, and this is going to extend our basic Congo View. We know that we need to push the Ace Editor div tag into the DOM before we ask Ace to render itself. So, let's concentrate on the render function straightaway. Inside the render function, we know that we need to at least create the editor. So that's what I'm going to do. I will Copy and Paste from base.js. I'll Copy and Paste this editor code, and tell it that we want it to live in the Ace Editor DOM element. I'm going to set this thing globally, because I know I'm going to need to work with the editor later on, so I'll just set it to be Congo.Editor. That'll be our reference to the Ace Editor. For right now, because we don't have a layout, I am just simply going to call render on initialize, because I need this thing jammed into the DOM. So we've made some small changes. Let's go see if we have broken anything, and indeed we have. Div element has no method setValue. Hmm. Well setValue's being called from here, I'm not sure why it thinks it's a div element. But that makes sense. There is no editor, so we need to account for that. SetValue is in place because we need to load the editor up with some text whenever we select a model. We can't load the EditorView in the same way that we've been doing in the past. We actually have to do it explicitly whenever we have a model value. This is because the Ace Editor doesn't like working within the Backbone Framework, it needs to be in the DOM, or otherwise it's just not going to show up. So, I'm going to create a setModel function here that we can call from elsewhere. That setModel function is simply going to take in a model. It's going to turn it into JSON, and that's going to be a JSON string, and then we can set the value of the editor to that JSON string to show up properly. If you're confused right now, hold tight. Hopefully this will become clear rather soon. Okay, so we have a setModel function. Where we going to use that from? Well, inside the renderEditor method on the AppLayout, we can call this thing directly. And, we can pass our model in, which I am descriptively calling thing for right now. Right. We've taken a few more steps. Refresh. Got another error. That's okay. Can't call setModel is something that's undefined. Well, that's because we haven't defined our editorView. We've created the code for it, the declaration, but we haven't actually instantiated it. So let's instantiate that right here in index.js, in init, and see if that works. No. We still have a problem. Hmm. Let's go back over to documents.js. What is going on? We've got our editorView, and we're declaring a new editorView. And, oh geesh, can you see what the problem is? Once again, I can't spell. Okay, fixing that we'll Refresh, ooh boy, can't read property env of null. Sort of feels like we're going in circles here doesn't it. The problem is that Ace can't find the div tag to render to. Can you see what the problem is? Well, I keep saying that the Ace Editor requires the element that it's rendering to be in the DOM before it is rendered. It can't be a DOM element that is assigned to a variable. It has to actually be in the DOM, and live. Checking it with jQuery, well we can see Ace Editor is not in the DOM. Hmmm. So, wonder if I can fix that by doing return this? I don't know, just got to cover all the bases. Nope. The Ace Editor is not in the DOM. It's an empty tag there. To get around this, we are going to need to hardcode the element for the editorView to a DOM element that's already in the DOM. In our case, the editor tag that is already in the DOM. We left it there on index.jade. Not only that, but we are going to need to reach in to the template, which we haven't done yet, and pull out the template information for our editorView. These are two steps that we missed critically. So, we are going to pull the HTML from our editor template. We're going to compile it using underscore. And then we're going to append the compiled source to this.el and this.el is, do you remember? Well, we're passing it in. It's the editor div tag. That is in the DOM. And guess what? It worked! Believe me, I was pretty surprised to see this work. I had maintained steadfastly that this was not possible, but I took it step by step, made sure that I understood all the differences, and well, it worked. So let's make this thing look a little bit better. I'm going to update the CSS, and some of the HTML here so that this will look a little bit better. Refreshing. Yay! That looks a whole lot better. Now we have our editor in the DOM, part of a View, boy am I happy. But, you know what would make me happier? Reducing some more technical debt! Let's do it. In our router, we are repeating all over the place currentDatabase equal to db, Congo.selectedCollection equal to collections, selectedDocumentId, da-ta-da. Let's put this all in one place, and we'll create a function here called setState. Too much repetitive code, well, that is the easiest kind of technical debt to get yourself around. So, let's refactor this a little bit. I'll have a setState function here, and I'll just say if there is a db variable passed in, we'll set that to Congo.currentDatabase, and then we'll refactor out the code by just saying this.setState. Ah, much cleaner. I like this a lot.. Hooking Up the Real Document Data Okay. On to the next task. Right now we're just sending in an object that says Hello!, message Hello! It's not the document that we want to edit. So, let's make that happen. We know the id of the document. We just need to now go get it from the database, and the good news is that Backbone helps us with this, and makes things pretty easy. So I'll start by creating a brand new Congo.MongoDocument. And I'll pass in the id that was given to us by the route. If I set the id on my document, then I can use the fetch method that Backbone gives us. Fetch simply goes out to the server, and it refreshes the document with the information that the server has. The one condition, needs to have an id, and we've just set that. So I'll say document.fetch. It also takes some options here. You can set a success function, which I'm going to use, and it'll give you back a model, and the model itself, and the response. It also has an error function, but I'm not going to set that just yet. So, when the document comes back, I simply need to say, render the editor, and I'm going to pass in the model straightaway. It's important to keep in mind that this is a Backbone model. This isn't just an object that I can turn into JSON. So that means I need to go over to my editorView into the setModel method, and I need to be sure to call model.toJson because we're expecting a Backbone model to come in here. And let's Refresh. Ooh. Sort of. That's pretty good, but we got some weird JSON here. Do you see the problem? Have to admit this is an unexpected result, but I think the problem is that I used id instead of _id. Remember, that is our identifier for this model. Refreshing, and indeed, that was our problem. And now, we have a document that we can play with in our editor. How exciting. Adding Save and Delete But that's only the first part of a lot of stuff we need to do. Next thing I need to do is to hook up the Save button here, so, well, we can actually Save and make changes. So let's head back over to our document.js file, and I need to wire up an event for our Save button, and, if you recall, it is simply just an object literal, and we're going to say for the click of the save document button we want to call a method, and I'll just simply call this saveDocument. So let's go down and declare that method on our editorView. And this is where things get just a little bit tricky. Because what the editor's going to give us back is just a big old set of JSON. It's not necessarily a model that we've changed. It's just a bunch of text. So the first thing I'll do is I'll use editor.getValue. That is a method on Ace Editor, so that it will return all the text that is inside the editor. The next thing I want to do is to be sure to wrap this in a try/catch block. If there's any problems in the editor, if we have a JSON problem, for instance, that's going to throw an error when getValue is called, so I want to make sure to catch that, and just say something like, we have a JSON problem, fix it. Next thing I need to do is to parse the JSON that I've just pulled. Yech. I'm fighting with the editor, thanks for the IntelliSense, but sometimes it is such a pain. And we'll just call JSON.parse on the text of the editor that we've pulled in. Assuming that works, we are now able to create a brand new Mongo document that we can work with, and I can just pass the parsed object in. This is just a bit of JSON, and this is going to act as the initial setting for our newDocument. The neat thing about this is the id will be part of it. So the id will be set, and all the values that are in our editor will be passed automagically straight over to our brand new MongoDocument. Okay! Now we just need to call save. I could call save directly, but I want to use the callbacks here. I want to know if it was successful, or if there was an error. Specifically, if there's an error, I want to pop an alert, and say that there is some sort of problem on the server, and that I should probably check what's happening on the server in my logs. On success, well, I suppose we could just navigate back to the collection. There's a lot going on here. This signature is a little bit strange, to say the least. Let's find out what's happening with Save. The error I just dealt with, if we can call it an error, as basically nothing happened, might seem just a bit odd, so let's break it down. When saving a model, a fairly simple process is followed. The model sends an Ajax request to the server, which in turn should update the database. So far so good. When save is called, Backbone will do a few things before sending the data to the server. First, it tries to see if the model is valid. Something that we haven't talked too much about, but I'll go into in just a few seconds. Next, it looks to see if the model has an id. That's how it knows if the model is new, or requires an update. Finally, it sends off the Ajax request using the URL that we specified on the model. If you recall, when we created our document model, I specified what attribute Backbone should consider to be the identifier. And I also created a strange looking URL function. The URL changed according to whether the document was new. This is a common pattern that you see quite often in non-Rails applications, like ASP.NET MVC. With Rails applications, you really don't need any of this code. Backbone works rather seamlessly with the Rails REST style backend. Using other frameworks, like Node, or ASP.NET MVC, well, you kind of have to get in here and jack things around. Backbone allows you to have simple validations on the client, which many people, including myself choose not to use. The main reason is that anyone with a knowledge of the framework can easily override your validations, and hit the server with whatever information they want to, therefore your validations, well, they don't offer too much security. It's always best to validate things on the server anyway, which means that whatever you put in place on the client, well, it's probably going to be redundant. That said, let's take a look at how validations work. Validate is simply a function that Backbone will call if it exists on your model before it saves it. If nothing is returned, your model is valid. If something is returned, well that's considered the error, even if it's just a message string, like we have here. It used to be that only the changed attributes on your model would be passed into the validate method, and this is no longer the case. All attributes are passed to validate on save, so you can check the presence of an email, or, for instance, the numericality of a number. If you want to do simple validations, such as checking for numerics, and so on, Underscore has a great set of utility functions that will allow you to do just that. Taking a look at our save routine, we can't really benefit from our validations at all. Can you see why? Well, the main reason is that we have no idea what we're editing. These documents are Mongo documents that can have any shape and size. They represent objects that live in MongoDb, so validating, well, anything is beyond what we can do here. And now we come to this strange signature for the save routine. If we specify save without options, the attributes will be taken from our model, using the model.attributes field. We can also pass those values directly to save if we want, which is helpful if you're just trying to do partial updates. And that's what we're doing here with setting patch equal to true in the options. So, another way we could have written our code is above. And personally, I like the way that we did it the first time. To me, it seems a little bit more clear. We're passing the attributes to save because we want to take advantage of the success and error callbacks. Why? Because the call to the server is asynchronous, meaning that when we call save, JavaScript will go on its merry way and not wait for the execution to complete. This is the nature of JavaScript. If you need to know if the result was successful, you have to structure continuation routines as we're doing here. We can go further with this if we want. Backbone allows you to stop all the eventing on your model until the server has acknowledged the Ajax call. To understand that, let's take a look at the events that happen on save. Normally when saving a model, the first event that's fired, well, that's the change event. That's when you update the values on the model, so change is fired. That also fires a change event on the model's collection. Next comes the request event. This happens after save is called, and that's fired right when the Ajax request goes off to the server. And finally, we have the sync event. This happens when the server responds with a 200 response code, basically saying, everything's okay. So we can reverse this whole chain if we want by setting wait to true in the save options. This allows you to wait until the server says it's okay before the pass in attributes are assigned to the model. That means that sync will be fired first, and then change after all the attributes are then grafted onto your model. So the moral of this story, there are two ways to save a Backbone model, which you choose is up to you, and what you need. Oh, and also that validations can be useful, but not many people use them, at least not many that I've run into, and there are other frameworks that you can use if you really need to do hardcore validations. Alright, let's get back to the code. Okay, now that we have that going for us, let's see if it works. I hit Save. And hey, it navigated us back. That's a good sign. Let's click the document again, and I'll change the name, see if we can actually see something, and, yep, look it, there it is! The name has been updated. Well, that's a good thing, and it wasn't terribly difficult, which is exciting! It's why I wanted to put the editor in a View. We can use Backbone to work with it. Okay, moving right along. Let's wire up our addDocument button. Here, I'm simply going to navigate the application to a new document. But I can use the existing route to do that, because in the existing route, we're simply appending the id onto the end of the currentDatabase and selectedCollection. If the id is a string that says new, well I can account for that in the routes. All I got to do is replace the id parameter here with a nonparameterized word new. Great! And so that is going to go and fire a newDocument function sitting on our router. Inside here, I can do pretty much the same thing I did in the showEditor function. I can set the state to the db, and collection, and then finally, if I've done things right, I should be able to tell the AppLayout to just render the editor. But instead of passing a model in, I'll just keep it empty, because we don't have a model. This is a new document that we want. Okay, so I'll save this thing down. Let's see what happens. Heading back over and Refreshing. I can't call method to JSON if undefined. Well that makes sense. We don't have a model. Hmm. So what are we going to do? Well, the simplest thing to do is to assign the model for the View to be the passed in argument, or if the argument is undefined, well I'll just create a brand new Congo.MongoDocument. Seems to be pretty straightforward. I get two things out of this. I handle a null condition, but I'm also setting the model of the View which is going to come in handy later. And Refreshing. Almost. The editor's showing up empty, but we have no breadcrumbs. That's not good. Well, it's simply because we're not accounting for the route that is on our router. So I can accommodate that. I'll just create a new route corresponding to newDocument, which is the route that gets fired when we send in new. And then I will simply come down here and I'll Copy and Paste what we do for renderEditor, with finally adding the crumb new on the end. Alright. That's showing up. So let's see if we can add a document. I'll set the name of this to be something highly exciting, like Billy. I'll hit Save, and it shows up. We have a new document that we can now edit. And look it, there's our id from MongoDb. That's pretty neat. But our Delete button's not hooked up. You think this is going to be difficult? Well, let's find out. To delete the document, I'll need a brand new function in here to do just that. I'll be sure to add a confirmation dialog here, Delete this document? Are you sure? And then if they say Yes, then I can simply call this.model.destroy. This will destroy it on the server, and we'll also remove it from our collection. And then I'll just navigate back to the collection itself so we can see that it's gone. Seems simple enough. Finally, I just need to wire up the click event of our delete document button. It'll look exactly the same as the saveDocument one, except it's going to call a different function, just like that. Refreshing. Delete. Delete this document? Hey, look at that. We have a functioning MongoDocument editor. I don't know, I think this is pretty exciting; however, it's also rather temporary. Everything works, which is at it should be. I'm happy. I'll ship this thing, but in the next episode, Derick Bailey's going to come and bring me right back down to earth, stuff my ego in a small bag, help me hook up Marionette.js. You don't want to miss that one. Thanks for watching and I'll see you then. Plugging in MarionetteJS Introduction Welcome to the final episode of TekPub's Playing with Backbone series. In this special screencast, we take the work we've done on the MongoDB Explorer, and roll in Marionette.js right underneath it. Why? Because it's the abstraction we have been working towards, but it's already done. What is Marionette.js? Well, it's the results of working with Backbone on a daily basis for many years. Derick Bailey, Marionette's creator, and maintainer, extracted many of the patterns that you've seen me use in this series, and he plugged them into a framework. That is Marionette. Personally, I'm really impressed with the thought and effort Derick has put into this project, and I think it's invaluable for any larger Backbone work. Hope you enjoy the show! Let's get to it. Sitting here with Mr. Derick Bailey. How are you Derick? I'm doing good. How you doing Rob? I am recovering. Recover? Recovering from this experience. The interesting thing is as I record every episode, and I'm done with it. Right. It takes me a week, sometimes longer, and people have been asking me, why are you taking so long? Well, it just takes that long to do this, and then the follow on question is, didn't you do this beforehand? I mean, you should have this. I did. I wrote this entire app beforehand. I don't know why it was so hard the second time, but man, oh, geesh this was. That's the whole thing about teaching right? I mean, you can build something yourself for yourself, and it's all good and dandy, but then you try to teach someone else, and suddenly it's a thousand times more difficult. No doubt. Well, so, that starts us off on a good footing. Let me just say straight upfront, and I said it the whole time, Backbone itself is not terribly difficult. Right. The concepts are really easy. Unfortunately, where Backbone sits is square in the middle of hell, in terms of, like you have JavaScript on one hand, and then you also have to use the DOM. Yuck, right? And then you have to understand evented programming. Mm hmm. Asynchronous evented stuff. Those three things, and Backbone sits in the middle, and you're in for pain. Yeah, it's a pretty big nasty, perfect storm there. Exactly. So that leads me to my first question with regards to Marionette. Marionette is, let's just call some sanity on top of Backbone I suppose. But how much Backbone does someone need to know and understand to use Marionette? Well it depends on how much, how much you want to know about the problems that Marionette solves for you. It's, what's the best way to put this? Do you want to understand why you take that medication every day? (Laughing) Or do you just want the doctor to tell you to take it without knowing what your life would be like without it? Okay. Well medications not necessarily an abstraction, but I suppose it could be, an abstraction of an illness. So here's my, my point is this, that like for ORMs, right? Right. O-R-Ms, that's always the big thing. It's the original leaky abstraction, leaky meaning you had to know SQL, and what's going on in the database. You had to go one layer down. Therefore, the abstraction leaks, and I wouldn't, I mean, my guess would be that you should, I mean, you can't use a tool like this without knowing some Backbone, right? Or can you? No, not at all. You really do need to know Backbone before you use Marionette, and honestly, if you're just starting out with Backbone, I wouldn't recommend using Marionette. I would really say, you should learn Backbone first, on its own, building really small applications just to get your feet wet, and to understand why you build Backbone the way you do. And then once you start seeing some of the repeated patterns, and running into some of the pain, and the heartache that you've run into in this series, then you'll start to see where Marionette comes from, and why it's built the way it is, and the problems it solves. So maybe it's a good way to look at this. Say, Marionette is essentially a set of helpers, maybe? Yeah, it's very much so. The first and foremost. It gets rid of a lot of the boilerplate and pain that Backbone gives you by being unopinionated. Okay. Okay. I like it! But it's simple enough, I think. Well, we'll see, because we're going to plug this in right now. And so finally, the final question I had for you is, you extracted this because of the real world work that you had going right? Yep. Absolutely. Okay. That's one thing I really like about Marionette is that you extracted it from real work, and as opposed to a lot of frameworks, I can name off the top of my head, like, well, I mean ASP.NET MVC. It had Rails to kind of pattern itself after, but it wasn't extracted. It was thought up. Right. Like hey, this is how we can do this. That's not a bad thing, but sometimes there're these weird edges to it that you don't quite understand why are they doing it this way, and it's kind of because, well, it's echoey, chambery, and so on. This came out of real world, and there're definite reasons for each part of it. So, to see that, we have to plug it in, so let's go plug it in, shall we? It sounds like fun! Setting Marionette Up Okay, well, so this is where I left off with the last episode. And basically, I started the last episode by saying, I really tried to back myself into a real corner, where everything hurt, and I got there. Because that's what working with Backbone is, unfortunately, and it's not Backbone's fault, you're just working with really wacky technologies, like we already talked about. Mm hmm. So, the good news is everything works. The bad news is, I don't know if I'm terribly proud of it. But it works, right, and that's kind of where we always get to when we say, you know, the whole ship-it struggle, right? Right. Does it work? Does it fit spec? Ship it. The whole start up thing of if you're not embarrassed when you're first shipping it, you're waiting too long. Exactly right! So where do we start? I want to, you know, there're a couple of things in here that just smell. So, this navigation thing, while I think it works, and it's readable, and its, I'm okay with it, I know that you probably are looking at this going, well, we could do this way better. So, I'll let you tell me what we should do, how to get started, and so on. You're familiar with all the code. We've gone through it. Yep. You have some opinions about it, so what first? Yeah, so, before we get started, I do want to say very briefly that one of Marionette's core philosophies is very much the same as Backbone in terms of providing building blocks. Pieces that you can just pick and choose what you want to use from whenever you want to use those pieces. So it's not an all or nothing endeavor. It's not like you're trying to switch from no JS to Ruby On Rails. So, that being said, what I like to do to begin introducing Marionette's into an existing project is find the smallest, safest, most comfortable place that we can to replace one little thing. Okay. And then once we have that replaced, we'll take the next step to replace the next little thing. I like that. And we'll never do it in a way that will be painful, or cause a tremendous amount of work, unless we can see that there is an immediate benefit in using Marionette. And by the time we're done with this, we'll end up having most of, if not all of your code replaced with Marionette, but we'll do it in a way that allows you to see the benefit of each piece that we're replacing while we are replacing it. Sounds like a good goal. Let's see if it'll happen. It's a tremendous goal. It's one of those pie in the sky things that I've been able to repeat over and over again, and blown the minds of many a people doing so. Alright. Well, let's start here. We'll download, look at you and your whippy-zippy fun stuff here. Yeah. That was developed by a company over in Germany, I think it is. They did some really awesome work on that design. Alright. So, I've got a couple of files here, backbone.babysitter, backbone.marionette, marionette.min. Mm hmm. Wreqr, jquery, json2, underscore. How much of this do I need? So you've already got Backbone setup. You've got Backbone, jQuery, you probably have the JSON2 Library, which is optional. So there're a couple of different approaches, which is what this zip file provides. You can do the all in one backbone.marionette.min file, which has everything you'd need packed right into it, or, you can do piecemeal. You can take individual pieces and include them yourself. Now, if you're using something like the Rails Asset Pipeline, I really do recommend the piecemeal approach, because that lets you keep the individual parts updated easier. If you're not using something like a pipeline, or another build process to concat and minify everything for you, just go ahead and grab that min file. And for our purposes, that min file's probably going to be the easiest thing to do. That way we just have the one file to include in the project, and we can get going. Yeah. Okay, good. So I have that in there. One other thing I was going to ask you is a lot of JavaScript Libraries, if you're not, I know Amber does this, if you're not using the min file, then it considers it like the development, so this might be the development, and it actually outputs a lot of debugging information for you. Yeah, I do not have the debugging information in there yet. That's something that I've been talking with a few people about recently. But, the non-minified version certainly does help in debugging because you can actually see the code easier. Geesh, Derick. See what's going on. I didn't think you sucked so much. I know. I know. I'm awful. Okay. Well tell you what, let's be good developers, and what I'll do right now is I'll just, ewww, and I'll say even though in episode 10, okay good. And so, Git checkout-b, I'll just call this Marionette. Switched, okay. There we go. All greens. Yay! Kind of neat. That's, WebMatrix's pretty cool, I have to say, I like it. Yeah, yeah it is. Alright. Okay, so Marionette's in there, and I assume probably the first thing we're going to need to do is to Edit to. Yep. Alright. This is what I did to Ben Sherman when we were working with his stuff. I made him let me drive, if that makes sense. I think I have everything, yeah, good. Marionette. Okay. We are plugged in. You know, my whole mantra this whole time, with this whole series is baby steps. Don't ever assume anything works. So I'll Refresh this. Yay! So look, we don't have any problems. It's exciting. Yea! Alright, hit me. Item and List Views So, you got Marionette plugged in there. First thing we want to do, like I said, is find a little spot that's going to be easy to put these Marionette pieces into. So, if you go back over to your browser real quick, I want to take a look at some of the pieces that you have. So this is your home screen where you get this list of DATABASES basically, and you have, well, a list of databases on the screen there. Each of those has a little bit of functionality. You can click on them, or click Delete, or whatever. Yep. So, this is basically what I would call a ListView or a CollectionView in Marionette. So I actually have a Marionette.collectionView that we can define, and build a nice little list like this. But before we do a ListView, the ListView, of course, contains Items. And in Marionette, I have an ItemView. So let's take a look at what you have for your ItemViews right now to list each of those individual databases, and let's see if we can replace your version with a Marionette version, and see what happens to the code. So what I have right now is a straight up ListView, and initialize. I just bind to events in the collection, add, remove, reset. Mm hmm. And then, duh, I'm not doing much different anything. I'm just looping over the ItemView, setting the model, rendering it, and then, I'm actually stuffing everything into an array. Okay. And then, I'm using this.el.html, which I probably shouldn't do. Actually, let me just fix this. Didn't we, didn't we solve this problem before? Yeah, I think we did. It's one of those things where it works in some ways and in some scenarios, and other ways in others. Yeah. There we go. I was just, fix that there right now. Okay, so yeah, that's what I'm doing. Let's make sure that works. Baby steps Rob, baby steps. Actually, I don't think that will because it's an array. Oh no, it does work, okay. I guess jQuery is smart. I heard that too. So that's it. That's my ListView and ItemView. Yeah! That's great. That is almost line for line what I started with when I was building my ListView with Marionette. Okay. Super simple. So let's go and see if we can replace this. Maybe what I'll do is my, I have a DatabaseListView right here. Mm hmm. I bet you we can, let's just see if this works the DatabaseListView. Well, let's do the ItemView first before we get to the ListView. Okay. Alright, so where you have Congo.ItemView, right there on line 29. Yep. You can actually just replace the word Congo with Marionette, because I happen to call it Marionette.ItemView. Beyond that, what is your showDb function do? When is that getting called? It's ah. Oh, that's from the events. Okay. Yeah. So this just gets the click of the link and it navigates us off. I get it, okay. So, at this point you happen to have built a pretty darn nice structure for your Congo.ItemView, and I'm happy to say that Marionette.ItemView works exactly the same from the basic API. Well, well, well. Let's Refresh it and see what happens. Ohhh, okay, there's no item listenTo. What version of Backbone are you on? I don't know. I'm betting you're on 0.9.2, and you need to update to 0.9.10 for this version of Marionette. Okay. Here's the backbone.marionette.zip. Okay. Well this is cool because, yeah, I need this, and it's here. Woo-hoo! Hey, it's right there in that zip file, everything you need. Hmmm. So, this is already minified? No, that is the unminified version of Backbone. Okay. So if you do want the minified version, you are going to have go back out to their site and grab it. I think I can live without it. I prefer developing with the unminified versions, honestly, it makes it easier to debug. Yeah. Okay. So we've updated Backbone. Let's see if that changes anything. Jooop. Hey! Yay! It works. It does. Cool beans. Okay. Yeah. So good for you for building a good API into your Congo.ItemView. Why thank you. Alright, so the second thing would be to take the ListView and replace that with a Marionette.collectionView. So, like that? Yeah, there is one minor difference between yours and mine. On line 47 there, that ItemView, should be a lowercase i for the Marionette itemView. Okay. Is that it? That's it. Dude. No way! Yeah. Whoa. Look it. That's cool. So it hadn't passed out your add and delete functionality as well, see if that works. BoomBoom, Adding. It does. Deleting. Wow. Okay. Yeah. Okay, wait, so hold on. If I delete that, it's gone, right? Yep. Which is exciting. Refresh it, it's still there! Ooohhh. So it didn't really work did it? No, what, Derick, what kind of magic voodoo trickery you got going on there? Well, yeah, sorry. There're a couple of different things going on here. First of all, if you go back to your ItemView. Mm hmm. So in your Congo.ItemView, you had a remove function in there, which did your whole confirmation to remove the item, and all that kind of stuff. It's this guy right here. Yes. Yeah. Well, in Backbone 0.9.9 and later, Backbone.View has a remove method built into it. But, here's the thing. Backbone.View remove method only removes it from the DOM. It doesn't delete the model, it doesn't clean up anything. It just removes the DOM elements from the DOM. Okay. Alright. That's, alright. So then, what I'll need to do is have my own remove function. Yeah, exactly. So looking. Name it something other than remove. Right. Because. So looking at this, my first inclination is, wait I layered in, and I don't want to call an abstraction, I layered in a helper, and ended up with more code. Yeah. Well, you moved code around. You didn't really end up with more code. That's true. Good point. So, am I getting anything else from using Marionette.ItemView here that I can't? Kind of like memory management, or hell yes. Yeah, absolutely. There's a lot of stuff built into Marionette's ItemView that you would not get from your standard Congo View without writing a couple a hundred more lines of code. Oh, okay. Including memory management, as well as some additional UI features and other ways to bind to models that make it really, really nifty to do things. Okay. Alright, so it's worth it to do it, good. So that was simple. Tell you what, let's, I mean all the other ListViews are the same, so let's, with the magic of video editing, I'm going to go and just plug everything in, because I got, they're all the same. Let's do it now. Let's do a montage. Dadaditado. Okay, I have plugged in Marionette magic. I just literally overlaid it on all my ListViews and ItemViews. I'll tell you what, I'm thinking about this. If I would have started with Marionette, I'm just thinking about all of the code that I wouldn't have had to write. Mm hmm. It would've been nice. Ace Editor Conversion Yeah. So, speaking of code that you wouldn't have had to write, that render function with your Ace Editor right there on the screen, that's looking kind of gnarly. Yeah. So, should I explain this in probably a little bit more detail here? Yeah, let me know what's going on there, why it's doing things the ways it's doing. Yep. So, let's, first let's understand why I have the Ace Editor in here. It's really handy. My thing that I really want to do is to make it so that people can edit JSON directly. Feel like they're editing the Mongo document, not going through some weird UI trickery. Right. And part of doing that is, you know, look at this. It highlights errors, shows you what's going on. Tells you this is a bad string. Oh, nice. So yeah, the Ace Editor is rad, and it's even groovy. It's the thing that powers the Cloud9 IDE if you ever use that, so. Oooh, okay, so that's the, GitHub uses that, right? Yes, yes. In fact, little bit of trivia, I contributed to the Ace project, the C#, the C# bits. Nice. Yeah. So, if all the recognition and keywords and stuff, and I think I got credit on that on the project site. Woo-hoo! So if you go look at C# on GitHub, whoop-whoop, use my code. Nice. Anyway, so to get this to work, as you can imagine, I mean this thing is, this thing is really powerful JavaScript stuff. Yeah, it's like an entire plugin system of its own, right? Yes, exactly. The way you get it to lay itself out is to say, I want you to drop yourself into this div tag, this id tag here, and then it takes care of the rest. If this element is not in the DOM, it throws an error, which I guess makes sense, right? Yeah, yeah. A lot of widget control suite things are like the jQuery UI, Kendo UI, I mean, they all have various pieces that are what I call DOM-dependent. They require the actual live DOM in the browser visible in order for them to work. Right, and Backbone doesn't work that way necessarily. Yeah, it really doesn't know anything about that. It only knows about, a Backbone View only knows about its individual element, and whether or not that element is in the DOM is not really so much baked into Backbone's View. Correct. So, to get this, so here I have dueling issues. The first thing is, I clearly want to use the Ace Editor. I also want to use Backbone. So I need to accommodate this. The reason I want to use Backbone is because I want to have this editorView here, and because the editorView, which is going to hold the Ace Editor, I want it to have a model so I can remove it, so destroy it, and do all the things that you can do, right? Wire up events. So I'm kind of having to do two things. To accommodate this, you know, I want all over the place, but it turned out to be a little bit easier than I thought, so the first thing I had to do is I had to render the editorView on initialization, immediately. So, in order for that to work, I had to, in index.js here, I had to tell it what element to render itself to, which I hate doing, but, I know. Right. You have to do it, and this is what I do to get around it. So, since it knows what element it's going to render to, now, what I'm able to do inside document.js, is I can call render immediately, and I pull in the template, or compile it, right? And the template is simply this guy right here, right? Right. It's got an Ace Editor div tag, and everything, dadadata, button Save, and so on. I compile it immediately, and then I jam it into this.el. This.el is, as I just said, the #editor div tag right here. Got it. That is already in the DOM. Right. So now that it's appended, Ace Editor is now in the DOM, and now I can have my cake and eat it too, so to speak. I gotcha. So, you're doing all of that just to get your View instance attached to the live DOM, so that when render is called, you're already in the live DOM, and you can actually stand up the Ace Editor. Yeah, and it does two more things, which is pretty cool. It instantiates the editor once, and you don't have to do every single time. So render's called only one time, and so what I do later on is I just call setModel, and what that does is it just sets the value in the editor. Okay, so you're just reusing that View over and over. Exactly. And in order to get that to work, you can see how far down this goes into the rabbit hole. Uh huh. To get that to work, I had to, on my AppLayout, I had to tell it, we're working in the editor, or now we're working in details, and so it's doing this, you know, this detail and editor region toggling hide and show. Yeah. Which is silly, but you know what, these are the things you got to do when you're working with Backbone sometimes, right? Yeah, sometimes. I mean it depends on your goals. It depends on the plugin. Like in this case, if it's really expensive to get the Ace Editor up and running, yeah, you definitely want to do something like this. Now, if it's not so expensive, if it takes, you know, a couple of milliseconds to get that thing up and running, well, maybe it's not worth doing all of this at that point. But, before we get down to this, I think we can clean up your View that wraps the Ace Editor quite a bit. Oh nice. Okay. And then from there, we'll see if we can clean up some of the rest of it, and make it snappy without having to do all of that code to reuse that View instance. Alright, what do we do senor? So, first thing, of course, is to replace Backbone.View with Marionette.ItemView. Ohhh. Okay. Alright, so you have a render method down below. Mm hmm. Well, Marionette provides a render method for you, and it does almost line for line those three lines of code on 81 through 83. Okay. So we don't really need those lines of code in there, but we do need to know after this thing has been rendered, go ahead and do all of this stuff. So Marionette provides the ability to have Marionette do the rendering for you, but still give you a chance to modify the DOM, or the Views element, and do things that you need. So change the word render on line 80 to onRender with a capital R. Oooh, so this is a callback. It is a callback. And this is built into Marionette's ItemView. Whenever that Marionette ItemView calls the render method, then you'll get this onRender, which happens just after the View has been rendered. Okay. So, if you save this, you should be able to Refresh your browser, and hopefully it'll still show your editor correctly. Good gravy. Look at that. Joop. Excellent. Alright, okay. Derick, you're betting a thousand so far. So far. I'm sure I'll flub once or twice, but. Okay. I think we can also change things up a bit so that you don't have to do that el assignment on initialization of the View. Now this will be interesting. Okay, how do you do that? And this is going to be a couple of different steps, so this is where I might actually make a strike or two. Okay. So, we're going to leave this as a Marionette ItemView, that's all good and well. Get rid of that initialize method. We don't want to call render directly from the initialize. That's generally not something I like to do. If you have a specialized case, like you did, okay fine, but in general. Right. Let's go back to the place where you are creating this EditorView instance now. Alright, so that is right here in index.js where I just have an init function, right? Alright. So the purpose of line 16 there is to get your View instance, and get it immediately into the DOM. You're just attaching that View to something that already exists on the DOM. So, I'm going to introduce a new concept from Marionette here called a region. Okay. And I think you have something like regions, because right down there on your AppLayout you say detailRegion, navigatorRegion, thinks like that. Yep. So, in Marionette, I take the idea of a region directly from Microsoft's Prism Framework, and a region in Marionette manages the visual portion of something on the screen. Some element on the screen. So, your editor element, for example. A region, a Marionette region can manage what is being displayed in that element for you, so that you never have to think about #editor again. I like it. Make that assignment once, and you're done. Okay. So to get that running, what you can do here is say, create a variable, and assign it to a new Marionette.Region. Let's call it, call it editorRegion just for consistency and simplicity. Dot Region. Yep. And you can literally Copy and Paste your object literal from that View instantiation, so the el #editor. That's the syntax that I use inside of a region constructor to tell the region what element on the screen it is managing. Okay. Now that we have that, let's go ahead and get this thing up and running, and rendered on the screen immediately still, but we're going to do this through Marionette instead of through the immediate assignment. So instead of assigning the View to the el, we now have the region managing it, but we still want to get the View into the region. Mm hmm. So, what you can do now is say editorRegion.show, and in parentheses, because it's a function call, pass in new Congo.editorView. I see. Oops. So here, you're creating an instance of your editorView, and then telling the editorRegion to show this View. Okay. Since we're no longer assigning the View instance to the element, the view will not be attached to the DOM right away. Right. That means in your View, in the onRender method, when you try to call the Ace Editor code to get that up and running, it is going to blow chunks. If you want to actually go ahead and show that just to verify that it's going to blow up, that might be fun. Yeah. This is the error that is so annoying, can't read property env of null. Right. Okay, thanks. Yeah, so what that means is you tried to instantiate the Ace Editor, but it wasn't available in the DOM, so, yeah. So back in your ItemView, we're going to change onRender. Back in, onRender, ah-huh. Rename that to onShow. Okay. So this onShow method, this gets called by the region whenever you tell the region to show your View. Nifty. Okay. Yeah. So this region, the great thing about it is it works with any Backbone View. It doesn't have to be a Marionette View, but if you provide this onShow method, the region will call the onShow method after it has placed your View in the DOM. Okay. Are you telling me this is going to work right now? It should. Cross my fingers. Almost. Almost. So, I saw the View flash up there, the editor, so it did get thrown in there, but can't call setModel of undefined, and that is from my base class, and that is because in my base class. Oh, because, right. Because previously you were creating, you were assigning your editorView instance to Congo.EditorView. Yeah, which I can do again, right? Yeah, you can totally do that. So right there on line 18, just take out your new Congo.EditorView. Yeah. So, I'll take that out, and so I'll just dootadoo. Rob, there we go. Voodoo! Look at that! Alright! Well, I mean, I'll tell you it's neat that it works, but it kind of just seems like we've just shimmed the difference, if you will. Yeah, basically. But the value here, it becomes a lot more apparent once you realize that you need to replace a view instance in the DOM over, and over, and over again. Well, as I'm looking at this, this should be going here. I mean because look, editorRegion, editorRegion. Same words, right? Mm hmm. So, I should be able to do that shouldn't I? Yeah, definitely. And actually Marionette provides a layout, which is very similar to your AppLayout there. A few differences, but it's very close, so let's go ahead and do that migration. Alright. Since we're looking at that. Okay. So, what we want to use is a Marionette.Layout. Okay. So create a View definition, like you would any other Backbone View. But instead of extending from Backbone.View, extend from Marionette.Layout. We're extending it because we're going to add to the base class? Yes. Exactly. Alright. So those two regions that you had up above, you can Copy and Paste those down into the Marionette Layout, and wrap those in their own object literal called regions. Ahhh, alright. Okay. Drop them in there. Okay. Alright, so a Marionette Layout is very simply an ItemView that has regions within it. So we already introduced the idea of a region. It manages some visual element. It allows you to stuff content into that element at will. So, a Marionette Layout, it'll render a template. You can pass it a model. It'll do all that good stuff, and then within the render template you can tell it to attach to various elements, and set up regions for those elements. Okay, so, well, because there're a number of regions, or things I have up here, navigation, details, and editor. So, I'm going to guess that I have to do something like this, right? Is that about right? You're talking about your navigator View? Yeah, so that's up here. That's this guy. Okay, yeah. Does that work? Yeah, that should work. Okay. And then we'll have to get your Congo.breadcrumbs into that region, correct? Yes. This guy. Okay, easy enough. One thing you want to change real quick on line 28, Congo.appLayout, capitalize the A. This is going to be a class that we instantiate. Right, thank you. The other thing, on line 23, you have the assignment of the el. We'll do that when we create the layout instance. Okay. So, as I'm looking at this, and I'm sort of understanding what we're doing, but I'm starting to think that if we don't start complying with the regions, and stuff, we might be breaking things, am I right? Like, in other words, here I'm passing in the el straight up to the View. Right. According to Marionette, I should be using a region. Yes. Okay, so I assume that we're going to tackle that one piece at a time. Yeah, pretty much. Baby steps. And of course, this really comes down to philosophy and preference. My philosophy is I want one thing, and only one thing to ever know about the actual DOM elements, and that's usually a region. Right. And then I use a region to manage displaying of my views. I never want to assign a View directly to an element, and I never want my View to know how to place itself in the DOM. Yes, makes perfect sense, and I get that. Okay. Alright. I'm going to assume that everything's going to break right now. It probably is. Let's just see. What? Ehh, kind of, sort of getting there. How did that not break? Okay. Derick, voodoo. Well, that didn't break because you were manually assigning that navigation. Oh, that's true, okay. But, we can make Marionette do this for you. Yeah, so it looks like renderEditor and renderDetails is broken on the app, makes perfect sense. Alright. So, what do we do next? Alright, so that navigator, let's make the layout manage the navigator. So up above, where are you creating that navigator View instance? Right here. Alright, move that line. Okay. Let's take that line to, right below the AppLayout create, right here we are going to pay attention to the AppLayout having been rendered. Okay. Because a region within a layout will only exist, will only be able to manage the contents of that element after the Views template, after the layout template has been rendered. Okay. I mean it kind of makes sense, right? You got to render the template in order for the element to be there, and the element has to be there in order for the region to manage the content within that element. Hmm, okay. So, right below line, whatever that is, do a Congo.AppLayout.on. Right here? Yeah. And listen to the render event on, yeah, on render, and then pass in a callback function, and within there, move line 41 into that. Let me ask you a question. Are you ever directly referencing Congo.breadcrumbs anywhere else in the app? No. Okay. Just assign that to a plain variable instead of attaching it to that namespace. Okay. And instead of assigning the element right there, we're going to say on the next line, Congo.appLayout.navigationRegion.show, and pass breadcrumbs into that. Ahhh, okay. Now there's an inconsistency. Previously when you were creating that breadcrumbs View, you were passing in #nav as the element identifier, but your navigation region is set up as #breadcrumbs, is that correct? Oh! Thank you. Okay, that looks, that looks good. I like the wiring, and it feels much more Backboney. Yeah. Whatever. So let's Save this and let's see if we can get that breadcrumb displaying on the screen correctly. Nope. And that's because, that's because our AppLayout, remember in the base class here we have renderDetails and renderEditor. Oooh, that's right. The router is failing, and since the router's failing, the breadcrumb View is not rendering right, so. Yeah. So, let's, I think we can solve that fairly quickly, just by moving those renderDetails and renderEditor into the new layout. Hmm, okay. So once again, we're not really adding more code, we're just kind of moving code around right now to get it into the Marionette structure. Right. Okay. Let's run it and see what happens. That's kind of my philosophy. Well, alright. We have no errors, but nothing's showing up. Ohhh, oh, oh, oh, I know why nothing is showing up. We're never actually calling render on that layout. Right. I forgot that on line 55, you're assigning that AppLayout to an existing element. So, all we really need to do is on line 57, just get rid of line 57 and line 60. Because we don't want to, we don't need to wait for the AppLayout to be rendered since the element is already in the DOM, and we're already attached to it. If we can just go ahead and stand up the breadcrumb View and show it. Alright. Woo-hoo! Okay. That's showing up. Okay. Unfortunately, I don't have a, the details aren't showing up, but the editor is. Okay, so this is probably where your hideDetails, showEditor functions come into play. Correct. So, what's happening here is that the AppLayout, all it really has in it is the editor. There're no details. Nothings being rendered. Details are not showing anything because it's not appending anything into the details thing. You see what I'm saying? Ohhh, okay. So basically all we've done is we've put the navigation into place, but we haven't put the real content in. Write to place. Yup, yup, yup. Gotcha. So, we need to go back up a few lines in this file, and find the place that was previously creating all your content Views. Yeah, so here, if you don't mind, I'm going to just simply do this. I want to clean this up. And actually I think we can get rid of those few lines of code. These two. We don't need that region instance anymore, because we now have the editorRegion inside of the layout. Oh. Right? Yeah, exactly. So we can get rid of line 18, and then move line 19 down wherever. So that's going to have to be moved down below the creation of the AppLayout instance. So, how do we have an editorRegion? I'm a little confused here. We have an editorRegion on the AppLayout instance. Right. Got it. Okay, so, that means the AppLayout.EditorRegion.show. Right. So let's see if that is going to work. Yes it does! Excellent. What I am doing down here is when I navigate to the, right here, so Index is going to show all the databases, right. So before, it was appLayout renderDetails, but now what I should be able to say is detailRegion.show Congo.dbLayout. And then databases fetch. So, that's actually going to double things up, I think. Yes. So it works. Right. But the editor is now showing up, and it shouldn't because we want to toggle it. Right. Okay. So let me ask you a question Derick. Mm hmm. The whole reason that I was doing what was I doing with the editor, having two regions on there, the editor and detailsView, right, is that this editor needs to be part of the DOM when you render it. Right. Given our new AppLayout and our regions, and all the things we're doing, is that problem solved? Mostly, yeah. It's, the way that we have it setup, we're still of course rendering the editor right away when the application stands up, but we really don't need to anymore. Since we have regions in place now, we can let the region tell our View when the View has been placed in the DOM, and then we can just render the editor into the DOM after it's in the DOM. Yeah, well, so what I'm thinking is, maybe we just have a detailRegion and not an editor. I'm just going to swing and try this. Sound good to you? Yeah, that sounds great. Let's try it. So, okay. So, we actually don't want to do this right here. Right. What we do want to do is we want to show the breadcrumbs. Okay, so we know that. Yeah. Alright, so let's give this a whirl. Let's see what happens. Okay good. That's exactly what we want to see. Right. Alright, so then instead of doing, is with every line here, I should be able to replace renderDetails with detailRegion.show, or if I wanted to shortcut it, I could just, I could just, I don't know, I don't like all this dotting, but I guess it doesn't really matter. It's more clear. ShowDatabase, showCollection, and Index. Okay, everything but showEditor. So if I Refresh this, let's open this. So, I should hit that, and it works. Awesome. Okay, so that's what we want. The final step here is we don't have renderEditor because, what we should be able to do. I want to be able to say something like, detailRegion show, and then I want to show the editor, but I want, so the editorView, right? So I should be able to say Congo.editorView. Here you're going to want to create a new editorView instance passing that model into it. Ohh, okay. Now, this is where we get stuck before, because the editorView. It needs to be in the DOM before you can run the Ace Editor, but we're using onShow right there on line 77. So, is this editor going to be, okay, well let's go one step at a time. So, okay, so just say var editorView = new Congo.editorView, and then we'll pass in a model, model = model. Okay. Mm hmm. I'm actually, I'm actually understanding the way your brain works, which is. That's kind of scary. Alright, let's just see if this works, right? So, joop, almost. Almost. Almost. So it's showing the editor. Mm hmm. That's good. It didn't get the document into it. Right. And the reason that it didn't is because back in the editorView, doo-too-doo, what we need we need to do right. So, we'll just say this.setModel. Yeah, you don't need to do that at all. You could, I would probably rename that setModel to populateEditor, or something. Equals and if it's not set, a new thing, right, good, BAM, and then so this.setModel, right. So, that's okay. Mm hmm. Okay, so you wanted to rename this to. Yeah, I just don't like the name setModel because that implies that you're going to change the model on the View, which I guess you kind of are, but. Ooop! Look at that. Hey, look at that! Okay. Okay this is good. We're cleaning this thing up. Alright, so, the one thing that I'm not hip about is having to cycle Ace Editor every single time. But it was pretty quick. I don't know, do you think I should care about this? I really don't think you should. We are potentially introducing a memory leak right here though. Since your assigning Congo.editor = ace.editor right there. Are you ever referencing Congo.editor over, and over, and over again? Well, you know this, I mean, you know, I could just do that and then we're only instantiating it once. Yeah. So, let me just say, you would want to do something like this if the editor takes a long time to spin up and get put in place. Like if it's a noticeable delay, more than 100 ms to get that editor spun up and visible, then this is probably something that you would want to do in order to reduce that flicker, and that downtime from the user's perspective. If it's a really fast thing to get up and running, I wouldn't do that. I would just create a variable and move on. Okay. Alright. I think you're right. So the thing that I was actually initially worried about was that in some large embedded documents, that might be the case, but I don't think it will be. Okay. Ahh. We'll leave it. Alright, so let's just make sure that every. Oooh! It's not working. What happened here? So, back to your code. I wonder if it has something to do with assigning the editor to a global variable. Got it! Yep, you're right. Oh, I think it's because I had. Ooh, yeah, because you were grabbing the same instance every time, and it was never re-rendering itself. Exactly. Yeah. People out there are probably, dude, you should be, hello, dumb-dumb. I've had people tell me that they sit there and watch my screencasts and yell at the screen, it's right there! It's right, just change! Right. Okay, so then I think what I'm going to do is just, I'm just going to keep this all down here, so I can use the variable. Yeah. Okay, so this.model, this is our new MongoDocument, that's what we want. DocJSON string, find that, and setting the Value. Clearing the selection is the most annoying thing ever. Good. Okay. Good. It's working. Solved that problem. Hooray! Wow! Alright. Okay, so we don't care about that. We're going to remove that code right there. You missed your comma, there. Thanks. And back in here, this is looking, I mean it's looking really swell. Derick, I think we're done. NOT. Save. Ahh, Save doesn't work. Oohhh. That's okay. That's okay. Alright. So this is why, got it, this is why I made it a global because it needs to be used. How do we get around this? So, I've made editor internal, so what I need to do now is I need to pull the value out of the editor. Oh, okay. Instead of assigning it to a global variable then, I would just assign it to the View. So, this.editor equals, and use this.editor everywhere. Okay, I actually did that before, and for some reason I was having a heart attack about it. Yeah, the heart attack you have about that is, oh, crap! I'm using this, and this changes all the time, and, but in this case, I can guarantee you that this variable is going to stay the same, it's going to be the View, because that's the way I built Marionette. Because I'm Derick Bailey, I think that's what you meant to say. That's right. Alright, so hit Save. It saved. Yeah, I like it. More Marionette Possibilities So, I just, you know, I'm navigating back to the collection View here, right? Mm hmm. And I'm thinking, I kind of want to show a message, is there anything in Marionette that's, you've got like a notification View, or anything like that? No, I don't really have anything like that built in. I mean, that's kind of application specific, and I like to think of Marionette as providing the infrastructure so that you can build your application framework, and I kind of consider notifications to be part of your application's specific needs. Well, what if I just did something stupid like, you're going to hate me for this. Just something. What does that even do? I've never used that effect method of jQuery. What? No, seriously, I never have. It just makes everything flash like that. Whoa! Yeah, so, yeah. It just shows like something happened. Oh nice. It shows all kinds of effects, shrink, grow, well, slide down, slide up, all that kind of stuff. Fade in is another one. Oh okay. So those, I've typically just used the method call, like jquerySelector.fadeIn. Yeah. Yeah, some of them are built in. Okay, so we got to wire up a little bit more here, so our editorView is Marionette. Everything is Marionetted, if you will, and our documentView, yep. I can just use a regular old View, right, for this? There's nothing that I'm doing with these optionViews that anything special. You're rendering that template so you'd want to use a Marionette.ItemView. Okay. And the reason I say that is just so you can avoid having to write your render method again. Right. Okay. So this is a DocumentOptionView, and let's go back and just make sure it shows up. So, okay good. It's showing up, this guy, right here. So, if I hit Add, and, so this is the router throwing this error, because we're going to a new URL, Shlonk users new. Mm hmm. Which means that we got to come down to here, and new document, right, appLayout renderEditor, right. Oh, okay, so that's from your router? Yeah, so what I want, this should just work, detailRegion.showEditor, right, I need these two lines here. Yeah. And unfortunately I don't know how to get around this duplication, because you need it just in case someone comes in on a URL, straight in. So, yeah, you need to change line 81 to use Congo.editorDocument. Yeah, and then you can get rid of 80. Yeah, so code duplication. Umm, this is where I would start extracting those two lines of code into a function that you can just call, and then if you start getting a collection of functions that are related, extract those into an object. Yeah, I could do that, but I'm not going to. There we go. Alright, so this is showing. Good, and write name is Derick, and saving. Ooop! Look at that. That works. Derick, do you mind if I Delete you? That's kind of a personal question there. Did we miss any tricks with Marionette? Oh, quite a few. We've just barely scratched on the surface of what Marionette really provides, and only from a View and region perspective. There's a lot more going on with Marionette that could really make this into a much more scalable and robust application. Are you saying it's not scalable and robust? Yeah, I kind of am, and there's nothing necessarily wrong with that. That's not necessarily bad. It comes down to a question of, do you need scalability beyond what you have here. Do you need more robustness? Are you going to have large areas of the application that need to be shut down and started up, so that you don't waste memory in a browser, and things like that? Well, the app's working, that's exciting. Mm hmm. Do we miss anything? I'm looking over this and it doesn't let me. Can't be that easy. Well, it kind of is. I mean, that's, like I said, one of my goals with Marionette is to be able to just drop in one piece at a time, when you need, where you need it, and then eventually you start seeing, oh hey, I took all of these pieces, brought them over to Marionette, and now there's this one extra little thing I can do to make it even easier, and add a little bit more feature and functionality. Well, in looking at this, okay, so in my base class, we're getting rid of the abstractions. We got rid of the AppLayout. Mm hmm. I believe we got rid of the ListView, I'll guess we'll find that out pretty quick. I think so. The ItemView is gonzo. Yep. I think Congo. Your Congo.View is gone as well, because that's Marionette. So, every View just about has been replaced, and I'm losing my abstractions. This is good, except for the layout. Yeah, deleting code, that's always fun. So I do have the layout being used here and there, like in the database, I'll come back down here. Congo, right, DatabaseLayoutView. I stole this from you. I did. Excellent. I think it's when I called you in my panic, Derick, why isn't this working? And you had shown me how to do this. Yeah. So this should be pretty easy to change, right, Marionette.Layout? Should be, yeah. So this should change from layoutReady to an onRender function. That's right. And then on line 68, instead of databaseList.append, you would be calling, yeah, this.databaseList.show, and just pass in your dbListView instance. You don't have to call render. Nice. Because another thing that I actually neglected to mention so far, is Marionette's regions will call the render method for you. That's nice. Okay. Yeah, so that cleaned up quite a bit. Let's see if that works. That's this View right here. Too doo doo too! Err. Alright, oh, looks like I have a, so is it LayoutView, or just Layout? Oh, it's just Layout. Okay, that was my problem. Darn it! Was hoping to catch you! And double dang. Look at that. Okay. So then that means we can go to collections, and do this down here. And this would be OnRender. Right. New collectionListView, right? OptionView. Okay, good. And this is show, and show, and too doo doo too doo, too doo doo, just like that. Oops, without the capital O, because we are not using .NET. Yeah. And if I go over here to collections, ka-double bam slam. Look at that. Excellent. That is good. So if we go Marionette.Layout, and we go to documents down below, right. Same here, onRender, show, show. I think that's it. So those are the layouts that I have. And it works. Wow. Alright, so, hmm. It's like there is somebody thinking about these things, and building a framework for it, or something. Don't get smart with me. Deleting my base class. That's kind of exciting. We've lost our base class. This is what I was hoping would happen, but I didn't think you could pull it off. And there he goes. Let's just see how deep the rabbit hole goes. Wow! Dude! This is quite a good refactor. Okay. Going back over here, we've lost an entire base class. We have Marionette in place. Our layouts are working the way we want them to. Everything is happening nicely. I rather like this clean up right here. This is neat. So, this init function is initializing all the things we need, and then basically wiring them, like, there might be something better, I don't know, maybe on start would you say to show the navigation region? So, yeah, there's a couple of things that we could do to use more Marionette, and not necessarily clean this up any, but just show you how I would do this with Marionette, because I don't really think it's going to be any different necessarily. It's just going to be the Marionette version of it. Well, we are Marionetted, so hit me. Alright, so Marionette includes an application object. So you can create a new Marionette.Application, and that application object is your bootstrapper. It's like the main function in a C# application where everything spins up and spawns, and gets rocking and rolling. Okay, so what would I do here? So, you can start out pretty simply. Instead of assigning Congo to an object literal, assign it to new Marionette.Application, and pass that object literal into the constructor function. Really? Yeah, so this is one of the things that I'm quite proud of. I've gone through this scenario enough where people start with object literals, and convert to Marionette, that I actually, I let you just pass your object literal directly into your Marionette.Application, and all of that is now right there and available on your Congo object. This will probably still work. Wow! Amazing. The reason it works is because you've provided all of your methods to start and init this thing, and get it up and running. And the Marionette.Application says, look, you provided these things for me, so I'm going to let you use them. But Marionette provides its own start method as well, and it gives you some additional functionality that you can use to help clean up your code, and keep things a little more segregated, and separated, and all that kind of stuff. Alright. So, right now you have that init function. Take all of that code, take that entire init function, and cut from the application object. So just cut line 4 through 28. Okay. Just cut it? Yeah, just bear with me here, follow along, line 4 through 28. Okay. Now, down below the application object definition, at the very bottom. Right here? Mm hmm. Do Congo.addInitializer. Ooh. Okay. AddInitializer is a method, right? Yeah, addInitializer is a method. So, you're going to pass a callback function to that, and then Paste everything that you just cut. Of course, get rid of line 31 there, because that's. Oh, right, right, right. And then line 54, get rid of that. So, an initializer im Marionette is pretty much what it sounds like. It gets run to initialize your application, and a Marionette initializer gets run when you call the application's start method. Now, you've overridden the start method by passing in your own start method into the application definition. So, we're going to need to move the code from that start method somewhere else as well. And typically, I put those few lines of code either in an initializer, or in an event that runs after the initializers. So for now, just Paste it right there, you can get rid of Congo.init, because this now is the init function. Yeah. And everything should be going. Let's see what happens when you Run this. Wow! Okay. If that works. You freak of nature. Look at that. We did not rehearse this, by the way. No. I wanted to see Derick cry, and he's not yet. Alright. We're getting there. Wow! Okay. Alright. So, do you have, I imagine that Congo has got some events now. Could I just say, let me guess. Congo.on start, yeah? No, unfortunately. Actually, I really think it should be called start, but I called it initialize. Well, there're two events. There is beforeInitialize and afterInitialize, and I got them, I named them kind of funny. I named it initialize:before and initialize:after, kind of following the Backbone colon namespaced thing. So, here's what I typically do. Uh huh. I usually have an initialize:after callback function, just like you're doing there, and I almost always put the Backbone history start in the after initialize. Yep. Now, I would put that layout region show, I would leave that in the initializer. Yeah. But I almost always do Backbone.history.start after the entire application has been initialized. So the benefit that we're gaining here, is that we can add a thousand initializers to the application object. You could have 350 million JavaScript files, and each one of those can call Congo.addInitializer, and you can add all of those initializers, and then there is that one Congo.start method call that runs all of those initializers. And then after all of those initializers have been run, start up your history. I like it. Okay. Now what? Well how far down the rabbit hole do you want to go with this? I mean, we could get into modules. We could get into some additional View types that, I'm not necessarily convinced that you would need in this application. There's quite a bit more going on that we could do, but I think for a good introduction for getting your application migrated into Marionette, this is pretty darn stellar. Well, I have a feeling that we could probably sit here for gosh, a week, going into all the different nuances of Marionette. Weeks on end. But I do think, that, you know, we covered what I needed. Number one, we got rid of my base class and abstractions that I was writing. Mm hmm. The application, as far as future goes, is just about finished. I think it is finished. Mm hmm. It does what I need it to do, and now I feel like it's a whole lot cleaner. Well good. Yeah, I mean, what do you think? Yeah, I'm really happy with the direction that we took with this, and where we ended up. I mean, there certainly are a good number of things that Marionette could offer to help you grow your application, but if you're saying your application is darn near feature complete, then let's leave it like it is. Let's move on, and make lots of money on this open source project. Well, you know, I was hoping at some point that you would come on, or I don't know, write a really flaming blog post about why my use of this router is completely wrong, but I kind of like it. I mean, I'm using it as a controller. Yeah. I know you don't necessarily care for that. Yeah. Would you, using Marionette, would you do this a different way? Uh, yes, I probably would. I would extract most of that code out into a separate object. I get kind of picky about my routers. I want my router to be, you know, the definition of the routes, and then, at most, one or two lines that call to another object so that the other object can actually do all of the real work. I don't like looking at large routers full of code. So, what you might do is have your own controller. Is there a Marionette controller? Yeah, there actually is. It's an object that is really, really, really poorly named, quite honestly. I originally started using it as a controller for my routers, and so that's why I call it a controller. But it's become such a tremendously useful object. I use it anywhere that I need to have Backbone events, and I need to have a close method to clean up after itself, and I need any of these little things that I constantly do inside of my Backbone applications. Okay, so in this, would this be something like Marionette.Controller.extend. Yep. And then, so what we should do is say, new document showEditor, all that stuff, doing what a controller typically does, put it in here, and then have the router sort of just call the controller, is that right? Yeah. So you want to do something crazy real quick? Sure, why not. Let's move all of your functions from that router into that controller, just move them. All of them? Just move them. All of them huh? Yep. Okay. All of them. Alright. Except for the routes. Except for the routes. So, okay, I know what you're thinking here. Uh huh. Then go down and change your router definition to Marionette.AppRouter.extend. Okay. And then change routes to appRoutes. AppRoutes, okay. Get rid of that comma on line 99, Internet Explorer will complain about that. Yes. Now, where are you instantiating that router? Up in the initializer, right at the very top, right there. Okay. So, inside of that constructor call, pass an options object, and pass a controller parameter. No, I'm sorry, don't call it options. Oh, I see, right. Call it controller, and pass in a new whatever that controller name you gave it, Congo dot. I think I just called it a controller. No way. You're kidding. No, that should work. Okay, so. Yeah, so this is basically what I do. I really don't like having methods inside of my routers. I like my routers to be clean and simple, and every now and then I do have some code in there for some special case. But generally speaking, I get rid of the code in my routers. I don't like my code to. It just works. Yeah. Derick! It's amazing! It just works! You don't write code this good? No, I don't. This is not me at all. So, alright, so I will say this, while this feels like just, you know, you're waving your arms and just throwing in some misdirection, it feels that way, but. It is. But the but, if you decide you don't want to support state anymore, right? Or you don't want to have URLs, or you just, whatever, these URLs change, that makes this more flexible. In other words, you can say no, no more URLs. Every things going to be, you know, starting from the root, and then you have to navigate along. You ditch the router, and then you could just use a controller, if you wanted. Yeah. That's, okay, I like it. Well not only that, but you could have your controller available to other areas of your code, so instead of just going through the routes all the time, you could make a button click call your controller function. Yes, I like it. And then suddenly you have the same piece of code running, whether it's called from a router, or a button click, or whatever else. Rabbit holes. I like this. This is good. Well, we are coming up on an hour and some, but I think this is worth it. I hope folks out there have learned about Marionette and how it works. I've had a good time. I've had fun too. I hesitate to even ask you this, but is there anything else you can think of. Not without really going deep into some rabbit holes, and I think we'd be pushing two to three hours if we tried to do that. So, heading over to Marionettejs.com, let's see you've got your docs somewhere. Yeah, so if you click on, right, Marionette.js on GitHub, all of the docs are listed in the readme, right there on the home page. Okay. Source code and Downloads, oh wow! Right there. Geesh, look at all this. Yeah, look at that. And if you click on one of those links, it's just a file sitting in the repository. Which is great, because I get a lot of really good pull requests to update the documentation. People will notice something that I missed, or misspelled, or something that's just not quite right, and they'll send in pull requests. So the documentation, I've heard, is quite stellar. I get compliments on the documentation on a regular basis. That's great. That's so helpful. It is really, really helpful. You know what's going to be even more helpful? What's that? This video right here. Excellent. Yay, hooray. Alright Derick, thank you so much. I really appreciate your time, and yeah, good luck with Marionette and everything else. Thanks. Alright, talk to you soon. Alright. Course author Rob Conery Rob Conery co-founded Tekpub and created This Developer's Life. He is an author, speaker, and sometimes a little bit opinionated. Course info LevelIntermediate Rating (166) My rating Duration4h 26m Released9 Feb 2013 Share course