UI-Router: how does the params map to the url - javascript

I am new to Angular and UI-Router and I have to work with an Angular codebase. I am having difficulty understanding how the params gets mapped to the url. Specifically how topics get injected as topic in /test?topic&manualMode&advancedMode I cannot seem to find the place where I can log out the intermediate value to see how the url gets constructed.
function StateConfig(
$stateProvider: angular.ui.IStateProvider,
breadcrumbsService: BreadcrumbsService
) {
$stateProvider.state("testHub", {
params: {
topics: null
},
url: "/test?topic&manualMode&advancedMode",
views: {
main: {
template:
'<div class="hubContent"><iot-mqtt-client-config></iot-mqtt-client-config></div>'
},
sidebar: {
controller: HelpControllerTutorial,
controllerAs: "vm",
templateUrl: "pages/mqtt/mqtt-client-help.html"
}
}
});
breadcrumbsService.addConfig("testHub", {
name: (i18n: I18nService) => i18n("text.test"),
parentState: null,
reconstructBreadcrumbPath: true
});
}

This should work for you in app.js:
.state('testHub', {
url: "/test/:topic/:manualMode/:advancedMode", // added for dynamic ID params
})
Then your ui-sref in substances.html will append the ( topic or manualMode or advancedMode ) to the url, and you will be able to access that in your controller in $stateParams

Related

Angular UI Router refresh is taking to Parent State issue

I have an app that uses angular-ui-router with html5mode(true). Everything seems to work fine when running and routing to other states. following are the states.
$urlRouterProvider.otherwise("/navigation-master");
$stateProvider
.state('master', {
url: "",
views: {
"#": {
templateUrl: "content-master"
},
"nav-view": {
templateUrl: "nav-content"
}
}
})
.state('master.content', {
url: "/content/:pageId",
views: {
"content-view": {
templateUrl: function ($stateParams) {
return 'content?pageId=' + $stateParams.pageId;
}
}
},
params: {extra: null}
});
secApp.run(function ($transitions, $http, $templateCache ) {});
when i refresh the page while i'm currently in other routes(lets say master.content) it takes me back to navigation-master.
Maybe try to set the url at / and not `` in your first state

Why can’t I pass parameters between two states (with a parent-child relation) using $stateParams in Ionic v1.3.3?

Codes setting up the router (the two states have a parent-child relation):
.state("tab.my-profile", {
url: "/my/profile",
views: {
"tab-my": {
templateUrl: "templates/tab-my-profile.html",
controller: "MyProfileCtrl"
}
}
})
.state("tab.my-profile-mobileinput", {
url: "/my/profile/mobileinput",
views: {
"tab-my": {
params: {"mobile": null}
templateUrl: "templates/util-mobile-input.html",
controller: "MobileInputCtrl",
}
}
})
Codes in the controller of the parent state:
.controller("MyProfileCtrl", function ($scope, $state) {
$scope.goToMobileInput = function () {
$state.go("tab.my-profile-mobileinput", {"mobile": "123456"})
};
})
Codes in the controller of the child state:
.controller("MobileInputCtrl", function ($scope, $stateParams) {
alert($stateParams.mobile); // undefined
})
I can jump to the child state. But in the child state’s controller, I can’t receive the parameter (got an “undefined”). I’ve been stuck in this problem for hours. Could anyone help me find a way out? Thanks a lot in advance.
In my apps, I set parameters on url.
.state("tab.my-profile-mobileinput", {
url: "/my/profile/mobileinput/:mobile",
views: {
"tab-my": {
templateUrl: "templates/util-mobile-input.html",
controller: "MobileInputCtrl",
}
}
})

Accessing child state parameters in parent in Angular UI-Router

I have the following state configuration. How can I get id parameters in index state # view so that it could be accessible by both, left and detail views controllers? Now if I try to access it via $state.params.id it is undefined, but if I console.log($state) I can see the parameter in my console. I only need the parameter if available on first load of left view.
$stateProvider
.state('index', {
url: '/',
views: {
'#' : {
template: '/**/'
resolve: {
params: function ($state) {
return $state.params.id;
}
}
},
'left#index' : {
template: '/**/',
controller: 'AppController',
controllerAs: 'app'
},
'main#index' : {
template: '/**/'
}
})
.state('index.detail', {
url: '/:id',
views: {
'detail#index' : {
template: '/**/',
controller: 'DetailController',
controllerAs: 'detail',
}
}
});

AngularJS ui-router: how to resolve typical data globally for all routes?

I have an AngularJS service which communicates with the server and returns
translations of different sections of the application:
angular
.module('utils')
.service('Translations', ['$q','$http',function($q, $http) {
translationsService = {
get: function(section) {
if (!promise) {
var q = $q.defer();
promise = $http
.get(
'/api/translations',
{
section: section
})
.success(function(data,status,headers,config) {
q.resolve(result.data);
})
.error(function(data,status,headers,config){
q.reject(status);
});
return q.promise;
}
}
};
return translationsService;
}]);
The name of the section is passed as the section parameter of the get function.
I'm using AngularJS ui-router module and following design pattern described here
So I have the following states config:
angular.module('app')
.config(['$stateProvider', function($stateProvider) {
$stateProvider
.state('users', {
url: '/users',
resolve: {
translations: ['Translations',
function(Translations) {
return Translations.get('users');
}
]
},
templateUrl: '/app/users/list.html',
controller: 'usersController',
controllerAs: 'vm'
})
.state('shifts', {
url: '/shifts',
resolve: {
translations: ['Translations',
function(Translations) {
return Translations.get('shifts');
}
]
},
templateUrl: '/app/shifts/list.html',
controller: 'shiftsController',
controllerAs: 'vm'
})
This works fine but as you may notice I have to explicitly specify translations in the resolve parameter. I think that's not good enough as this duplicates the logic.
Is there any way to resolve translations globally and avoid the code duplicates. I mean some kind of middleware.
I was thinking about listening for the $stateChangeStart, then get translations specific to the new state and bind them to controllers, but I have not found the way to do it.
Any advice will be appreciated greatly.
Important note:
In my case the resolved translations object must contain the translations data, not service/factory/whatever.
Kind regards.
Let me show you my approach. There is a working plunker
Let's have a translation.json like this:
{
"home" : "trans for home",
"parent" : "trans for parent",
"parent.child" : "trans for child"
}
Now, let's introduce the super parent state root
$stateProvider
.state('root', {
abstract: true,
template: '<div ui-view=""></div>',
resolve: ['Translations'
, function(Translations){return Translations.loadAll();}]
});
This super root state is not having any url (not effecting any child url). Now, we will silently inject that into every state:
$stateProvider
.state('home', {
parent: 'root',
url: "/home",
templateUrl: 'tpl.html',
})
.state('parent', {
parent: 'root',
url: "/parent",
templateUrl: 'tpl.html',
})
As we can see, we use setting parent - and do not effect/extend the original state name.
The root state is loading the translations at one shot via new method loadAll():
.service('Translations', ['$http'
,function($http) {
translationsService = {
data : {},
loadAll : function(){
return $http
.get("translations.json")
.then(function(response){
this.data = response.data;
return this.data;
})
},
get: function(section) {
return data[section];
}
};
return translationsService;
}])
We do not need $q at all. Our super root state just resolves that once... via $http and loadAll() method. All these are now loaded, and we can even place that service into $rootScope:
.run(['$rootScope', '$state', '$stateParams', 'Translations',
function ($rootScope, $state, $stateParams, Translations) {
$rootScope.$state = $state;
$rootScope.$stateParams = $stateParams;
$rootScope.Translations = Translations;
}])
And we can access it anyhwere like this:
<h5>Translation</h5>
<pre>{{Translations.get($state.current.name) | json}}</pre>
Wow... that is solution profiting almost from each feature coming with UI-Router... I'd say. All loaded once. All inherited because of $rootScope and view inheritance... all available in any child state...
Check that all here.
Though this is a very old question, I'd like to post solution which I'm using now. Hope it will help somebody in the future.
After using some different approaches I came up with a beautiful angularjs pattern by John Papa
He suggest using a special service routerHelperProvider and configure states as a regular JS object. I'm not going to copy-paste the entire provider here. See the link above for details. But I'm going to show how I solved my problem by the means of that service.
Here is the part of code of that provider which takes the JS object and transforms it to the states configuration:
function configureStates(states, otherwisePath) {
states.forEach(function(state) {
$stateProvider.state(state.state, state.config);
});
I transformed it as follows:
function configureStates(states, otherwisePath) {
states.forEach(function(state) {
var resolveAlways = {
translations: ['Translations', function(Translations) {
if (state.translationCategory) {
return Translations.get(state.translationCategory);
} else {
return {};
}
}],
};
state.config.resolve =
angular.extend(state.config.resolve || {}, resolveAlways || {});
$stateProvider.state(state.state, state.config);
});
});
And my route configuration object now looks as follows:
{
state: ‘users’,
translationsCategory: ‘users’,
config: {
controller: ‘usersController’
controllerAs: ‘vm’,
url: ‘/users’.
templateUrl: ‘users.html'
}
So what I did:
I implemented the resolveAlways object which takes the custom translationsCategory property, injects the Translations service and resolves the necessary data. Now no need to do it everytime.

Angular ui-router variable in nested view

I'm currently working on an app where I have multiple nested views, they sort of look like this:
- ui-view
- ui-view="header"
- ui-view="nav"
- ui-view="body"
My states are defined as follows:
.state('index', {
url: '', // default route
templateUrl: 'welcome.html'
})
.state('app', {
abstract: true,
templateUrl: 'app.template.html' // This template contains the 3 different ui-views
})
// I'm using a different state here so I can set the navigation and header by default
.state('in-app', {
parent: 'app',
abstract: true,
views: {
'nav#app': { '...' },
'header#app': { '...' }
}
})
// In-app routes
.state('dashboard', {
parent: 'in-app',
url: '/app/dashboard'
views: {
'body#app': { '...' }
}
})
.state('users', {
parent: 'in-app',
url: '/app/users'
views: {
'body#app': { '...' }
}
})
.state('settings', {
parent: 'in-app',
url: '/app/settings'
views: {
'body#app': { '...' }
}
})
At the moment this works great, but for the in-app routes I would like to define a title that is displayed in the header#app view.
What would be the best way to do this? At the moment I can only think of either setting a variable on the $rootScope, or sending out an event. But for both of those I would need a controller.
Is there a way I could do this directly from my routes config?
The sample applicaiton of the UI-Router, uses this code:
ui-router / sample / app / app.js
.run(
[ '$rootScope', '$state', '$stateParams',
function ($rootScope, $state, $stateParams) {
// It's very handy to add references to $state and $stateParams to the $rootScope
// so that you can access them from any scope within your applications.For example,
// <li ng-class="{ active: $state.includes('contacts.list') }"> will set the <li>
// to active whenever 'contacts.list' or one of its decendents is active.
$rootScope.$state = $state;
$rootScope.$stateParams = $stateParams;
}])
And that means, that with data : {} feature:
Attach Custom Data to State Objects
You can attach custom data to the state object (we recommend using a data property to avoid conflicts).
// Example shows an object-based state and a string-based state
var contacts = {
name: 'contacts',
templateUrl: 'contacts.html',
data: {
customData1: 5,
customData2: "blue"
}
}
we can do this:
.state('in-app', {
parent: 'app',
abstract: true,
views: {
'nav#app': { '...' },
'header#app': { '...' }
}
data: { title : "my title" },
})
And use it in some template like:
<div>{{$state.current.data.title}}</div>
Some summary.
We can place state and params into $rootScope, so we can access it without any controller anyhwere.
We can declare some more custom stuff via data and use it as a title ... anyhwere

Categories