how to get current url from UI Router - State? - angularjs

By conditionally, I require to route my application to a new path. so I would like to know the current url of my application.
how can i get my current url from sate like toState.name?
here is my scenario:
.state('serialCreateCase', {
url: '/sn={serialNumber}', //sn=12345;
templateUrl:'app/createCase/create-case.html',
controller: 'createCaseController as ctrl',
data: {
requireLogin: false
}
here is the condition:
if(toState.name==="serialCreateCase"){ // i am getting proper result
console.log('toState.name', toState );
$rootScope.goToView("serialCreateCase"); //i am asking to go there. but not works! //sn=12345;
event.preventDefault();
}
Thanks in advance.

You don't need the url because you are using states
You should use this method
$state.go("serialCreateCase", {sn: 12345});
This will send the user to state serialCreateCase with the data
Key : sn
Value : 12345
EDIT
You code inside the controller should look like this
if (toState.name === "serialCreateCase") { // i am getting proper result
console.log('toState.name', toState);
$state.go("serialCreateCase", { sn: 12345 });
event.preventDefault();
}

Edited Code:
$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams) {
var curentpath = fromState.url;
var split = curentpath.split(':');
var params = $stateParams.sn;
var mainUrl = split[0] +params;
console.log(mainUrl);
});
&& Route:
.state('serialCreateCase', {
url: '/sn={serialNumber}', //sn=12345;
templateUrl:'app/createCase/create-case.html',
controller: 'createCaseController as ctrl',
data: {
requireLogin: false
}

Related

How to supply the separate `template` when param exist?

I have a scenario, to handle the params. ( when param exist it will handled differently )
so, how can i keep 2 templates and use them according to the requirement? at present I am trying like this, which is not working at all.
any one help me?
my state with 2 template: ( please help me to correct )
.state('serialCreateCase', {
url: '/serialCreateCase?sn=',
views:{
"" : {
"templateUrl": 'app/login/loginWithSerial.html'
},
"?sn=" : {
"templateUrl": 'app/login/login.html'
}
}
})
here is the redirection with 2 scenarios: ( correct me if I am wrong )
if(!$rootScope.isUserLoggedIn && toParams.sn !== undefined ) {
console.log('dont take action', toState, toParams.sn );
$rootScope.canNavigate = true;
$state.go('serialCreateCase'); //works
$state.go('serialCreateCase', {sn:'1234'}); //not works
event.preventDefault();
return;
}
There is a working plunker
I would say that you need replace templateUrl with
Templates
TemplateUrl ...
templateUrl can also be a function that returns a url. It takes one preset parameter, stateParams, which is NOT
injected.
TemplateProvider
Or you can use a template provider function which can be injected, has access to locals, and must return template HTML,
like this...
There are more details and plunkers
Angular UI Router: decide child state template on the basis of parent resolved object
dynamic change of templateUrl in ui-router from one state to another
This I prefer the most
...
templateProvider: [$stateParams, '$templateRequest',
function($stateParams, templateRequest)
{
var tplName = "pages/" + $stateParams.type + ".html";
return templateRequest(tplName);
}
],
(check it here) because it uses also $templateRequest
EXTEND
There is a working plunker
this could be the state def
.state('serialCreateCase', {
url: '/serialCreateCase?sn',
views: {
"": {
templateProvider: ['$stateParams', '$templateRequest',
function($stateParams, templateRequest) {
var tplName = "app/login/loginWithSerial.html";
if($stateParams.sn){
tplName = "app/login/login.html";
}
return templateRequest(tplName);
}
]
},
}
});
what we really need is to always pass some value, as sn. So, these should be the calls:
// we need to pass some value, to be sure that there will be other than last
<a ui-sref="serialCreateCase({sn: null})">
// here is reasonable value
<a ui-sref="serialCreateCase({sn:'1234'})">
Check it here in action
use, $stateParams instead of toParams,
1) Deciding the template depending on the param(your requirement)
.state('serialCreateCase', {
url: '/serialCreateCase?sn=',
views: {
'': {
templateUrl: function(stateParams) {
var param = stateParams.sn
return (param == undefined) ? 'app/login/loginWithSerial.html' : 'app/login/login.html'
},
controller: 'myController',
}
}
})
You can check the stateParam using the parameter of templateUrl, and change the templates.
2) change the state depending on the param from controller.
This is a sample controller where you can check the state parameter and use the re directions as your wish.
allControllers.controller('myController', ['$scope','$rootScope','$state','$stateParams',
function($scope,$rootScope,$state,$stateParams) {
if(!$rootScope.isUserLoggedIn)
{
if($stateParams.sn !== undefined )
{
alert('dont take action', $stateParams.sn );
}
else
{
alert('You can redirect, no parameter present');
}
}
}
}])

Resyncing $urlRouterProvider.deferIntercept(); for angular 1 ui router

In Angular 1.5 and angular ui router, I want to change the back button behaviour of my states to recognise the names of the states and not the params as I have a url /restaurant/1?param1=value&param2=value which dynamically changes without refreshing the page. I have the binding and url not changing when a property changes, but when I hit the back button it goes to the previous params state, not the saved state in $rootScope by name. I've debugged this for hours and my current solution only works sometimes, it's not consistent because the url sync isn't always called in time thus the state does not update when the url updates. I'm correctly identifying when the back button is hit but it's not refreshing the state. Right now, I have to use a location.assign and yet it only works some of the time. Is there anyway to resync the deferIntercept in angular ui router?
function bind(propGetters,
getUrl) {
let unwatch = this._$rootScope.$watchGroup(propGetters, () => {
let trimmedUrl = getUrl();
let remove = this._$rootScope.$on('$locationChangeSuccess', () => {
this._$rootScope.disableBackButton = false;
remove();
});
this._$rootScope.disableBackButton = true;
if (!this._$rootScope._hitBackButton) {
this._$rootScope.shouldSync = false;
this._$location.url(trimmedUrl);
}
});
return {
unbind(): void {
unwatch();
}
};
module.run(
($urlRouter, $rootScope) => {
$rootScope.shouldSync = true;
$rootScope.$on('$locationChangeSuccess', e => {
if ($rootScope.shouldSync) {
$urlRouter.sync();
} else if (!$rootScope._hitBackButton) {
e.preventDefault();
}
$rootScope.shouldSync = true;
});
$rootScope.$on("$stateChangeSuccess", (event, toState, toParams, fromState, fromParams) => {
if ($rootScope.previousState) {
if ($rootScope.previousState.name !== fromState.name && !$rootScope.disableBackButton) {
$rootScope.previousState = lodash.merge(fromState, { params: fromParams });
console.log($rootScope.previousState.name, 'previousState');
}
} else {
this._$rootScope.previousState = lodash.merge(fromState, { params: fromParams });
}
});
$rootScope.$on('$locationChangeSuccess', (evt, newUrl, oldUrl) => {
$rootScope.actualPrevious = oldUrl;
if ($rootScope._hitBackButton) {
this._urlProvider.sync();
$rootScope._hitBackButton = false;
}
});
$rootScope.$on('$locationChangeStart', (evt, newUrl, oldUrl) => {
if ($rootScope.actualPrevious === newUrl && $rootScope.previousState && !$rootScope.disableBackButton && !$rootScope._hitBackButton) {
$rootScope.shouldSync = true;
event.preventDefault();
console.log('hit back', $rootScope.previousState.name);
$rootScope._hitBackButton = true;
window.location.assign(this._urlService.getFullPath(this._$state.href($rootScope.previousState.name, $rootScope.previousState.params)))
// this._$state.go($rootScope.previousState.name, $rootScope.previousState.params, { reload: true }); - this doesn't seem to always work because of watch collisions?
}
});
$urlRouter.listen();
});
After playing around for 5 hours,
I found it's best to avoid using deferIntercept all together and instead reloadOnSearch: false like so
$stateProvider.state('app.restaurant', {
url: '/restaurant/{slug}?param1&param2&param3',
resolve: {
param1: function 1,
param2: function 2,
param3: function 3
},
reloadOnSearch: false,
params: {
slug: { value: null },
},
controller: 'restaurantController',
template:
});
Note you will have to use deferIntercept for slashes instead of params. I'd strongly advise using params if your url changes. The back button should work fine with my solution above minus the deferIntercept and plus the reloadOnSearch: false
Full modified implementation:
this._$rootScope.$on('$locationChangeStart', (evt, newUrl, oldUrl) => {
if (this._$rootScope.actualPrevious === newUrl && this._$rootScope.previousState && !this._$rootScope._hitBackButton) {
evt.preventDefault();
this._$rootScope._hitBackButton = true;
this._$state.go(this._$rootScope.previousState.name, this._$rootScope.previousState.params);
}
});
this._$rootScope.$on("$stateChangeSuccess", (event, toState, toParams, fromState, fromParams) => {
if (this._$rootScope.previousState) {
if (this._$rootScope.previousState.name !== fromState.name) {
this._$rootScope.previousState = lodash.merge(fromState, { params: fromParams });
}
} else {
this._$rootScope.previousState = lodash.merge(fromState, { params: fromParams });
}
});
this._$rootScope.$on('$locationChangeSuccess', (evt, newUrl, oldUrl) => {
this._$rootScope.actualPrevious = oldUrl;
if (this._$rootScope._hitBackButton) {
this._$rootScope._hitBackButton = false;
}
});

Infinite loop in State Change Events in angularjs

I want to change the state from "mycarts" state to "carts" state. so I used $stateChangeStart angularjs event in "mycarts" controller and set a condition if the state you are going from "mycarts" state is "carts" state so go to the carts state.
Here is my angular event in my controller :
$scope.$on('$stateChangeStart', function (event, toState, toParams, fromState, fromParams) {
if (toState.name === 'carts' && fromState.name === 'mycarts') {
$state.go('carts', fromParams, true);
event.preventDefault();
return;
}
if (toState.name === 'mycarts' && fromState.name === 'mycarts') {
//Nothing
} else {
$rootScope.selectedItemsMyCarts = undefined;
}
});
My code will be stuck in :
if (toState.name === 'carts' && fromState.name === 'mycarts') {
$state.go('carts', fromParams, true);
event.preventDefault();
return;
}
Here is my state in app.js
.state('mycarts', {
url : '/mycarts/:type/:vendor?vendors&price_to&price_from&manufacturer&editor&theme&page&order&filter_by&no',
params: {
type: {squash: true, value: null},
vendor: {squash: true, value: null}
},templateUrl : 'partials/mycarts.html',
controller : 'MyCartsController'
}).state('carts', {
url : '/carts/:id?vendors&price_to&price_from&manufacturer&editor&theme&page&order&no',
templateUrl : 'partials/carts.html',
controller : 'CartsController'
}
And I get angular.js:12416 RangeError: Maximum call stack size exceeded error.
why this happens? And what is the solution if I want to change a state due to a condition in angular event? And what kind of documents I can read to understand what exactly going on when events like this happends.
If he is already going to the carts state, why are you doing this? :
$state.go('carts', fromParams, true);

How to dynamically set ui-sref value to parent state of the current state

1) My html form/view has below anchor tag which takes me to a state after clicking it
<a class="btn btn-default" ui-sref="custom.email.send">
2) But the same form is called from 2 different routes
3) Hence I want to set value of ui-sref dynamically to point to parent state of the state from where it was called!
For ex , if the above form is called from state "custom.email.send" then ui-sref should point to "custom.email"
http://angular-ui.github.io/ui-router/site/#/api/ui.router.state.$state
$rootScope.linkHistoryBack = '/';
$rootScope.$on('$stateChangeSuccess', function(event, to, toParams, from, fromParams) {
$rootScope.linkHistoryBack = $state.href(from, fromParams, {
absolute: true
});
});
<a ng-href="{{$root.linkHistoryBack}}">Go Back</a>
or, alternatively, build a directive:
angular
.module('uiSrefUtils', ['ui.router'])
.directive('uiSrefBack', function uiSrefBackDirectiveFactory($state) {
return function(iScope, iElement, iAttributes) {
iElement.attr('href', '/');
$rootScope.$on('$stateChangeSuccess', function(e, to, toP, from, fromP) {
var link = $state.href(from, fromP, {
absolute: true
});
return iElement.attr('href', link);
});
};
})
;
// use in your app
angular.module('myApp', ['ui.router', 'uiSrefUtils']);
<a ui-sref-back>Return</a>
You may create a state change listener to listen for state change globally
$rootScope.$on('$stateChangeSuccess', function(event, to, toParams, from, fromParams) {
$rootScope.previousState = from;
});
You may then access the previous state name with $rootScope.previousState.name and use this as the binding value

angularjs state parameters not working

I'm having an issue trying to pass a parameter object to a state using stage.go().
Here is my state definition:
.state('drillhole.ddhinttype', {
url: '/ddhinttype',
templateUrl: VIRTUAL_DIR_PATH + '/App/Views/drillholemanager/drillhole/tabddhinttype.html?v=' + fileVer,
controller: 'DrillHoleDdhIntTypeController',
params: { name: null, description: null }
})
And here is my controller:
try {
angular.module('centric.drillhole.manager');
} catch (e) {
angular.module('centric.drillhole.manager', ['app.config', 'ui.router', 'kendo.directives', 'ui.bootstrap', 'ngCookies', 'centric.common', 'centric.notification', 'pascalprecht.translate', 'centric.security', 'centric.app.settings']);
}
angular.module('centric.drillhole.manager').controller('DrillHoleDdhIntTypeController', ['$scope', 'CentricUIHelper', 'NumberHelper', 'DrillHoleManagerService', 'app.config', '$stateParams',
function ($scope, uihelper, numberHelper, service, appconfig, $stateParams) {
$scope.loading = false;
$scope.isbusy = function () {
return $scope.loading || $scope.$parent.loading;
}
var load = function () {
var hello = $stateParams.name;
var hello2 = $stateParams.description;
};
load();
}]);
And I'm calling the state like so:
$state.go('drillhole.ddhinttype', { name: tab.params.name, description: tab.params.description });
In my controller the name and description properties are always null.
Not sure what I'm missing here. Any ideas?
If you put the params in your url you will be able to access it in controller using $stateParams
.state('drillhole.ddhinttype', {
url: '/ddhinttype/:name/:description',
templateUrl: VIRTUAL_DIR_PATH + '/App/Views/drillholemanager/drillhole/tabddhinttype.html?v=' + fileVer,
controller: 'DrillHoleDdhIntTypeController',
params: { name: null, description: null }
})
You can read more about url routing here: https://github.com/angular-ui/ui-router/wiki/url-routing
Try this in the state definition:
params: { name: undefined, description: undefined }
or this:
params: ['name', 'description']
I feel like I should post the final result. I have decided to pass the parameter in the URL so that I can re-use the same controller for several tabs which each have the same functionality but against different tables in the DB.
Here is the part of my base controller which creates the tabs (CoreLogController.js):
service.getDrillHoleIntervalTypes()
.success(function (res) {
$scope.data.drillHoleIntervalTypes = res;
for (var i = 0; i < $scope.data.drillHoleIntervalTypes.length; i++) {
// add the tab and set it as active if we're in the correct $state
$scope.dynamictabs.push({ heading: $scope.data.drillHoleIntervalTypes[i].Name, route: 'drillhole.ddhinttype', params: { ddhinttype: $scope.data.drillHoleIntervalTypes[i].Name }, active: ($scope.$state.params.ddhinttype == $scope.data.drillHoleIntervalTypes[i].Name) });
}
})
.error(function (error) {
uihelper.showError(error);
});
And here is the relevant HTML portion where the tabs are shown (corelog.html):
<tabset>
<tab ng-repeat="t in statictabs" heading="{{t.heading}}" ui-sref="{{t.route}}" active="t.active"></tab>
<tab ng-repeat="t in dynamictabs" heading="{{t.heading}}" ui-sref="drillhole.ddhinttype({ddhinttype: '{{t.params.ddhinttype}}'})" active="t.active"></tab>
</tabset>
And here is where I define the state (app.js):
.state('drillhole.ddhinttype', {
url: '/ddhinttype/{ddhinttype}',
templateUrl: VIRTUAL_DIR_PATH + '/App/Views/drillholemanager/drillhole/tabddhinttype.html?v=' + fileVer,
controller: 'DrillHoleDdhIntTypeController',
params: { ddhinttype: null }
})
I now get access to the ddhinttype variable on each instance of the controller (DrillHoleDdhIntTypeController.js) which tells it which table to perform operations against.
Since ddhinttype is also contained the URL the user can create a bookmark which will bring them right back to the same tab even though they are dynamically generated.

Resources