How to modify url of a state in AngularJS ui-routes - angularjs

I am on angular 1.6. Trying to override value of a ui-router state.
Initial states as follows :
$stateProvider.state('parent', {
abstract: true,
parent: 'ancestor',
url: '/parent',
data: {
authorities: [A,B]
},
views: {
'content#': {
templateUrl: 'app/scripts/myapp/module/parent.html'
}
}
})
.state('child', {
parent: 'parent',
abstract: true,
views: {
'tabs': {
templateUrl: 'app/scripts/myapp/module/submodule/child.html',
controller: 'ChildController',
controllerAs: 'childController'
}
}
})
.state('grandChild', {
parent: 'child',
url: '/{dataSource:(?:option1|option2|option3)}',
views: {
'body': {
templateUrl: 'app/scripts/myapp/module/submodule/grandchild.html',
controller: 'GrandChildController',
controllerAs: 'grandChildController'
},
},
resolve: {
groups: ['MyService', '$transition$', function (MyService, $transition$) {
var selectedSource = $transition$.params().dataSource ? $transition$.params().dataSource : 'option1';
return MyService.getGroups(selectedSource);
}]
}
})
Then in one of sub-implementation I am trying to override value of url - adding option4 for one of the state.
var states = $stateRegistry.deregister('grandChild');
$stateRegistry.register(states[0]);//There is one more child. For simplicity not showing here.
states[1].url.pattern = '/{dataSource:(?:option1|option2|option3|option4)}';
$stateRegistry.register(states[1]);
when I do following on 'grandChild'
$state.go('grandChild', {dataSource: 'option4'});
I get error as
Param values not valid for state 'grandChild'. Invalid params: [ dataSource ]
when I inspect $state
I see something weird.
$state.$current.params.datasource.type.pattern = /(?:option1|option2|option3)/
$state.$current.url.pattern = "/{dataSource:(?:option1|option2|option3|option4)}"
$state.$current.url._compiled[0] = /((?:option1|option2|option3))/

Related

How do I get URL parameters on AngularJS SPA when using stateProvider for routing

For example, on the last state on the below code I want to get the value of "category" URL parameter so that I can use it to retrieve some from the database
var app = angular.module("myApp",["ui.router"]);
app.config(function($stateProvider, $urlRouterProvider){
$urlRouterProvider.otherwise("/");
$stateProvider
.state("main", {
url: "/",
views: {
"slider": {
templateUrl: "slider.html"
},
"departments": {
templateUrl: "departments.html"
},
"brands": {
templateUrl: "brands.html"
}
}
})
.state("cart", {
url: "/cart",
views: {
"cart": {
templateUrl: "../account/cart.php"
}
}
})
.state("department", {
url: "/department/:category",
views: {
"department": {
templateUrl: "department.php"
}
}
});
});
Create a controller, pass stateParams and instantiate the controller within the views of the last state
.state("department", {
url: "/department/:category",
views: {
"department": {
templateUrl: "department.php",
controller: "myController"
}
}
});
});
app.controller('myController', function($stateParams) {
var param = $stateParams.category;
document.getElementById("category").value = param;
});

AngularJS uiRouter access controller from other view

I have simple hierarchical state:
angular
.module('App.Module.Suppliers', [])
.config(function($stateProvider) {
return $stateProvider
.state('suppliers', {
url: '/suppliers',
views: {
main: {
templateUrl: 'views/layouts/wrapper.html'
}
}
})
.state('suppliers.edit', {
url: '/:id',
views: {
entity_view: {
templateUrl: 'views/layouts/foo.html'
}
}
})
.state('suppliers.edit.details', {
url: '/edit',
views: {
entity_sub_view: {
controller: function () {
this.foo = {bar: "TEST HEADER"};
},
controllerAs: 'vm',
templateUrl: 'views/layouts/main.html'
}
}
});
});
main and entity_view views are generic for all entities and only entity_sub_view changes with core information.
Now in entity_view I want to use some value like <h2>{{vm.foo.bar}}</h2> but it seems that I can't access vm inside these parent states.
Is there a way to pass this and other parameters to parent states to use?
So I found solution that fits my need. Basically you can set controllerAs to top-most state and access it via $scope:
angular
.module('App.Module.Suppliers', [])
.config(function($stateProvider) {
return $stateProvider
.state('suppliers', {
url: '/suppliers',
views: {
main: {
templateUrl: 'views/layouts/wrapper.html'
controller: function () {
this.foo = null;
}
controllerAs: 'mainCtrl'
}
}
})
.state('suppliers.edit', {
url: '/:id',
views: {
entity_view: {
templateUrl: 'views/layouts/foo.html'
}
}
})
.state('suppliers.edit.details', {
url: '/edit',
views: {
entity_sub_view: {
controller: function () {
this.foo = {bar: "TEST HEADER"};
},
controllerAs: 'vm',
templateUrl: 'views/layouts/main.html'
}
}
});
});
And in some controller do
this.$scope.mainCtrl.foo = {bar: "TEST HEADER"};
In view
{{mainCtrl.foo.bar}}

Could not resolve 'story.detail?storyId=167&pubId=84' from state 'search'

Could not resolve story.detail?storyId=167&pubId=84 from state search
var params = 'storyId='+$scope.stories[index].ID+'&pubId='+$scope.pubId;
$state.go('story.detail?'+params);
$stateProvider
.state('story.list', {
url: '/search?storyId&pubId',
templateUrl: 'views/search.html',
controller: 'SearchCtrl',
resolve: {
ds : ['$wakanda', function($wakanda){
return $wakanda.init();
}]
}
})
.state('story', {
url: '/story',
abstract: true,
templateUrl: 'views/story.html'
// controller: 'StoryCtrl'
})
.state('story.detail', {
url: '/story.detail?storyId&pubId',
templateUrl: 'views/story_detail.html',
controller: 'StoryDetailCtrl',
resolve: {
ds : ['$wakanda', function($wakanda){
return $wakanda.init();
}]
}
});
I've read through other similar questions and replies here.
I don't know why router could not resolve the state name story.detail?storyId=167&pubId=84 from state search.
$state.go should be configured like so:
$state.go('story.detail', {
storyId : $scope.stories[index].ID,
pubId : $scope.pubId
});

ui router - abstract state inside à normal one (3 levels)

i'm trying to get work this combination of sub levels routes.
http://plnkr.co/edit/1nBzppJkB45Ljv5SRW4b?p=preview
i took a sample from ui-route on github and added a parent view (contactg).
$stateProvider
.state('contactg', {
url: '/contactg',
templateUrl: 'contactG.html',
onEnter: function () { console.log("enter contactG"); }
})
.state('contactg.contacts', {
abstract: true,
url: '/contacts',
templateUrl: 'contacts.html',
controller: function ($scope) {
$scope.contacts = [{ id: 0, name: "Alice" }, { id: 1, name: "Bob" }];
},
onEnter: function () {
console.log("enter contacts");
}
})
.state('contactg.contacts.list', {
url: '/list',
// loaded into ui-view of parent's template
templateUrl: 'contacts.list.html',
onEnter: function () {
console.log("enter contacts.list");
}
})
.state('contactg.contacts.detail', {
url: '/:id',
// loaded into ui-view of parent's template
templateUrl: 'contacts.detail.html',
controller: function ($scope, $stateParams) {
$scope.person = $scope.contacts[$stateParams.id];
},
onEnter: function () {
console.log("enter contacts.detail");
}
})
My issues is when i click on an item in contactg.contacts.list, the link generated tends to redirect me to /contacts/:id (detail) instead of /contactg/contacts/:id
is there a way to specify that ?
Thanks
Guillaume.

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'
})

Resources