Populate route params with resolved data in angular ui-route - angularjs

Give the following code:
$stateProvider
.state('app.users', {
abstract: true,
url: '/users',
templateUrl: 'views/users.html',
resolve: {
userId: Users => Users.lastUserSelected()
},
})
.state('app.users.questions', {
url: '/:userId/questions',
templateUrl: 'views/questions.html',
controller: 'UsersQuestionsCtrl',
resolve: {
questions: (userId) => Questions.getAll(userId)
}
})
When I transit to the app.users.questions state, everything goes ok, but the URL in the browser ends up being like mydomain.com/users//questions (notice the double forward slash // in the route, there's no userId)
Seems like the user ID resolved from the parent state is not populated in child route, or something alike. I think I'm missing a key concept here.
I would like to achieve a URL like mydomain.com/users/USERID/questions.
I've been through many ui-router guides but couldn't figure this out, any help is really appreciated.
I'm populating my sideBar menu using the addMenuItem and addMenuSubItem methods from the MEANJS project.
Menus.addMenuItem('sidebar', {
state: 'app.users',
type: 'dropdown',
iconClass: 'fa fa-comments',
position: 4,
roles: ['*']
});
Menus.addSubMenuItem('sidebar', 'app.users', {
state: 'app.user-questions'
});
Notes:
1- It doesn't matter the previous state, wherever state I come from... it's not related at all to the user, so passing the :userId from all the possible previous states sounds wrong to me. I'm just using USERS and QUESTIONS as an example here but those are not the entities i'm working with in my actual project.
2 - Im using MEANJS seed project

Related

Dynamic variable in URL in AngularJS

I have an Angular app which has several dynamic fields, each of these fields are changed updated based on config which comes from a backend database.
In order to control what config is used I need to dynamically switch a single variable - I've decided that the URL is the best way to set/switch the variable as there need to be multiple permutations of the site based on the URL so:-
/:dynamicVariable/
I'm looking for some guidance as to whether this is the best way to do it and what the best way to do it would be? I'm struggling as I don't want to have to set each route for each section like this /:dynamicVariable/homepage /:dynamicVariable/about-us etc etc. Ideally the core module checks it and sets it but the routing ignores it so /:dynamicVariable/ becomes the root.
Hope that makes sense, thanks in advance for your help.
I ended up doing this by using ui.router and nesting states within an abstract parent state which held the client, like so :-
.state('rootClient', {
abstract: true,
url: '/:client',
templateUrl: 'app/layout/layout.html',
controller: 'Layout',
controllerAs: 'layout',
noClient: false,
resolve: {
client: function ($stateParams, ClientService) {
return ClientService.getClient($stateParams.client);
}
}
})
.state('rootClient.home', {
url: '/homepage',
views: {
'content': {
templateUrl: 'app/homepage/homepage.html',
controller: 'Homepage',
controllerAs: 'home'
}
}
});
This way all the routes are under the parent route, I also added a resolve to make sure the client exists before moving to the route. Hopefully this will help someone else down the line.
Cheers

$state.href with absolute: true doesn't return the right url

I'm using Angular and UI router. I'm trying to get a link shown on the page that the user can copy and share. This thread has shown me that $state.href is the function I'm looking for, however it isn't generating the correct link.
An important detail here is that the root of my application is not the root of the domain. In this case, the domain is localhost, but the root of the angular app is in localhost/dev/app/.
Here's the command I'm using inside my controller.
$scope.url = $state.href('survey', { survey: "asd" }, {absolute: true});
In my app.js, the following route is declared:
.state('survey', {
url: "/:survey/survey?ao",
templateUrl: "views/survey/survey.html",
controller: "surveyController",
},
data: {
requireLogin: false,
requireAdmin: false
}})
This should return http://localhost/dev/app/#/asd/survey, instead it returns http://localhost/#/asd/survey.
(The remarkable thing is that ui-sref="survey({survey: "asd"}) does translate to the correct link.)
Is there a way I can fix this so I get the full url?
Adding a base tag to my app page solved this issue for me. It defines the base URL for the page with the router references. For legacy support reasons, I'm on version 0.2.15 of Angular UI Router. I don't know if this is still necessary for more current versions.
<base href="http://localhost/dev/app/" />
.state('survey', {
url: "/:survey/survey?ao",
templateUrl: "views/survey/survey.html",
controller: "surveyController",
data: {
requireLogin: false,
requireAdmin: false
}
})
You had an extra '},' in after controller, maybe that is messing things up? Also if you're passing parameters you might want to include that as a params line:
params: {
survey: null
}
Also if you want the url http://localhost/dev/app/#/asd/survey your url should be:
url: "dev/app/:survey/asd/survey"

ui-router adding trailing slash at end of route causing 404

I've built out an application and mostly everything is working as expected except I have these three states where when I refresh the page via reloading the url it causes a trailing slash on the end of the page causing my otherwise('/404') to trigger.
This happen nowhere else on the entire platform. The weird part is that if I change the state URL for one of the states with issues, the issue is fixed.
The three state url's that have issues are market, refer-business and invite-friends. These are all a child of a shell view named root. I have absolutely no idea what is causing this issue.
I also realized that if I take $urlRouterProvider.otherwise('/404'); out of my main modules config, the issue goes away as well.
Here are two of the routes that aren't working.
market.routes.js
function marketRoutes($stateProvider) {
$stateProvider.state('market', {
parent: 'root',
url: '/market?category', // If I change this to /blahblah, it works perfects
views: {
"#root": {
templateUrl: '/market/market.html',
controller: 'MarketController',
controllerAs: 'MarketCtrl'
}
},
resolve: {
Categories: ['MarketService', function (MarketService) {
return MarketService.getCategories();
}],
Products: ['MarketService', '$stateParams', function (MarketService, $stateParams) {
// By default the market should open on `deals of the moment` category
return MarketService.getProducts(0, 9, 1, $stateParams.category || 4);
}]
},
data: {
title: 'Market'
}
});
}
refer-business.routes.js
function ReferBusinessRoutes($stateProvider) {
$stateProvider.state('refer-business', {
parent: 'root',
url: "/refer",
templateUrl: "/refer-business/refer-business.html",
controller: "ReferBusinessController",
controllerAs: "rbCtrl",
onEnter: function () {
this.data.title = "Refer a business";
},
data: {
title: 'Refer a business'
},
authenticate: true
});
}
I've spent the last 3 days on this and I've come up with nothing. Hopefully somebody here has run into this issue or has some tips on how to further debug it.
You might find the answer here: Handling trailing slashes in angularUI router
Explains How to tell angular deal with trailing slashes as usual.
It also might be permission problem in your template files at server side

How can i update $stateParams without reloading the ui-view? angular ui router

Get the context, angular, ui-router, nothing special, a root view built with 3 named ui-views.
so in index.html we have
<body>
<div ui-view='left'>
<div ui-view='center'>
<div ui-view='right'>
</body>
my route looks like
$stateProvider
.state('main', {
url: '/',
views: {
'left': {templateUrl: 'foo.html'},
'center': {templateUrl: 'bar.html'},
'right': {templateUrl: 'xyz.html'}
}
})
.state('main.b', {
url: '/b',
params: { foo: {value: 'bar'} }
views: { 'right#': {templateUrl: '123.html'} } // I wish to update $stateParams in 'left#' view
})
.state('main.c', {
url: '/c',
params: ...
views: { 'left#': ..., 'center#': ..., 'right#': .. }
});
Is there a way in going to b state to update the $stateParams in the 'center' and 'left' view?? I can get it using a service but i need to add a $watch to the variable I need and it looks a little bit hacky to me.
Going into c state I can actually get what I want, but the view is reloaded, and i wish to avoid this behaviour cause i have a canvas in the 'left' view.
You could use the following to go to a specific route without reloading the views:
$state.go('.', {parm1: 1}, {notify: false});
The last object literal represents the options which you can pass along to go. If you set notify to false, this will actually prevent the controllers from being reinitialized. The . at the beginning is the absolute state name or relative state path you wanna go to.
The important thing is the notify though.
I think that using "Dynamic params" is now a better solution:
When dynamic is true, changes to the parameter value will not cause the state to be entered/exited. The resolves will not be re-fetched, nor will views be reloaded.
$stateProvider.state('search', {
url: '/search?city&startDate&endDate',
templateUrl: 'some/url/template.html',
params: {
city: {
value: 'Boston',
dynamic: true
}
}
}
and then:
$state.go('.', {city: 'London'});
https://ui-router.github.io/ng1/docs/latest/interfaces/params.paramdeclaration.html#dynamic
https://github.com/angular-ui/ui-router/issues/2709
Quoting #christopherthielen from https://github.com/angular-ui/ui-router/issues/1758#issuecomment-205060258:
using notify: false is almost never a good idea, and is now
deprecated. Use reloadOnSearch if you must.
You can also try dynamic parameters in the 1.0 version (currently
1.0.0-alpha.3). In your state, configure a parameter as dynamic and implement the uiOnParamsChanged callback :
.state('foo', {
url: '/:fooId',
params: { fooId: { dynamic: true } },
controller: function() {
this.uiOnParamsChanged = function(changedParams, $transition$) {
// do something with the changed params
// you can inspect $transition$ to see the what triggered the dynamic params change.
}
}
});
For a demo, have a look at this plunker: http://plnkr.co/edit/T2scUAq0ljnZhPqkIshB?p=preview

AngularJS ui.router abstract routes and trailing slashes

I have three route states - an abstract state, a state that shows the listing and a state that specifically shows a detail of one particular object.
My states are configured as follows:
.state('movies', {
url: "/movies",
template: '<ui-view ng-show="isLoaded" />',
abstract: true,
ncyBreadcrumb: {
skip: true
}
})
.state('movies.index', {
url: "?genres&tags&year&season&page&perpage",
templateUrl: "views/movies.html",
controller: 'MoviesViewController',
ncyBreadcrumb: {
label: 'Movies'
}
})
.state('movies.show', {
url: "/:id/:slug",
controller: 'MoviesItemController',
templateUrl: "views/movies/details.html",
ncyBreadcrumb: {
parent: 'movies.index',
label: '{{item.title_main}}'
}
})
I'd like to add the posibility of movies.index also beginning with a slash, so the URL can either be /movies or /movies/. However with my design, I have no idea how to do that.
I'm also not sure if I understand the concept behind abstract states correctly. I can either use this, or have movies.index be the parent state, in which case, how do I replace its content by the child's template? Also, I have noticed that since the parent controller also gets called, an unnecessary GET request is sent to my API, which can slow things down (especially since it's completely useless information). Can anyone give me a hand in this?
I understand that this use case is supported by $urlMatcherFactory.strictMode(false)
Take a look her
http://angular-ui.github.io/ui-router/site/#/api/ui.router.util.$urlMatcherFactory#methods_strictmode

Resources