No display when setting up multiple ui-view in index.html - angularjs

I'm trying to implement something as shown in the Multi-Named-Views wiki page of ui-router. The example is the following:
$stateProvider
.state('report', {
views: {
'filters': { ... templates and/or controllers ... },
'tabledata': {},
'graph': {},
}
})
With my current setup as seen below, the routing is not working. Not sure what I'm doing wrong here?
My current index.html looks like this:
<body>
<div ui-view="anonymous"></div>
<div ui-view="home"></div>
</body>
Then my app.js:
app.constant("AccessLevels", {
anon: 0,
user: 1
});
app.config(["$stateProvider", "$urlRouterProvider", "AccessLevels", function ($stateProvider, $urlRouterProvider, AccessLevels) {
/* ANONYMOUS USERS */
$stateProvider
.state('anon', {
abstract: true,
template: '<ui-view/>',
data: {
access: AccessLevels.anon
}
})
.state('anon.login', {
url: '/login',
views: {
anonymous: {
templateUrl: 'Client/scripts/app/partials/account/login.html',
controller: 'loginCtrl'
}
}
})
.state('anon.register', {
views: {
anonymous: {
url: '/register',
templateUrl: 'Client/scripts/app/partials/account/registration.html',
controller: 'registerCtrl'
}
}
});
/* AUTHENTICATED USERS */
$stateProvider
.state('user', {
abstract: true,
template: '<ui-view/>',
data: {
access: AccessLevels.user
}
})
.state('user.home', {
views: {
'home': {
url: '/home',
templateUrl: 'Client/scripts/app/partials/home/dashboard/index.html',
controller: 'homeCtrl'
}
}
})
.state('user.deliveries', {
views: {
'home_content': {
url: '/home/deliveries',
templateUrl: 'Client/scripts/app/partials/home/deliveries/deliveries.html',
controller: 'deliveryCtrl'
}
}
});
$urlRouterProvider.otherwise('/login');
}]);

In general, we can use simplified, so called relative view target names only, if we target the parent. And that is not your case, because
.state('anon', {
abstract: true,
template: '<ui-view/>', // parent contains unnamed view
...
})
.state('anon.login', {
url: '/login',
views: {
anonymous: { // this view is not in parent
So we have to use absolute naming
.state('anon.login', {
url: '/login',
views: {
'anonymous#': { // no we target root
// realtive
'' : { // here we target unnamed parent view
// absolute
'#anon' : { //the same as the line above
A link to doc:
View Names - Relative vs. Absolute Names
Behind the scenes, every view gets assigned an absolute name that follows a scheme of viewname#statename, where viewname is the name used in the view directive and state name is the state's absolute name, e.g. contact.item. You can also choose to write your view names in the absolute syntax.

Related

Nested templates using ui-view

I'm trying to display a nested template using ui-view.
AngularJS routing config
angular.module('myApp')
.config(['$stateProvider', function ($stateProvider) {
$stateProvider
.state('home', {
url: '',
abstract: true
})
.state('home.default', {
parent: 'home',
url: '/home',
data: {
pageTitle: 'Homepage'
},
views: {
'content#': {
templateUrl: 'app/default/default.html',
controller: 'defaultController',
controllerAs: 'defaultController'
}
}
})
.state('default.subview', {
parent: 'default',
url: '/default/subview',
data: {
pageTitle: 'Homepage - subview'
},
views: {
'content#': {
templateUrl: 'app/subview/subview.html',
controller: 'subviewController',
controllerAs: 'subviewController'
}
}
})
;
}]);
Home: /#/home
<!-- this URI should be #/home -->
<h2>Homepage</h2>
<select>
<option>Subview</option>
</select>
<hr>
<!-- nested subview -->
<div ui-view=""></div>
Subview: /#/home/subview
<h2>Subview</h2>
So basically, I want the parent view (home) and subview's content to be included when I visit (/#/home/subview). However, only the subview content is being displayed.
Any tips on how to correctly utilize ui-view and nested subviews in AngularJS?
Your subview has to be a child of home and you set the subview with 'content#' to an defined ui-view wich replaces your view from home.
And I edited some copy paste issue since it looks like your home route was called default before
.config(['$stateProvider', function ($stateProvider) {
$stateProvider
.state('home', {
url: '/home',
abstract: true,
template: '<ui-view/>'
})
.state('home.default', {
url: '/home/default',
data: {
pageTitle: 'Homepage'
},
views: {
'': {
templateUrl: 'home.html',
controller: 'defaultController',
controllerAs: 'defaultController'
}
}
})
.state('home.subview', {
parent: 'home',
url: '/subview',
data: {
pageTitle: 'Homepage - subview'
},
views: {
'': {
templateUrl: 'subview.html',
controller: 'subviewController',
controllerAs: 'subviewController'
}
}
});
}]);
Edit:
I created a Plunker with an working configuration, there was some more issues with that abstract home state (I never get it to work as expected) but if you click the links everything appears as expected.
Plunker
There really is no need for the views section if you have only one ui-view
angular.module('myApp')
.config(['$stateProvider', function ($stateProvider) {
$stateProvider
.state('home', {
url: '',
abstract: true,
template: '<ui-view></ui-view>'
})
.state('home.default', {
// parent: 'home', // No need to set parent if you already prefixed state name
url: '', // The default subview of an abstract view should have '' for url
data: {
pageTitle: 'Homepage'
},
templateUrl: 'app/default/default.html',
controller: 'defaultController',
controllerAs: 'defaultController'
})
.state('home.default.subview', {
// parent: 'default', // No ned for parent
url: '/subview', // Only pu the part of the url here that is added to the parent'ls url
data: {
pageTitle: 'Homepage - subview'
},
templateUrl: 'app/subview/subview.html',
controller: 'subviewController',
controllerAs: 'subviewController'
})
;
}]);
In addition I've also changed the ui-sref in index.html
<a ui-sref="home.default.subview">Subview Route</a>
And the ui-view in home.html
<!-- nested subview -->
<ui-view></ui-view>
Check this plunker:
https://plnkr.co/edit/vEDYvXhp5mNjVT0yLRJN?p=preview

Nested states with parent's url == /

If I have the following state:
$stateProvider
.state( 'home', {
url: '/',
views: {
'dashboard-body': {
templateUrl: './modules/main-dashboard.options.html',
controller: 'MainDashboardController',
controllerAs: 'vm'
}
}
} );
Can it have nested states?... I'm having trouble with it, I have the following states:
$stateProvider
.state( 'home', {
url: '/',
views: {
'dashboard-body': {
templateUrl: './modules/main-dashboard.options.html',
controller: 'MainDashboardController',
controllerAs: 'vm'
}
}
} )
.state( 'home.purchases', {
url: '/purchases',
views: {
'dashboard-body#home': {
templateUrl: './modules/purchases/purchases-dashboard.options.html',
controller: 'PurchasesDashboardController',
controllerAs: 'vm'
}
}
} );
But if i go to home.purchases state the url generated is: http://localhost:3000//purchases
If home.purchases has the property url like: url: 'purchases', it generates the right url http://localhost:3000/purchases but it doesnt't change the view... Any ideas?
If your root view (typically index.html) has the element with
ui-view="dashboard-body"
then your home.purchases state needs to reference that view using
views: {
'dashboard-body#': {
// ...
}
}
Otherwise, it's trying to load the template into a view named dashboard-body within the home state's template (modules/main-dashboard.options.html)

Is there a better way to go about building layouts using ui.router?

I am currently using <div ng-include src="'js/app/partials/layout/header.html'"></div> just above my <div ui-view> in my index.blade.php file while using Angular with Laravel.
I have looked into parent state inheritance in ui.router but it seems to not work, and feels complicated / or perhaps an overkill for layouts. I just want to inject a header and a footer.
This is what I was doing earlier in my attempt to use ui.router states to create a layout injection system. As you can see below.
<div ui-view="header"></div>
<div ui-view></div>
.state('root', {
url: '/',
abstract: true,
views: {
'header': {
templateUrl: 'js/app/partials/header.html'
}
},
data: {
requireLogin: false
}
})
.state('root.login', {
url: '/login',
templateUrl: 'js/app/partials/login.html',
controller: 'LoginCtrl',
data: {
requireLogin: false
}
})
You need to change your structure of your html, by making named views & those will be specified with templateUrl & controller from views option of the state.
Basically inside your home.html you would have three named views such as header, content & footer, root state is setting header & footer templates with controlllers. Then your child state login will set the content view by using absolute state name using content#root in this #root because content named view has been loaded inside root state.
Markup
<div ui-view="header"></div>
<div ui-view="content"></div>
<div ui-view="footer"></div>
Code
myApp.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/login');
$stateProvider
.state('root', {
abstract: true,
url: '/',
//templateUrl: 'js/app/partials/home.html',//remove this
views: {
'': {
templateUrl: 'js/app/partials/home.html' //add it here
},
'header': {
templateUrl: 'js/app/partials/header.html'
},
'footer': {
templateUrl: 'js/app/partials/header.html'
}
},
data: {
requireLogin: false
}
})
.state('root.login', {
url: 'login',
views: {
'content#root': {
templateUrl: 'js/app/partials/login.html',
controller: 'LoginCtrl',
},
},
data: {
requireLogin: false
}
})
});
Working Plunkr
I Think you use this.
`.state('header', {
abstract : true,
templateUrl: 'js/app/partials/header.html'
})
.state('home', {
url: '/',
templateUrl: 'js/app/partials/home.html',
parent : 'header',
data: {
requireLogin: false
}
})
.state('login', {
url: '/login',
parent : 'header',
templateUrl: 'js/app/partials/login.html',
controller: 'LoginCtrl',
data: {
requireLogin: false
}
})`

angular ui router state - multiple states with same template and controller

I have states defined as below in my angularjs app using angular ui router state provider. And, I would like to define multiple states with the same configuration ie. with the same template and controller.
$stateProvider
.state('parent', {
templateUrl: 'parent.html',
abstract: true,
parent: 'apm'
})
.state('parent.list', {
abstract: true,
url: '/list',
templateUrl: 'list.html',
controller: 'ListCtrl'
})
.state('parent.list.closed', {
url: '/q',
templateUrl: 'closed.html'
})
.state('parent.list.details', { // would like to have same template, controller on different state parent.details without list
url: '/:id/:name',
abstract: true,
templateUrl: 'details.html',
controller: 'DetailsCtrl',
resolve: {
.....
.....
}
})
.state('parent.list.details.data', { // would like to have same template, controller on different state parent.details.data without list
url: '/details',
views : {
'view1' : {
templateUrl : 'view1.html'
},
'view2' : {
templateUrl : 'view2.html',
controller : 'View2Ctrl'
},
'view3' : {
templateUrl : 'view3.html'
},
'view4' : {
templateUrl : 'view4.html'
}
}
})
Is it possible to do something like
.state(['parent.list.details', 'parent.details'], {
url: '/:id/:name',
abstract: true,
templateUrl: 'details.html',
controller: 'DetailsCtrl',
resolve: {
.....
.....
}
})
Any help or suggestions?
Each state needs to be defined in it's own .state() method. You will run into multiple problems trying to do it the way you listed above. Most importantly would be the url.
You can simply do this:
.state('parent.list', {
url: '/list',
abstract: true,
templateUrl: 'details.html',
controller: 'DetailsCtrl',
resolve: {
.....
.....
}
.state('parent.list.details', {
url: '/:id/:name',
abstract: true,
templateUrl: 'details.html',
controller: 'DetailsCtrl',
resolve: {
.....
.....
}
})
While the code is not condensed or efficient in the sense you have to declare the controller and partial used on each state, it is necessary because each state needs its own .state() method
I wanted the same and made it like this:
//add a new Function to the object $stateProvider
$stateProvider.states = (statesArr, obj) => {
for (var i in statesArr) {
var state = statesArr[i];
$stateProvider.state(state, obj);
}
return $stateProvider;
};
//use the new function
$stateProvider
.states(["main", "main.test"], {
url: '/main',
templateUrl: 'modules/ViewContainer.html',
controllerAs: 'currentCtrl',
controller: 'MainCtrl'
})

AngularJS. Default child state with named views

I am using UI Router for my application. Their FAQ page covers default child state question, but they are not using named views and i can't figure out how to get this working.
Here are samples of my code:
index.html
<a ui-sref="/">Home</a>
<a ui-sref="topic.basics">Basics</a>
<a ui-sref="topic.payments">Payments</a>
<div ui-view="container" class="container"></div>
app.js
$stateProvider
.state("/", {
url: "/"
})
.state("topic", {
url: "/topic/",
abstract: true,
// ?
})
.state("topic.basics", {
url: "basics/",
views: {
"container": {
templateUrl: "views/basics.html"
}
}
})
.state("topic.payments", {
url: "payments/",
views: {
"container": {
templateUrl: "views/payments.html"
}
}
});
$urlRouterProvider
.when("/topic/", "/topic/basics/")
.otherwise("/");
You are almost there, but because the view target is not a parent, but index.html, we have to use aboslute naming
.state("topic.basics", {
url: "basics/",
views: {
// instead of this, which targets the parent
// "container": {
// we need this, where string empty after # means root/index.html
"container#": {
templateUrl: "views/basics.html"
}
}
})
.state("topic.payments", {
url: "payments/",
views: {
// "container": {
"container#": {
templateUrl: "views/payments.html"
}
See
View Names - Relative vs. Absolute Names
Behind the scenes, every view gets assigned an absolute name that follows a scheme of viewname#statename, where viewname is the name used in the view directive and state name is the state's absolute name, e.g. contact.item. You can also choose to write your view names in the absolute syntax.
For example, the previous example could also be written as:
.state('report',{
views: {
'filters#': { },
'tabledata#': { },
'graph#': { }
}
})
Make the base home state abstract and remove the / in front of the /topic you already use this in the base route.
$stateProvider
.state("home", {
name: 'home',
abstract: true,
url: "/"
})
.state("topic", {
name: 'home.topic',
url: "topic/"
})
.state("topic.basics", {
url: "basics/",
name: 'home.topic.basics'
views: {
"container": {
templateUrl: "views/basics.html"
}
}
})
.state("topic.payments", {
url: "payments/",
name: 'home.topic.payments',
views: {
"container": {
templateUrl: "views/payments.html"
}
}
});
$urlRouterProvider.otherwise("/");

Resources