I want to be able to pass some state params that will show up in the route, and some that won't.
It would be nice to be able to do this:
.state('widgetadmin.widgets.widget', {
url: '/widget/{widgetId}/{friendlyName}',
views: {
"sub#widgetadmin": {
controller: 'WidgetAdminController as vm',
templateUrl: 'widgetadmin/widgets/widget.tpl.html',
params: { widgetHref: null }
}
},
data:{ pageTitle: 'Edit Widget' }
}
Then pass it like this:
$state.go('widgetadmin.widgets.widget',
{widgetId: widget.id, friendlyName: slug, widgetHref: widget._links.self.href},
{reload: true});
But when I try to access it, it's undefined:
var something = $stateParams.widgetHref;
How can I pass some state params in route, and some not?
Needed to put the params in a different place:
.state('widgetadmin.widgets.widget', {
url: '/widget/{widgetId}/{friendlyName}',
views: {
"sub#widgetadmin": {
controller: 'WidgetAdminController as vm',
templateUrl: 'widgetadmin/widgets/widget.tpl.html'
}
},
data:{ pageTitle: 'Edit Widget' },
params: { widgetHref: null }
}
Related
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))/
I have my state configurations defined as below:
$stateProvider
.state('parentState', {
abstract: true,
url: '/:tenantId/',
param: {
tenantId: {
array: false
}
},
views: {
'header#': {
templateUrl: 'home/header.html',
controller: 'Header as vm'
},
'footer#': {
templateUrl: 'home/footer.html',
controller: 'FooterCtrl as vm'
}
},
resolve: userResolve,
data: {
private: true
}
})
//...4-5 other child states, then a state to handle unknown urls
.state('parentState.otherwise', {
views: {
'#': {
templateUrl: 'home/404/pageNotFound.html',
controller: 'PageNotFoundCtrl as vm'
}
}
});
$urlRouterProvider.otherwise(function ($injector) {
$injector.get('$state').go('parentState.otherwise', {}, {
location: false
});
});
Now, when an invalid URL is entered, parentState.otherwise state loads correctly, and parentState param, i.e. tenantId, is also correctly filled.
However, on page reload(refresh, Ctrl + R) with same invalid URL, parentState.otherwise state loads, but the problem is parentState param, i.e. tenantId is coming as empty string("").
Somehow, with location: false, the parent state, i.e. parentState in this case, was not picking up tenantId param from the URL on page refresh. So, if we explicitly pass tenantId param to child state, i.e. parentState.otherwise while opening it, everything works perfectly even on page refresh:
$urlRouterProvider.otherwise(function ($injector) {
$injector.get('$state').go('parentState.otherwise', {
tenantId: 'someTenantId'
}, {
location: false
});
});
controllerA from state A
$state.go('account.accountRegister', {accountType: $stateParams.accountType, acName: acName})
State defined in app.js
.state('account.accountRegister', {
url: '/:accountType/register',
params: {accountType, acName},
views: {
'mainView#':{
templateUrl: 'app/views/registration.html',
controller: 'registrationController'
}
}
})
controllerB from state B
console.log($stateParams.acName); // is getting undefined
How to use acName in the controller without showing in the url part of the state?
I came up with a solution
.state('account.accountRegister', {
url: '/:accountType/register',
params: {
acName: {
value: 'defaultValue',
squash: false
}
},
views: {
'mainView#':{
templateUrl: 'app/views/registration.html',
controller: 'registrationController'
}
}
})
For more info on squash property of the params object:
https://ui-router.github.io/docs/0.3.1/#/api/ui.router.state.$stateProvider
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("/");
My angular app is routed as following:
$stateProvider
// setup an abstract state for the tabs directive
.state('tab', {
url: "/tab",
abstract: true,
templateUrl: "templates/tabs.html"
})
// Each tab has its own nav history stack:
.state('tab.dotnet', {
url: '/dotnet',
views: {
'tab-dotnet': {
templateUrl: 'templates/tab-dotnet.html',
controller: 'QuestionsCtrl'
}
}
})
.state('tab.sql', {
url: '/sql',
views: {
'tab-sql': {
templateUrl: 'templates/tab-sql.html',
controller: 'QuestionsCtrl'
}
}
})
The above two routes use the same controller but different html pages.
Since both the pages are same, I want to have a single html page in my application instead of two different tab-sql and tab-dotnet pages.
But I will need a differentiation variable to be injected to the controller when selecting the tabs.
Basically I need something like this:
.state('tab.dotnet', {
url: '/dotnet',
views: {
'tab-dotnet': {
templateUrl: 'templates/tab.html',
controller: 'QuestionsCtrl',
type: 'dotnet' // so that i get this type in my Controller
}
}
})
.state('tab.sql', {
url: '/sql',
views: {
'tab-sql': {
templateUrl: 'templates/tab.html',
controller: 'QuestionsCtrl',
type: 'sql'
}
}
})
How to achieve this?
You can pass data to controllers in a state using resolve.
.state('tab.dotnet', {
url: '/dotnet',
views: {
'tab-dotnet': {
templateUrl: 'templates/tab.html',
controller: 'QuestionsCtrl',
resolve: {
type: 'dotnet';
}
}
}
})
.state('tab.sql', {
url: '/sql',
views: {
'tab-sql': {
templateUrl: 'templates/tab.html',
controller: 'QuestionsCtrl',
resolve: {
type: 'sql';
}
}
}
})
https://github.com/angular-ui/ui-router/wiki#resolve