AngularJS ui-Router Nested Views throwing error: No Such State - angularjs

I'm trying to set up a fairly complex page design with multiple ui-views. I've extracted it to a plunker (http://plnkr.co/edit/DwridY).
I have a main ui-view with several possible templates being loaded. Several of these templates have multiple ui-views of their own, for example:
<h1>Workflows</h1>
<div class="well">
<div ui-view="workflow.list"></div>
</div>
<div class="well">
<div ui-view="workflow.details"></div>
</div>
The angular config lists the states like this:
.state('tasks', {
url: "/tasks",
views: {
"mainView": {
templateUrl: "tasks.html",
controller: "TaskController"
}
}
})
.state("task.list", {
url: "/taskList",
views: {
"task.list": {templateUrl: "task.list.html"},
}
})
.state("workflow", {
url: "/workflows",
views: {
"mainView": {
templateUrl: "workflow.html",
controller: "WorkflowController"
}
}
})
.state("workflow.list", {
url: "/workflowsList",
views: {
"workflow.list": {templateUrl: "workflow.list.html"},
"workflow.details": {templateUrl: "workflow.details.html"}
}
});
The problem is that it works with the workflow state and it's sub-views but not the task state.
When I call:
function TaskController($scope, $state) {
$state.transitionTo("task.list");
}
I get thrown an error:
No such state 'task.list'.
Can anyone see where I'm going wrong?

In general - if there is a . (dot) in the state name - UI-Router expects that it means:
before last dot - parent name (parents if more dots)
after last dot - current state name
so, what we are experiencing above with "task.list" is either
missing state "task" or
declaration "tasks.list" (the parent will be existing "tasks" instead of "task")
Here is the updated and working plunker, where I decided to use tasks as parent:
.state('tasks', {
url: "/tasks",
views: {
"mainView": {
templateUrl: "tasks.html",
controller: "TaskController"
}
}
})
//.state("task.list", {
.state("tasks.list", { // here we inherit from "tasks" not "task"
url: "/taskList",
views: {
"task.list": {templateUrl: "task.list.html"},
}
})

Related

AngularJS router-ui. Load child state in named view on the same level as parent

What i'm trying to do:
<div id="chat">
<div ui-view>Here should people.htm be loaded</div>
<div ui-view="chat">Here is current person chat peopleChat.htm</div>
</div>
I already managed a nested structure. If "chat" is child of "people" - no problem.
But I want em to remain on the same level, but be in a different state. Something like.
$stateProvider
.state('people', {
url: '/people',
templateUrl: ...,
controller: ...
})
.state('people.chat', {
views: {
'chat': {
url: '/:personId',
templateUrl: ...,
controller: ...
}
}
})
My unnamed view is filling with data. After unnamed view is filling, i'm calling $state.go('people.chat', { personId: vm.personId });
But nothing is happening.
Name both views and you are ok:
<div id="chat">
<div ui-view="main">Here should people.htm be loaded</div>
<div ui-view="chat">Here is current person chat peopleChat.htm</div>
</div>
And your controler:
$stateProvider
.state('people', {
views: {
'main#': {
url: '/people',
templateUrl: ...,
controller: ...
}
}
})
.state('people.chat', {
views: {
'chat#': {
url: '/:personId',
templateUrl: ...,
controller: ...
}
}
})
Basically the # absolute targets the view.
Meaning if you use it like chat# it targets the named view chat in the root html.
If you want to nest the views you can use chat#people
which targets the ui-view loaded in the template that people state has injected.
Plunker

How to hide content in the parent view when the user goes to a nested state and show it again when the user backs to the parent one?

I use ui-router and have two nested views.
I’d like to hide some html-content in the parent view when the user goes to child state and show it again when the user backs to parent one.
Could anybody give an advice how to achieve that?
It’s easy to do that using root scope and state change events but it looks like a dirty way, doesn’t it?
app.js
'use strict';
var myApp = angular.module('myApp', ['ui.router']);
myApp.controller('ParentCtrl', function ($scope) {
$scope.hideIt = false;
});
myApp.controller('ChildCtrl', function ( $scope) {
$scope.$parent.hideIt = true;
});
myApp.config(function ($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/');
$stateProvider
.state('parent', {
url: '/parent',
templateUrl: 'parent.html',
controller: 'ParentCtrl'
})
.state('parent.child', {
url: '/child',
template: '<h2>Child view</h2>',
controller: 'ChildCtrl'
});
});
parent.html
<h2>Parent view</h2>
<div ng-hide="hideIt">
<p>This text should be hidden when the user goes to the nested state.</p>
</div>
<a ui-sref="parent.child">Go to the nested view</a>
<div ui-view></div>
One simple solution is to fill ui-view tag in the parent template with the content that you want gone when child state is loaded.
<ui-view>
<h2>Parent view</h2>
<div ng-hide="hideIt">
<p>This text should be hidden when the user goes to the nested state.</p>
<a ui-sref="parent.child">Go to the nested view</a>
</ui-view>
You should check out named views for this. That would probably be the best way to go. https://github.com/angular-ui/ui-router/wiki/Multiple-Named-Views
Also, there's another thread that answered this question over here: https://stackoverflow.com/a/19050828/1078450
Here's the working code for nested named views, taken from that thread:
angular.module('myApp', ['ui.state'])
.config(['$stateProvider', '$routeProvider',
function($stateProvider, $routeProvider) {
$stateProvider
.state('test', {
abstract: true,
url: '/test',
views: {
'main': {
template: '<h1>Hello!!!</h1>' +
'<div ui-view="view1"></div>' +
'<div ui-view="view2"></div>'
}
}
})
.state('test.subs', {
url: '',
views: {
'view1#test': {
template: "Im View1"
},
'view2#test': {
template: "Im View2"
}
}
});
}
])
.run(['$state', function($state) {
$state.transitionTo('test.subs');
}]);
http://jsfiddle.net/thardy/eD3MU/
Edit:
Adding some thoughts re the angular-breadcrumbs comment. I haven't used it myself, but at first glance it seems like subroutes shouldn't break the breadcrumbs. I'm just looking at the source code of their demo, around line 62. I'd have to spin it all up to really go about testing it, but it looks like they're doing almost the same thing with specifying views, and it works there: https://github.com/ncuillery/angular-breadcrumb/blob/master/sample/app.js#L62
.state('room', {
url: '/room',
templateUrl: 'views/room_list.html',
controller: 'RoomListCtrl',
ncyBreadcrumb: {
label: 'Rooms',
parent: 'sample'
}
})
.state('room.new', {
url: '/new',
views: {
"#" : {
templateUrl: 'views/room_form.html',
controller: 'RoomDetailCtrl'
}
},
ncyBreadcrumb: {
label: 'New room'
}
})
.state('room.detail', {
url: '/{roomId}?from',
views: {
"#" : {
templateUrl: 'views/room_detail.html',
controller: 'RoomDetailCtrl'
}
},
ncyBreadcrumb: {
label: 'Room {{room.roomNumber}}',
parent: function ($scope) {
return $scope.from || 'room';
}
}
})
Edit2:
This solution will not combine routes into one crumb
See the official demo
re: But I use angular-breadcrumb and in your solution they will be combined into one crum.

AngularJS UI Router nested view not loading content

I've looked at countless examples of how to set this up. Many right here at SO. But nothing is working in my case. It's a very simple set of two views, one nested below the first. Second ui-view never loads...
Here is the simple index.html...
<body ng-app="d6Games">
<div ui-view="home"></div>
</body>
Here is the simple child view, this is inside home.html template...
<div class="d6body bilbo">
<div ui-view="content"></div>
</div>
Here are the simple states...
.state('home', {
url: '/home',
views: {
'home': {
templateUrl: '/views/home.html'
}
}
})
.state('home.intro', {
url: '/intro',
views: {
'content': {
templateUrl: '/views/game-intro.html'
}
}
})
The first /views/home.html template loads fine, as expected, however the child /views/game-intro.html never loads. It's just html and text and it's in the same folder as home.html.
What am I missing?
There is a working plunker
I just changed the template path (removed the leading '/'), and all is working (however this was required for plunker, not sure about your environment and path settings):
$stateProvider
.state('home', {
url: '/home',
views: {
'home': {
templateUrl: 'views/home.html'
}
}
})
.state('home.intro', {
url: '/intro',
views: {
'content': {
templateUrl: 'views/game-intro.html'
}
}
})
}
Check that in action here

AngularJS with ui-router and additional state on first request

I am writing an AngularJS Application using ui-router. The states 'home' and 'book' are loaded into the (parent) - ui-view element
My setup for the routes is as following :
.config(function ($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise("/home");
$stateProvider
.state('home', {
url: '/home',
templateUrl: '/home2/app'
})
.state('book', {
url: '/book',
templateUrl: '/book/index'
})
.state('book.overview', {
url: '/overview',
templateUrl: '/book/overview'
})
.state('book.edit', {
url: '/edit/:bookid',
templateUrl: '/book/detail',
controller: 'bookeditcontroller'
})
.state('book.create', {
url: '/create',
templateUrl: '/book/detail',
controller: 'bookeditcontroller'
});
});
When the user tiggers the 'book' state (through a href), the template from '/book/index' is loaded and displayed successfully. But on this first request, i also want to load the template from '/book/overview' and displaying it in the child ui-view.
i've already read the topics about the default states under https://github.com/angular-ui/ui-router/wiki/Frequently-Asked-Questions#how-to-set-up-a-defaultindex-child-state
But this is not exactly the behavior i want. Is there a way to tell ui-router when parent state 'book' is loaded, also load 'book.overview' into its (child) ui-view ?
Thanks for you help!
I would say that you will need
Multiple Named Views
This allows us to think in one state - many views
State would look like this
.state('book', {
url: '/book',
views : {
'' : { templateUrl: '/book/index', },
'#book': {templateUrl: '/book/overview' },
}
})
this way, we will place two views into one state.
The first will be injected into index.html/root <div ui-view=""></div>
The second will be placed inside of the templateUrl: '/book/index',
That's how we can play with many views in one (or even more parent, grand parent...) state.
I created a plunker with layout, which does show a bit similar example. The code snippet of the state with many views is:
$stateProvider
.state('index', {
url: '/',
views: {
'#' : {
templateUrl: 'layout.html',
controller: 'IndexCtrl'
},
'top#index' : { templateUrl: 'tpl.top.html',},
'left#index' : { templateUrl: 'tpl.left.html',},
'main#index' : { templateUrl: 'tpl.main.html',},
},
})

Angular UI-Router multiple views

I am using angular UI-Router. I have the following in my route config
.config(function config($stateProvider) {
$stateProvider.state('newsFeedView', {
url: '/newsFeed',
controller: 'newsFeedController',
templateUrl: '../src/app/bulletinBoard/views/newsFeed.part.html',
data: {
pageTitle: 'News Feed'
}
})
.state('tradeFeedView', {
url: '/tradeFeed',
controller: 'tradeFeedController',
templateUrl: '../src/app/bulletinBoard/views/tradeFeed.part.html',
data: {
pageTitle: 'Trade Feed'
}
})
.state('bulletinBoard', {
url: '/bulletinBoard',
views: {
'tradeFeed': {
url: "",
controller: 'tradeFeedController',
templateUrl: '../src/app/bulletinBoard/views/tradeFeed.part.html'
},
'newsFeed': {
url: "",
controller: 'newsFeedController',
templateUrl: '../src/app/bulletinBoard/views/newsFeed.part.html'
}
},
templateUrl: '../src/app/bulletinBoard/views/bulletinBoard.part.html'
});
})
In my index page I just invoke the view using:
<div class="container" ui-view></div>
In My bulletinBoard.html i want to have a nested view:
<div ui-view="tradeFeed"></div>
<div ui-view="newsFeed"></div>
For the /newsFeed page and the /tradeFeed pages this works perfectly but for the bulletin board i can't see anything on the page. Where am i going wrong?
I find the example on the official GitHub wiki to be very unintuitive. Here is a better one:
https://scotch.io/tutorials/angular-routing-using-ui-router
For instance:
...
.state('bulletinBoard', {
url: '/bulletinBoard',
views: {
// the main template will be placed here (relatively named)
'': { templateUrl: '../src/app/bulletinBoard/views/bulletinBoard.part.html' },
// the child views will be defined here (absolutely named)
'tradeFeed#bulletinBoard': { template: ..... },
// another child view
'newsFeed#bulletinBoard': {
templateUrl: ......
}
}
});
The syntax of each view attribute being viewName#stateName.
The .state() method's templateUrl is ignored when using the views object. See the ui-router wiki for more info:
https://github.com/angular-ui/ui-router/wiki/Multiple-Named-Views#user-content-views-override-states-template-properties

Resources