I have a parent route which loads a list of objects in the resolve function. After the user selects a item of this list it loads the child route. The child route appends the itemId to the url. Now I would like that the parent automatically "redirects" to the first item of the list and therefore change to the child route.
I tried calling $state.go in the resolve function after the promise was resolved but that started a endless redirect cycle.
Here is my current setup.
$stateProvider.state("parent", {
url: "/parent/:parentId/children",
templateUrl: "parentTempl.html",
controller: "ParentController",
controllerAs: "vm",
resolve: {
ParentLoadingService: function ($stateParams, ResourceService) {
return ResourceService.request.getChildren({ parentId: $stateParams.parentId }).$promise;
}
}
}).state("parent.child", {
url: "/:childId",
templateUrl: "child.html",
controller: "ChildController",
controllerAs: "vm",
resolve: {
ChildLoadingService: function ($stateParams, ParentLoadingService) {
...
}
}
});
thanks
Related
I have a working app though I am changing the architecture, cutting views down into smaller, more manageable documents. I currently have a state with a child state.
.state('patents', {
url: '/patents',
templateUrl: 'p3sweb/app/components/patents/views/list-patents.htm',
controller: 'listPatentsCtrl',
controllerAs: '$ctrl',
})
.state('patents.patent', {
url: '/{patentId}/:patentHref',
templateUrl: 'p3sweb/app/components/patents/views/patent-item.htm'
})
When I click on a table row in state patents, up pops patents.patent view below it.
I have now changed it so the child patents.patent state has multiple views like so:
.state('patents.patent', {
url: '/{patentId}/:patentHref',
templateUrl: 'p3sweb/app/components/patents/views/patent-item.htm',
views: {
'#': {
templateUrl: 'p3sweb/app/components/patents/views/patent-item.htm'
},
'patentinfo#patents.patent': {
templateUrl: 'p3sweb/app/components/patents/views/ui-views/patent-info.htm',
controller: 'patentInfoCtrl',
controllerAs: '$ctrl'
},
'patentcostanalysis#patents.patent': {
templateUrl: 'p3sweb/app/components/patents/views/ui-views/patent-costanalysis.htm',
controller: 'patentCostAnalysisCtrl',
controllerAs: '$ctrl'
},
'patentrenewals#patents.patent': {
templateUrl: 'p3sweb/app/components/patents/views/ui-views/patent-renewals.htm',
controller: 'patentRenewalsCtrl',
controllerAs: '$ctrl'
}
})
When I now click on the row in state patents, the patents.patent view replaces the parent view. So instead of displaying below it, it's the only view displayed.
Question
How do I resolve the issue that has occurred now I have included multiple views in patents.patent state?
So it turns out, after reading ui-router wiki, using # creates an absolute path, and I wasn't targeting the view in the parent state patents.
So instead of
views: {
'#': {
templateUrl: 'p3sweb/app/components/patents/views/patent-item.htm'
}
It should of been
views: {
'#patents': {
templateUrl: 'p3sweb/app/components/patents/views/patent-item.htm'
}
I am attempting to set up nested views loading in the parent views via state children but I'm not sure if I'm going about this the correct way.
So far, I have:
$stateProvider
.state('splash', {
url: '/splash',
templateUrl: 'system/templates/splash.html',
controller: ""
}).state('home', {
url: '/',
templateUrl: 'system/templates/home.html',
controller: ""
}).state('user', {
url: '/user/:user?',
templateUrl: 'system/templates/user.html',
controller: "userController"
}).state('user.data', {
views: {
"#vdata" : {
templateUrl: 'system/templates/user.html',
controller: "userController"
}
}
})
The "user" parent state recieves :user? the correct way, however when I try to navigate via $state.transitionTo();, I get the response of
Param values not valid for state 'user.data'. I have an unnamed view with the pattern
<div ui-view></div>
set as the parent. Then nested in the user template, I have a ui-view called "vdata". According to the documentation, if I target #vdata, the pages requested should be loading there.
How can I get the nested view to inherit the parameter from the parent view?
Use resolve and inject user on controller. The resolved references are shared betwen parent child states.
$stateProvider
.state('splash', {
url: '/splash',
templateUrl: 'system/templates/splash.html',
controller: ""
}).state('home', {
url: '/',
templateUrl: 'system/templates/home.html',
controller: ""
}).state('user', {
url: '/user/:user?',
templateUrl: 'system/templates/user.html',
controller: "userController",
resolve:{
user: function($stateparams){
return $stateParms.user;
}
}
....
On usercontroller inject user
I would like to create an abstract parent state, that has only one job: to resolve the current user through an ajax server call, and then pass this object to the child state. The problem is that the child state never gets loaded. Please have a look at this plunker: Example
a state
angular.module('test', ['ui.router'])
.config(function($stateProvider, $urlRouterProvider){
// Parent route
$stateProvider.state('main', {
abstract:true,
resolve: {
user: function(UserService){
return UserService.getUser();
}
}
});
// Child route
$stateProvider.state('home', {
parent: 'main',
url: '/',
controller: 'HomeController',
controllerAs: '$ctrl',
template: '<h1>{{$ctrl.user.name}}</h1>'
});
$urlRouterProvider.otherwise('/');
});
a factory
angular.module('test').factory('UserService', function($q){
function getUser() {
var deferred = $q.defer();
// Immediately resolve it
deferred.resolve({
name: 'Anonymous'
});
return deferred.promise;
}
return {
getUser: getUser
};
});
a controller
angular.module('test').controller('HomeController', function(user){
this.user = user;
});
In this example, the home state will never display the template, I don't really understand why. If I remove the parent: 'main' line, then it displays the template, but of course I get an error because it cannot find the user dependency in the HomeController.
What am I missing? I did everything like it is described in ui-router's documentation, I think this should work.
Every parent must have a target ui-view in template for its child
$stateProvider.state('main', {
abstract:true,
resolve: {
user: function(UserService){
return UserService.getUser();
}
}
template: '<div ui-view=""></div>'
});
NOTE: Another option is to use absolute names and target index.html .. but in this case the above is the way to go (Angularjs ui-router not reaching child controller)
I'm trying to perform a resolve on state change to get data I want to inject in a controller which uses "multiple" views. The reason for having nested views is because the template/app.html contains a <ion-side-menu>, and I want to resolve data inside the <side-menu-content>.
CODE
module configuration:
$stateProvider.state('app', {
url: '/app',
abstract: true,
templateUrl: 'template/app.html'
})
.state('app.list', {
url: '/list',
views: {
'maincontainer#app': {
controller: 'listctrl',
templateUrl: 'template/list.html',
resolve: {
item: function(dataservice) {
return dataservice.getItems();
}
}
}
},
resolve: {
auth: auth
}
});
controller:
angular.module('controller', []).controller('listctrl',
['$scope', function($scope, items){
console.log(items); // prints undefined
}]);
PROBLEM
The problem is that the resolved items is never injected into the controller, though the item function is resolved.
I've been thinking about maybe having to store the data in local storage when resolved, and getting the items back again from the controller. I'd prefer if I didn't have to go that route (pun intended).
You have to actually inject the items.
angular.module('controller', []).controller('listctrl',
['$scope', "items", function($scope, items){
console.log(items); // prints undefined
}]);
I was trying to wrap my head around ui-router and I've tried to implement the following logic:
if there is no state, go to state /items
when processing /items, retrieve a list of "items" from the server
when "items" are received go to state /items/:item, where "item" is the first in the list of items, returned by the server
in state /items/:item render a list of items with the corresponding "item" being "highlighted" (the highlighting part is not included in my code)
However, the child state's "controller" function is not executed. I bet it's something really obvious.
Here's the js (I also have it on plunkr with the accompanying templates).
angular.module('uiproblem', ['ui.router'])
.config(['$stateProvider', '$urlRouterProvider',
function ($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/items');
$stateProvider
.state('items', {
url: '/items',
resolve: {
items: function($q, $timeout){
var deferred = $q.defer();
$timeout(function() {
deferred.resolve([5, 3, 6]);
}, 1000);
return deferred.promise;
}
},
controller: function($state, items) {
// We get to this point successfully
console.log(items);
if (items.length) {
// Attempt to transfer to child state
return $state.go('items.current', {id: items[0]});
}
}
})
.state('items.current', {
url: '/:id',
templateUrl: 'item.html',
controller: function($scope, items) {
// This is never reached, but the I can see the partial being
// loaded.
console.log(items);
// I expect "items" to reflect to value, to which the "items"
// promise resolved during processing of parent state.
$scope.items = items;
}
});
}]);
Plunk: http://plnkr.co/edit/K2uiRKFqe2u5kbtTKTOH
Add this to your items state:
template: "<ui-view></ui-view>",
States in UI-Router are hierarchical, and so are their views. As items.current is a child of items, so is it's template. Therefore, the child template expects to have a parent ui-view to load into.
If you prefer to have the child view replace the parent view, change the config for items.current to the following:
{
url: '/:id',
views: {
"#": {
templateUrl: 'item.html',
controller: function($scope, items) {
// ...
}
}
}
}