Angular ui-router nested states without nested views - angularjs

Let's say I have a films app. It has Home/About/Films pages. Films page has subcategories: Comedy/Drama. Currently, I'm struggling with navigation. The Goal is when I click Home - it should render home. About - about. Films - render all films (for example simple cards with title/genre/year). When I click Films->Comedy - it should use the same controller as Films, render exactly same template but only comedy films. Moreover, navigation should be active with Films and Comedy.
I've created plunker to demonstrate first approach https://plnkr.co/edit/d0Db18ZJYtQx6aJEZ3xa?p=preview
So my first approach was:
.state('layout.films', {
url: '/films',
controller: 'FilmsCtrl as films',
template: '<div>All films</div>'
})
.state('layout.films.genre', {
url: '/:genre',
controller: 'FilmsCtrl as films',
template: '<div>{{ films.genre }} films</div>'
})
and this layout:
<div class="layout">
<ul>
<li><a ui-sref-active="_active" ui-sref="layout.home">home</a></li>
<li><a ui-sref-active="_active" ui-sref="layout.about">about</a></li>
<li>
<a ui-sref-active="_active" ui-sref="layout.films">films</a>
<ul>
<li><a ui-sref-active="_active" ui-sref="layout.films.genre({genre: 'comedy'})">comedy</a></li>
<li><a ui-sref-active="_active" ui-sref="layout.films.genre({genre: 'drama'})">drama</a></li>
</ul>
</li>
</ul>
<hr>
<div ui-view></div>
</div>
But that doesn't work. Turns out to be that nested states requires nested views. I was sad. And tried second approach: https://plnkr.co/edit/3YWAoLcPU3fd2FdebWpD?p=preview
I created only one films state:
.state('layout.films-genre', {
url: '/films/:genre?',
controller: 'FilmsCtrl as films',
template: '<div>{{ films.genre }} films</div>'
})
And fixed layout to work with this:
<a ui-sref-active="_active" ui-sref="layout.films-genre">films</a>
<ul>
<li><a ui-sref-active="_active" ui-sref="layout.films-genre({genre: 'comedy'})">comedy</a></li>
<li><a ui-sref-active="_active" ui-sref="layout.films-genre({genre: 'drama'})">drama</a></li>
</ul>
Seems working. It even highlights menu items properly (wow). But actually... I can't change state from films->comedy to films. Next thought was to change the link to the all films:
<a ui-sref-active="_active" ui-sref="layout.films-genre({genre: ''})">films</a>
But now it doesn't highlight root menu item (films) when I click one of the genres. What should I do to implement desired behavior?

If I understand your question correctly, you want to have a page that can render a specific genre of films?
If so, I think you should look up stateParams. This way you could have a menu that all directs to the same child view, but sends different parameters. Then sort the list of movies accordingly to the params being sent.
It would look something like this:
.state('layout.films-genre', {
url: '/films',
controller: 'FilmsCtrl as films',
template: '<div> Template goes here </div>'
params: { genre: 'all' } // as default if I remember correctly
})
You might aswell find the answer to your question here:
How to pass parameters using ui-sref in ui-router to controller

Related

ui-sref is not working properly

ui-sref in my application is working partially. Mean for some link it is generating href but for other's not. below is my code:-
// for ng-repeat it is not working but for others it is working.
<nav class="site-links" ng-controller="itemsController">
<ul class="nav-links">
<li ng-repeat="item in items">
<a ui-sref="{{item.link}}">
<span>{{item.Description}}</span>
</a>
</li>
<li><a ui-sref="index">Home</a></li>
<li><a ui-sref="route1">Route 1</a></li>
<li><a ui-sref="route2">Route 2</a></li>
</ul>
Could you take a look??
Provided you have the following routes defined in you router:
$stateProvider
.state( 'testState', {
url: '/test',
templateUrl: 'app/templates/test.html',
controller: 'testController'
});
You can link to this state via the ui-sref directive ONLY by its name. So, the following is valid:
<a ui-sref="testState">Something</a>
Something <!-- Notice the difference. Here we're using the reference to the route. -->
So, for the ui-sref you need to tell it the NAME of the state and for the normal href, a simple route is fine.

multiple nested views with their own router

I am building an angular app with nested views using ui-router. The app has a list of posts, each with its own Nav menu to change the post's view.
To simplify the context, lets just say that each nav menu can change the theme of the post it is attached to.
POST 1 CONTENT
[Light theme button] [Dark theme button]
--------------------------------------------
POST 2 CONTENT
[Light theme button] [Dark theme button]
--------------------------------------------
*
*
*
The problem I am facing is when I press a button on one post's nav menu, all the posts change.
I want the nav menu for each post only to effect its respective post.
I am a total beginner to angular and my questions are:
Is this a problem i would want to solve with ui-router? (do i want to
have a router for each post?)
If it is, how do i solve it?
If not, can you point me in the right direction?
any help is appreciated, whether it is a link, explanation, code or just a comment.
PS. in reality i am not just changing the theme, i am changing the content on the post completely. In the future i want to implement more than just 2 options menu options.
here is the code that i am using now (modified a bit to remove redundancy):
Main.js:
angular.module('app',['ui.router'])
.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/postlist');
$stateProvider
.state('postlist', {
url: '/postlist',
templateUrl: 'ListView.html',
controller: ListCtrl
})
.state('postlist.light', {
templateUrl: 'pollViewLight.html',
controller: PollLightCtrl
})
.state('postlist.dark', {
templateUrl: 'pollViewDark.html',
controller: PollDarkCtrl
})
});
simplified part of index.html:
<nav>
<ul>
<li><a ui-sref="postlist">Post List</a></li>
</ul>
</nav>
<div class="container">
<div ui-view></div>
</div>
ListView.html:
<div class="row" ng-repeat="post in posts">
<div class="col">
<div ui-view></div>
<ul class="nav nav-pills">
<li><a ui-sref=".light">Light Theme</a></li>
<li><a ui-sref=".dark">Dark Theme</a></li>
</ul>
</div>
</div>

AngularJS UI Router - Nested state with individual views

I have a menu on my website, where the items have an active state. The default state is areas, then I can navigate through my website changing states.
<li ui-sref-active="active">
<a ui-sref="areas">
<span>Areas</span>
</a>
</li>
.state('areas', {
url: '/areas',
templateUrl : 'templates/areas.html',
controller : 'AreaCtrl'
})
In my areas.html template, I have a list, with items which can be clicked...:
<li ng-repeat="area in areas" ui-sref="areas.city({areaId: area.area_id, areaName: area.name})">
Now when one of these is clicked, I need to keep the active state on my menu. So the only way of doing this is via nested states...
.state('areas.city', {
url: "/:areaId/:areaName",
templateUrl: 'dist/templates/cities.html',
controller: 'CityCtrl'
})
However the problem is, my cities.html needs to be a totally new view (in place of where areas.html is), which isn't nested within areas (so I don't have a <ui-view> within areas.html).
I can, just not nest the view, so the state is .state('city', but then I lose the active state on the menu.
Any clue how I get around this?
You can activate the state in the main menu as like below
<li ng-class="{active: $state.includes('area') || $state.includes('areas.city')}">
<a ui-sref="areas">
<span>Areas</span>
</a>
</li>
Also, please apply the $state into $rootScope. So that you can access $state in any views.
myApp.run(function($rootScope, $state) {
$rootScope.$state = $state;
});

ui-router active class for parent menu when submenu selected

I am a newbie to ui-router , i would like to get a menu like below (its not a collapse thing, please see the plnkr )
menu1
a) submenu1
b) submenu2
c) submenu3
menu2
menu3
I managed to get the menus and submenus using the ui-router but not sure about the proper way to use the ui-router and used ui-sref-active="active" active the menu , the problem am facing is when I click on the submenu i would like to get the active to parent also.. ie if I click submenu1 , submenu2 or submneu3 i want to active its parent menu1.
here is the plunker : http://plnkr.co/edit/1kpmUiacrb3Aoo4E19O1?p=preview
There is an updated plunker, which does use the $state.includes method as defined here
Angular UI Router: How do I get parent view to be "active" when navigating to nested view?
the changes are: menu gets controller which puts $state into $scope:
"menu#dashboard": { templateUrl: "menu.html",
controller : function ($scope, $state){ $scope.$state = $state },
},
instead of this:
<li ui-sref-active="active"><a ui-sref=".menu1.submenu1">Menu 1</a></li>
<li ui-sref-active="active"><a ui-sref=".menu2">Menu 2</a></li>
<li ui-sref-active="active"><a ui-sref=".menu3">Menu 3</a></li>
we have to use defintion with ng-class:
<li ng-class="{active:$state.includes('dashboard.menu1')}"><a ui-sref=".menu1.submenu1">Menu 1</a></li>
<li ng-class="{active:$state.includes('dashboard.menu2')}"><a ui-sref=".menu2">Menu 2</a></li>
<li ng-class="{active:$state.includes('dashboard.menu3')}"><a ui-sref=".menu3">Menu 3</a></li>
BUT: this feature would be in a next ui-router release as we can see here:
feat(uiSrefActive): Also activate for child states.
cite
To limit activation to target state use new ui-sref-active-eq directive
Breaking Change: Since ui-sref-active now activates even when child states are active you may need to swap out your ui-sref-active with ui-sref-active-eq, thought typically we think devs want the auto inheritance.

angular-ui-router dynamic menu: TypeError: Cannot call method 'match' of undefined while rendering menu

i am new to angular and angular-ui-router and trying to create a menu.
I tried angular-ui-router and think that it fits for my needs.
now i have a problem while creating the menu with the ui-router attributes.
my html code looks like that:
<div ng-controller="MenuCtrl">
<ul>
<li ng-repeat="item in menu">
<a ui-sref="cf.{{item}}">{{item}}</a>
</li>
</ul>
</div>
the menu array contains different entries dependent on the info if the user is logged in.
now i get this error message:
TypeError: Cannot call method 'match' of undefined
<a ui-sref="cf.{{item}}" class="ng-binding">
It looks like ui-router tries to get access to the list entry before it is rendered complete with ng-repeat.
What can i do to prevent this problem?
So ui-router doesn't support interpolation in ui-sref, believe me I wish they would. Here is how I solved this.
In your controller:
app.controller("MenuCtrl", ['$scope', '$state', function($scope, $state) {
$scope.$state = $state;
}]);
In your view use an ng-href to evaluate $state object that we've now added to the $scope:
<div ng-controller="MenuCtrl">
<ul>
<li ng-repeat="item in menu">
<a ng-href={{ $state.href('cf.' + item) }}>{{item}}</a>
</li>
</ul>
</div>
You can also you this technique for wildcard params:
ng-href="{{ $state.href('cf.items.item', {'item' : item} ) }}"
Assuming you've set up your ui-router routes properly for this.

Resources