How do I setup ui-router to allow views inheritance? - javascript

How do I setup ui-router to allow views inheritance? Currently, I have my ui-router setup similar to as follows,
$stateProvider
.state('public', {
url: '/public',
templateUrl: 'partials/public.html',
controller: 'PublicController'
})
// abstract parent
.state('private', {
abstract: true,
views: {
'': {
template: '<ui-view></ui-view>'
},
'nav': {
templateUrl: 'partials/nav.html'
}
}
})
// concrete private child state
.state('private.pageone', {
url: '/pageone',
views: {
'': {
templateUrl: 'partials/pageone.html',
controller: 'PageOneCtrl'
}
}
})
Everything is running fine, except that the parent nav view is not being inherited, and so I can't see the nav in the child state display. On the other hand, if I get rid of the parent state and then move the nav view directly to the child state... I can display the nav. Can anybody explain to me why I can't seem to be able to inherit the nav, even though the child is specified as private.pageone (same as parent: 'private').

The docs for ui-router mention that relative views actually target the template in the parent state. So to be able to use relative views in this particular situation we would have to do the following.
$stateProvider
.state('public', {
url: '/public',
templateUrl: 'partials/public.html',
controller: 'PublicController'
})
// abstract parent
.state('private', {
abstract: true,
views: {
'': {
template: '<ui-view></ui-view>'
}
}
})
// concrete private child state
.state('private.pageone', {
url: '/pageone',
views: {
'': {
templateUrl: 'partials/pageone.html',
controller: 'PageOneCtrl'
},
// target the <div ui-view="nav"></div> in the parent template
'nav': {
templateUrl: 'partials/nav.html'
}
}
})
Alternatively, it would be possible to use absolute views instead of relative ones, as in the following.
$stateProvider
.state('public', {
url: '/public',
templateUrl: 'partials/public.html',
controller: 'PublicController'
})
// abstract parent
.state('private', {
abstract: true,
views: {
'': {
template: '<ui-view></ui-view>'
},
// note how nav has been specified absolutely
'nav#private': {
templateUrl: 'partials/nav.html'
}
}
})
// concrete private child state
.state('private.pageone', {
url: '/pageone',
views: {
'': {
templateUrl: 'partials/pageone.html',
controller: 'PageOneCtrl'
}
}
})

Related

How to define multiple views with parent child state using UI router?

Is it possible to define multiple views in child state with parent child state relationship using UI-Router?
I have the following code in my config
$urlRouterProvider.otherwise("/child");
$stateProvider
.state('parent', {
abstract: true,
views: {
'parent': {
templateUrl: "parent.html",
controller: "parentCtrl as parentCtrl"
},
}
})
.state('parent.child', {
url: '/child',
views: {
'state1#parent.child': {
templateUrl: "child.html",
controller: "childCtrl as childCtrl"
},
}
});
I verify that my parent.html is showing up, but my child.html is not
If I move my child.html to the parent views object like
$stateProvider
.state('parent', {
abstract: true,
views: {
'parent': {
templateUrl: "parent.html",
controller: "parentCtrl as parentCtrl"
},
'state1#parent.child': {
templateUrl: "child.html",
controller: "childCtrl as childCtrl"
},
}
})
Than child.html works.
I verify using console.log($state.$current.name); in my parentCtrl that my current state is parent.child.
Can someone give me some hint?
Thanks
There is a working plunker
I adjusted your states and mostly child views : {} like this
$stateProvider
.state('parent', {
abstract: true,
views: {
'parent': {
templateUrl: "parent.html",
controller: "parentCtrl as parentCtrl"
},
}
})
.state('parent.child', {
url: '/child',
views: {
//'state1#parent.child': {
'view1#parent': {
templateUrl: "child.html",
controller: "childCtrl as childCtrl"
},
// the same as view2#parent
'view2': {
templateUrl: "child.html",
controller: "childCtrl as childCtrl"
},
'view3#': {
templateUrl: "child.html",
controller: "childCtrl as childCtrl"
},
}
the construct '...#parent.child' is wrong, because it is a absolute naming... trying to say, that we search a ui-view="..." inside of the 'parent.child' state. And that is not the case.
So, let's place this into index:
// place for parent
<div ui-view="parent"></div>
// place for child view number 3
place in index for view 3
<div ui-view="view3"></div>
And parent template could be like this
<div ui-view="view1"></div>
<div ui-view="view2"></div>
Then the above state def will target view1 with absolute naming, the same for view3 - being in index.html; view2 will go to parent with relative name
check it here

could not resolve state "home.app.detail" from state "home.apps.list", UI-Router

I have a page showing the list of applications that I want to be able to go to the page of the details of the app, when I click on each one of them.
Here is my config:
module bandar {
'use strict';
export class RouterConfig {
/** #ngInject */
constructor($stateProvider: ng.ui.IStateProvider,
$urlRouterProvider: ng.ui.IUrlRouterProvider,
$locationProvider: ng.ILocationProvider) {
$stateProvider
.state('home', {
url: '',
abstract: true,
templateUrl: 'app/components/main/main.html',
controller: 'MainController',
controllerAs: 'mainCtrl'
})
.state('home.apps', {
url: '/apps',
abstract: true,
templateUrl: 'app/components/apps/apps.html',
controller: 'AppsController',
controllerAs: 'appsCtrl',
})
.state('home.apps.list', {
url: '',
templateUrl: 'app/components/apps/list.html',
})
.state('home.app.detail', {
url: '/app/:package_name',
templateUrl: 'app/components/apps/app.html',
controller: 'AppController',
controllerAs: 'appCtrl',
});
$urlRouterProvider.otherwise('/apps');
/*$locationProvider.html5Mode(true).hashPrefix('');*/
}
}
}
And here is the part of the list template which is anchoring to the app's details page:
<a ui-sref="home.app.detail({package_name: app.package_name})">{{app.title}}</a>
But when I hit it in my browser, the following error occurs in the console:
Error: Could not resolve 'home.app.detail' from state 'home.apps.list'
at Object.transitionTo (angular-ui-router.js:3140)
at Object.go (angular-ui-router.js:3068)
at angular-ui-router.js:4181
at angular.js:17682
at completeOutstandingRequest (angular.js:5387)
at angular.js:5659
I guess the problem is UI-Router thinks that I'm pointing at the state relatively, but I wanna do it in the absolute way.
The problem is parent name 'home.app' instead of 'home.apps'
// wrong
.state('home.app.detail', { ...
// should be
.state('home.apps.detail', { ...
because parent is
.state('home.apps', { ...
EXTEND in case, that this should not be child of 'home.apps' we have to options
1) do not inherit at all
.state('detail', { ...
2) introduce the parent(s) which is(are) used in the dot-state-name-notation
// exists already
.state('home', { ...
// this parent must be declared to be used later
.state('home.app', {
// now we can use parent 'home.app' because it exists
.state('home.app.detail', {

Accessing ui-router parent state views from child state

I have some states defined like this:
$stateProvider.state('main.product', {
url: '',
abstact: true,
views: {
'': {
templateUrl: 'product/index.html'
},
'sidebar': {
templateUrl: 'product/sidebar.html'
}
}
});
$stateProvider.state('main.product.overview', {
url: '/products/:product_id',
templateUrl: 'product/overview.html',
controller: 'ProductOverviewController'
});
In my 'main wrapping' controller, i'd like to access the abstract states views, like this:
angular.module('myApp').controller('MainController', function($rootScope, $scope, $state, $stateParams) {
console.log($state.$current.views.sidebar.templateUrl);
});
This works if i'm in the parent state main.product. However, as expected, this returns undefined for the child state, main.product.overview.
How can I access views from a child state?
I know I could use a data object, eg:
$stateProvider.state('main.product', {
url: '',
abstact: true,
views: {
'': {
templateUrl: 'product/index.html'
},
'sidebar': {
templateUrl: 'product/sidebar.html'
}
},
data: {
'sidebar': {
templateUrl: 'product/sidebar.html'
}
}
});
Then access like this:
console.log($state.current.data.sidebar.templateUrl)
But this is not clean, the templateUrl would be duplicated.
Is it possible to access views from a child state?
You can refer to any state by using get method
$state.get('main.product').views.sidebar.templateUrl

Angular js ui-router share controller

I want to give 2 parts of my UI the same controller but still let them have each of their own unique controllers.
$stateProvider
.state('standard.page', {
url: '/:page',
resolve: {
page: function($stateParams) {
...
},
},
views: {
'content': {
templateUrl: '/tmpl/page',
controller: 'controllercontent'
},
'sideMenu': {
templateUrl: '/tmpl/menu',
controller: 'controllermenu',
}
}
})
So I want both content and sideMenu to share a controller. If I add a controller above the views then it requires a new template, I want to use the standard template instead of making a unique template for this state. Any ideas how I can get 3 controllers going in this example? Thanks.
I battled with this at some point in time, and I believe I made a template file that isn't directly accessible (via abstract: true). Here's an example...
.state('standard', {
url: '/standard',
abstract: true,
templateUrl: '/tmpl/standard.html',
controller: 'SharedController'
},
})
.state('standard.page', {
url: '/:page',
resolve: {
page: function($stateParams) {
...
},
},
views: {
'content': {
templateUrl: '/tmpl/page',
controller: 'controllercontent'
},
'sideMenu': {
templateUrl: '/tmpl/menu',
controller: 'controllermenu',
}
}
});
In your tmpl/standard.html file, make sure this exists somewhere within the file:
<div ui-view="sideMenu">
<div ui-view="content">
Hope this points you in the right direction.

angular-ui-router nested views

I have an app with 3 views (A,B,C) and 2 states(1,2)
html
<div ui-view="A"></div>
<div ui-view="B"></div>
<div ui-view="C"></div>
The two states are called list and create. In both states the template and controller of view A + B stay the same but view c should change templates and controllers. I can get view c's content to change but it refreshes view A and view B as it does ie things that are in their controllers run again.
What is the correct way to organise the router to prevent this?
js so far
$urlRouterProvider.otherwise("/basestate/list");
$stateProvider
.state('baseState', function() {
url:"/basestate",
templateUrl: "basestate.html",
controller: 'BaseStateCtrl'
})
.state('baseState.list', function() {
url: "/list",
views: {
"viewA#baseState": {
templateUrl: "viewA.html"
controller: "ViewACtrl"
},
"viewB#baseState": {
templateUrl: "viewB.html"
controller: "ViewBCtrl"
},
"viewC#baseState": {
templateUrl: "list.html"
controller: "listCtrl"
}
}
})
.state('baseState.create', function() {
url: "/create",
views: {
"viewA#baseState": {
templateUrl: "viewA.html"
controller: "ViewACtrl"
},
"viewB#baseState": {
templateUrl: "viewB.html"
controller: "ViewBCtrl"
},
"viewC#baseState": {
templateUrl: "create.html"
controller: "createCtrl"
}
}
})
To achieve that you basically need to freeze your viewA and viewC at the level of baseState and make that state abstract:
.state('basestate', {
url: '/basestate',
abstract: true,
views: {
"viewA": {
templateUrl: "viewA.html",
controller: "ViewACtrl"
},
"viewB": {
templateUrl: "viewB.html",
controller: "ViewBCtrl"
},
"viewC": {
template: '<div ui-view="viewC_child"></div>'
}
}
})
Note that for viewC we are making a placeholder that will contain our nested view (either list or create):
.state('basestate.list',{
url: "/list",
views: {
"viewC_child": {
templateUrl: "list.html",
controller: "ListCtrl"
}
}
})
.state('basestate.create', {
url: "/create",
views: {
"viewC_child": {
templateUrl: "create.html",
controller: "CreateCtrl"
}
}
})
Check this plunkr and be careful with commas in your code :)

Categories

Resources