This lesson is for PRO members.

Unlock this lesson NOW!
Already subscribed? sign in

AngularJS Architecture: Using ui-router's named views

8:03 Angular 1.x lesson by

We'll take a deeper look at ui-router as we introduce named views into Eggly. We will take the basic state that we defined in the previous video and refactor it so that it consists of two unique views within the application.

Get the Code Now
click to level up

egghead.io comment guidelines

Avatar
egghead.io

We'll take a deeper look at ui-router as we introduce named views into Eggly. We will take the basic state that we defined in the previous video and refactor it so that it consists of two unique views within the application.

Avatar
Danny

in categories.js, by injecting $stateProvider a dependency on the ui.router module created. Should that be made explicit in the module definition? (again in later video in the series when injecting the $state service into a controller.)

// categories.js
angular.module('categories', [
  'eggly.models.categories',
  'ui.router'  // <= required
])
In reply to egghead.io
Avatar
Joel

It isn't required, but if you want to test the controller/module later it will throw an error.

I've also run into order-of-operations issues with the top level app module ui.router import. It needs to be above modules that require it.

So, with those two things in mind, it is a good idea to explicitly declare a module's dependencies.

In reply to Danny
Avatar
Fang

what's interesting to me is that MainCtrl is parent of two ui-views which convert to BookmarkCtrl and CategoryCtrl, so how does the scope work ?

because in the BookmarkCtrl template, ng-repeat needs to ask $scope.bookmarks, is the bookmarks here same as the one in the MainCtrl ?

maybe you will talk about in the next video :)

In reply to egghead.io
Avatar
James

So, I get that a lot of people wonder how to handle sub views and the like in angular, but is this not what directives and transclusion are for? I know that for many people directives are the 'hardest' part of angular to learn but as a teaching resource would it be better to point people to directives as a solution to their problem?

Im just curious about the decision process for using ui-router for this feature? (Its better then ng-route just because of the ui-serf function but Im not sold on named views).

Nice demo though :) Keep up the good work.

Avatar
Robbie

Hi, Ive been having real problems on this section. Up to the start of the video I had everything working has planned. By the time I end this video I get almost nothing (other than the background css stuff main body/sidebar.)

Whats weird is that if I put my no named ui-view back in to the container-fluid, and keep my first view as
.state('eggly',{
url:' ',
templateUrl:'app/categories/categories.tmpl.html',
controller:'MainCtrl'
});
})
then I can get the body of the site to display whatever I want in the categories.tmpl.html.

However when I take the no named ui-view away I get blank. I've even tried copying code across from you completed code but still no luck. Do you know how I can go about debugging? There are no errors in console.

In reply to egghead.io
Avatar
Mike

I was just going through this today and ran into the same issue. The problem for me was that while writing the views in the categories.js file I copied the first
'categories@': {
controller: 'CategoriesCtrl',
templateUrl: 'app/categories/categories.tmpl.html'
},
to make the bookmarks but didn't update the templateUrl to account for the fact that the bookmarks.tmpl.html was inside the bookmarks folder and not the categories folder. After fixing this error I got everything working as normal. It's a long shot if that's your problem but it just happened to explain the exact same problem I was having. So maybe the solution will be the same :)

In reply to Robbie
Avatar
Joel

ui-routers #1 flaw IMO is the debugging. It fails silently providing no context for debugging. If a view is specified, but no matching target is found, it doesn't say a word!

These errors are almost always a missing ui-view or there is a string with a typo someplace.

Regardless, it is impossible to debug this without the code in context!

Avatar
Guillaume

Question. I have almost the same setup, a main app with submodules, I use ui.router in all the submodules. But I couldn't make it work initially, I had a loading module error from Angular. I was able to solve it by putting ui.router as the first dependency in the main module. But I don't understand why it works. If I put my submodules first and ui.router after in the main module, then I have to redefine the ui.router dependency in my submodules. If I put ui.router first, then I don't need. I'm surprised. I'm sure I'm missing something simple here, any idea? Thanks!

Avatar
Tom

@Robbie
I had the same issue and after about 1/2 hour of individually inspecting every character and comparing with the vid I realised I had "view" instead of "views" in the categories.js state definition.

In reply to Robbie
Avatar
Paul Mark Quinn

It was bizarre for me in that, it would only work after I actually removed abstract and url from the base module state config:

.config(function ($stateProvider, $urlRouterProvider) {
$stateProvider
.state('eggly', {
//url : '/',
//abstract : true
})
;

$urlRouterProvider.otherwise('/');

})

Avatar

Good call. Same situation here. The commenting out worked.

In reply to Paul Mark Quinn
Avatar
Aaron Endsley

Im getting an injector error saying $urlRouteProvider

In reply to
Avatar
Aaron Endsley

Ha Ha Never Mind I Mistyped its supposed to be $urlRouterProvider

In reply to Aaron Endsley

In this lesson, we are going to really tap into the power of ui-router with named views. In the previous lesson, we created a single, simple route and moved our main layout into an HTML template.

We are going to take that a step further by separating that template into two templates, a category template and a bookmarks template, and then defining a separate view for each of them.

When working with a large application, it is often a good idea to define a top-level, abstract state that defines the base layout, as well as any additional information that you want the child states to draw from.

Let's take a quick moment and refactor the Eggly state to be an abstract state that we can use as a starting point for the additional states that we're going to define. We're also going to set up a fallback to redirect the user with one additional service called "urlRouterProvider."

I am going to inject urlRouterProvider, and then from here, we're just going to say, "Abstract is true." I'm going to say, "Otherwise, just redirect to the root of the application."

Now that we've done that, let's refactor our categories template that just contains everything here into two specific templates. In categories, I'm going to just copy this right here, and I'm going to paste this up here.

Then, for the bookmarks, I'm going to copy the bookmark-specific stuff, and I'm going to paste this into the bookmarks template.

Now, we are left with this remaining container HTML. We are going to go back into our main HTML file and paste this into here. Let's delete this unnamed ui-view here, and let's create two named views.

This is where we want the categories to go. We're going to go ui-view. This takes a property here of categories, and then let's do the same for bookmarks, ui-view.

Now that we have named ui-views, we need to define corresponding views and our stateProvider to match up. We'll hop into our categories and define an Eggly category state that we can attach our views to.

We will inject our stateProvider.

We will give this the URL of the root of the application, and then we are going to define our views property. This is going to be just an empty object initially, but we need the keys on the views object to match up to our named view, so categories and bookmarks.

We'll go categories.

We are adding the at symbol to make this an absolute path, meaning that it will target this named view specifically with any unnamed state within our main page.

This allows us to go as far as defining specific configurations or a specific view and a specific state. More on that later. From here, it's pretty much like defining a normal route. We will define our controller and template URL, and we should be ready to go.

We will do the same for our bookmarks.

The categories controller and the bookmarks controller doesn't actually exist yet, so let's just define just a real quick stub of those. We'll go controller.

Let's do the same for the bookmarks controller.

We should be good to go. Let's go back into the browser and refresh. You can see that the page is still rendering, but if we actually inspect the element here, we can see that it's actually targeting the categories ui-view and the bookmarks ui-view.

Just a quick recap. We refactored the Eggly state to be abstract, as well as we introduced urlRouterProvider to redirect to the root of the application.

We then refactored the categories template, or the main template, to have two separate templates, categories and bookmarks, and then, in the main index page, we introduced two ui-views, ui-view categories, ui-view bookmarks.

Then, from here, we defined the eggly.categories state with the URL of the root of the application and then two absolute views targeting the categories named view, the bookmarks named view, and the controller and the template for each of those views.

I look forward to seeing you in the next lesson, where we are going to introduce stateParams so we can pass specific information from one state to another. See you then.

HEY, QUICK QUESTION!
Joel's Head
Why are we asking?