In this lesson, we continue to dig into ui-router while doing some significant refactoring to our Eggly application.
We will start out by removing MainCtrl entirely from the application as we start to move functionality to more appropriate places with the application. We will build out the edit and create sub-modules to include the states and controllers for editing and creating a bookmark. With our states defined, will leverage them to manage our view instead of the ng-if statements we were previously using. We tie it all together by using CategoriesModel to track the current category and provide functionality to the BookmarksListCtrl.
We cover a lot of material in this lesson as we start to apply the concepts covered previously to finalize functionality in the application.
[00:00] In this lesson, we are going to start to build out the edit and create bookmark functionality in Eggly. In doing so, we are going to dig a little deeper into ui-router, as well as perform some housecleaning along the way.
[00:15] Speaking of housecleaning, the first thing that we're going to do is delete the main controller. It has been good to us, but it's time to move along. We'll start to move out the pieces of specific functionality into more appropriate places within the Eggly application.
[00:31] Within the index.html file, we will delete the ng-controller reference. In eggly-app.js, we will go ahead and just delete this controller entirely.
[00:45] Now that we have cleared the deck, so to speak, let's take a moment to review the routes or states that we have in place, because each one builds on top of each other.
[00:57] This will be helpful as we get into building our edit and create states. At the top level, we have this abstract Eggly state that serves as a placeholder or a namespace for application states.
[01:11] We can see this state being built upon in the categories.js file, where we define the eggly.categories state. This state has two named views, a categories and bookmarks view.
[01:29] The categories view targets the UI element named "categories" in the top-level state, which is Eggly. The bookmarks named view targets the UI view named "bookmarks," also, in the top-level state.
[01:45] In the bookmarks file, we have defined an eggly.categories.bookmarks state that also targets the bookmarks named view in the top-level state.
[01:58] Before we start to build out the create and edit states, let's go ahead and just build out the templates by refactoring the bookmarks template. I'm going to hop in, take this edit form, and just paste this into the bookmarks edit template. We can delete this.
[02:24] I'm going to take this create form. We will just paste this into the bookmarks create template. I'm going to delete this ng-show, because we want this form to show at all times when we're in a create state.
[02:44] I'm going to go ahead and close that. From here, I'm just going to convert this div wrapper into a ui-view element. We're going to leave this as an unnamed ui-view element that we'll revisit in just a moment.
[03:04] Now that we have the template refactored into the smaller, more specific templates, let's go into the bookmarks create module and define the create state. We are going to define a config block, inject stateProvider in.
[03:27] We will define our first state is eggly.categories.bookmarks.create. We'll give this a URL of bookmarks/create. The template URL is going to be...
[04:01] The controller will be CreateBookmarkCtrl as create controller. Let's go ahead and stub out this controller so that it's there when we get to future videos.
[04:30] Let's go ahead and do the same thing for the edit bookmark state. We'll hop into the edit bookmark sub-module. We will define our config block, inject stateProvider in.
[04:52] The state will be eggly.categories.bookmarks.edit. The URL will be bookmarks. We do need to pass in a bookmarkID since this is dependent on the bookmark that we're editing.
[05:08] We'll do edit, and then, the templateUrl will be app. We will define the controller as "EditBookmarkCtrl as editBookmarkCtrl." We will just go ahead and build out this controller just real quick.
[05:46] We have successfully defined the two states for creating and editing a bookmark. We need to do a few additional steps so that we can successfully navigate to these newly created states.
[05:57] We are going to hop into the CategoriesModel, create a few new methods, and add an additional property to keep track of the current category we are on.
[06:10] Let's define a new property called "currentCategory." Then, we'll go down here. We will create a method called "setCurrentCategory," that accepts a categoryName.
[06:30] From here, we will return the result of getCategoryByName, pass in the categoryName. We'll take this category that is returned from this. We'll set it to currentCategory.
[07:00] Then, let's define two more methods, which are fairly simple in nature, getCurrentCategory, which just returns currentCategory, and getCurrentCategoryName, which checks to see if currentCategory exists. If it does, it returns currentCategory.name. If not, it just returns an empty string.
[07:39] Now that we have modified the CategoriesModel, now that we have defined the CategoriesModel, let's inject it into the bookmarksListCtrl. Instead of setting this locally, we will pass this into or we will delegate this to the CategoriesModel and pass in the stateParams.category property.
[08:14] From here, while I'm looking at this, let's just update result to bookmarks so that it's a little bit more self-descriptive. Then, we're going to pull some methods off of the CategoriesModel and make them available to the local BookmarksListCtrl. One of them is getCurrentCategory. We'll do the same for getCurrentCategoryName.
[09:00] With that in place, we are ready to actually wire up this template. The first thing we need to do is update this ng-if to target the bookmarksListCtrl.getCurrentCategory. If a current category exists, then, we will show this, as well as this ng-click here to initiate the creation of a bookmark is no longer valid.
[09:32] We're going to replace this with a ui-sref. We're going to navigate to eggly.categories.bookmarks.create. Let's also update the ng-click event for going into the edit state. We will replace this with a ui-sref. We're going to navigate to eggly.categories.bookmarks.edit. We're going to pass in a bookmarkID.
[10:15] Let's go ahead and update this filter here to call getCurrentCategoryName. Let's just do one other thing real quick, since I'm here. Let's go into the categories template.
[10:38] I want to actually allow a click on the logo to reset or go back to the default category state. We'll delete that ng-click. ui-sref. We'll navigate to eggly.categories.
[10:51] I believe I've covered everything. Let's hop into the browser, give this a spin, and see if this is working. We'll select Development, Design. You can see now we're filtering on the current category.
[11:09] I can click the logo, and it goes back to the base category state. From here, if I click "Edit," then, you can see it's navigating to the edit state. I can go back. If I click "Create," then, you can see it's navigating to the create form.
[11:28] We have covered quite a bit of material in this lesson, but the main thing that I'd like to just quickly go over, that we did, is we created some methods on the CategoriesModel to expose the current category that we are on.
[11:47] Then we created two new routes, one to edit a current bookmark and one to create a new bookmark. Stay tuned for the next lessons, where we will continue to finalize the functionality in the Eggly application. See you next time.
Shaun, great content. An architecture / best practice question. With ui-router do you always require one parent with sub nested views or can you have two parents withs ome sort of relationship? Example, could you have 2 categories (not that it would make sense, but for illustration purposes) one for vertical tabs and one for horizontals tabs / states. Left tab would filter subject matter by topic whereas lets say the top categories filters by roles / groups using the bookmarks. So I could end up with sub matter development clicked on left and registered users on top and the result would be the correlation of the two axis in the matrix.
lol and when I say Shaun, I meant Lukas ... apologies.
The code which is available in github is not in sync with the video. In github all the controllers are used as MainCtrl as main and all reference of scope has been changed to main.*. However in the Video it is still showing the old code. Though the code in github is latest and better practise but the same is not captured in the video. I had some tough time in understanding that and had to jump out of the course and watched / read other material to understand.
For the ui router architecture the state's are moved out of the main.js and into they're respective controllers and configured there. I was just wondering if this is the best practice, so that I may continue to do it this way. Thanks!
Also, noticed that the service is written inside of the model, is this also best practice?
About states: yes we really like this approach because it keeps the logic for a particular feature grouped within that feature. It is also congruent with the Angular's implementation of a
component, both in Angular 1 and 2.
About services: this isn't so much a best practice as it is a convenient naming convention. We used the
model naming convention simply because the service is basically
modeling a particular entity (categories or bookmarks). If the service had been handling something like authentication, we would not have used the
model naming convention.