$stateChangeSuccess, always the same value of $state.params - angularjs

I can't wrap my head around this, I'm really struggling with ui-routeand $stateChangeSuccess and $watch, got two issues. I'm trying to change a value of a parameter, when I change the state, click a url. I think it's important to know that I use sub-states. With my current setup I get that the $stateChangeSuccess triggers twice on load, meaning it sets the value right away. What I'm trying to do is to only have it set on change of url.
My route looks like this, I'm trying to set the value of a parameter
.state('medications', {
url: '/medications',
templateUrl: '/partials/home.html',
controller: 'mainController',
params: { showSection: false },
resolve: {
postPromise: ['medicationservice', function(medicationservice) {
return medicationservice.getAll();
}]
}
})
.state('medications.add', {
url: '/add',
templateUrl: '/partials/home.html',
controller: 'mainController',
params: { showSection: true },
})
in my controller I got the following, where I set the openSesame parameter to false explicitly on init, but as described it triggers and sets it to true.
mainModule.controller('mainController', [
'$scope',
'$state',
'$rootScope',
'medicationservice',
function($scope, $state, $rootScope, medicationservice) {
$scope.medication = {};
$scope.medications = medicationservice.posts;
$scope.openSesame = false;
$rootScope.$on("$stateChangeSuccess", function() {
$scope.openSesame = true;
console.log($scope.openSesame);
});
}]);
in my plunker the state change works once, that is if I use the $rootScope.

You can actually use $stateChangeSuccess without $injecting $rootScope. You can set a listener on the $scope object instead. Take a look at the following plunker.
And the revised code:
(function() {
var app = angular.module('myApp', ['ui.router']);
app.controller('mainController', [
'$scope',
'$state',
function($scope, $state) {
$scope.medication = {};
$scope.openSesame = false;
$scope.$on('$stateChangeSuccess',function(event, toState){
$scope.openSesame = toState.params.showSection;
});
$scope.triggerMe = function() {
alert('yes');
};
}
]);
app.config([
'$stateProvider',
'$urlRouterProvider',
function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('medications', {
url: '/medications',
template: '<div>{{openSesame}}</div>',
controller: 'mainController',
params: {
showSection: false
}
})
.state('medications.add', {
url: '/add',
template: '<div>{{openSesame}}</div>',
controller: 'mainController',
params: {
showSection: true
},
});
$urlRouterProvider.otherwise('medications');
}
]);
}());
Click your buttons medication and medication add to see the value change.

The callback of $stateChangeSuccess, you have access toState, fromState. Or check current state name
$rootScope.$on("$stateChangeSuccess", function() {
if ($state.current.name == "medications.add") {
$scope.openSesame = true;
}
console.log($scope.openSesame);
});

Related

$scope.myVar updates but not in the view

I have a template nested in an other template (menu is the parent template) which share the same controller. My Controller gets the value from a service called counterOperations. Althought $scope.total seems to be updating in console.log the view does not update the value.
Controller
.controller('ListController', function ($scope, $http, $state, counterOperations, userService) {
//Some code
$scope.add = function (index) {
$scope.total = counterOperations.getTopCounter();
console.log($scope.total);
};
})
Templates
$stateProvider
.state('app', {
url: '/app',
abstract: true,
templateUrl: 'templates/menu.html',
controller: "ListController"
})
$stateProvider
.state('app.list', {
url: '/list',
views: {
'products': {
templateUrl: 'templates/product-list.html',
controller: "ListController"
}
}
})
with ng-click I trigger a function which calls some functions from a service
The view variable for menu
<span>{{total}}</span>
I have tried to update the value this way but nothing changes
setTimeout(function() {
$scope.total = counterOperations.getTopCounter();
}, 1000);
Any ideas ?
Here your 2 states "app" and "app.list" have same controller, when you change state from "app" to "app.list" regardless of same controller controller will reinstantiated which means value in $scope.total variable will lost and will reset in next state.
Solution -
Assign total to $rootScope if you want it in other state too
$scope.add = function (index) {
$rootScope.total = counterOperations.getTopCounter();
};
.controller('ListController', function ($scope, $http, $state, counterOperations, userService) {
//Some code
$scope.total = ''; //or $scope.total = 0;
$scope.add = function (index) {
$scope.total = counterOperations.getTopCounter();
console.log($scope.total);
};
})
Check if the above works for you?

stateParams vs $stateParams with ui-router?

I am confused. For a long time now I have been using stateParams as a means of find out the stateParams inside a templateUrl.
Now I tried to do the same in a resolve and it does not work. In fact nothing happens when I use stateParams.
However by chance I found that I can use $stateParams in the resolve and it works.
Can someone tell me what is the difference and why do I need to use stateParams in the templateUrl and $stateParams in the resolve?
var auth = {
name: 'auth',
url: '/Auth/:content',
templateUrl: function (stateParams) {
var page = 'app/auth/partials/' + stateParams.content + '.html';
return page;
},
controller: function ($scope, authService) {
$scope.aus = authService;
},
resolve:
{
init: function ($stateParams) {
var x = 99;
return true;
}
}
};
I've created working example here, showing that $statePrams are accessible in the resolve
// States
$stateProvider
.state('auth', {
url: "/auth/:content",
templateUrl: 'tpl.html',
controller: 'AuthCtrl',
resolve : {
init : ['$stateParams' , function($stateParams){
return { resolved: true, content: $stateParams.content };
}]
}
})
Controller
.controller('AuthCtrl', ['$scope', 'init', function ($scope, init) {
$scope.init = init;
}])
and this could be the calls
auth/8
auth/xyz
Check it here

Can't transition to previously activated state using ui-router-extras Sticky State

Using ui-router-extras Sticky State (Parallel States) and Deep State Redirect as per http://christopherthielen.github.io/ui-router-extras/#/sticky, I'm unable to transition to a state that was previously activated.
app.js
'use strict';
angular.module( 'StickyStateDemo', [
'ui.router',
'ct.ui.router.extras',
'StickyStateDemo.controllers'
])
.config(function($stateProvider, $stickyStateProvider, $urlRouterProvider) {
var states = [];
$stickyStateProvider.enableDebug(true);
states.push({name: 'contentview', url: '/',
views: {
'#': {controller: 'ContentViewCtrl', templateUrl: 'contentView.tpl.html'}
}});
states.push({name: 'contentview.small', url: 'small/{myId}',
views: {
'smallview#contentview': {controller: 'SmallViewCtrl', templateUrl: 'smallView.tpl.html'}},
deepStateRedirect: true, sticky: true
});
states.push({name: 'contentview.large', url: 'large/{myId}',
views: {
'largeview#contentview': {controller: 'LargeViewCtrl', templateUrl: 'largeView.tpl.html'}},
deepStateRedirect: true, sticky: true
});
angular.forEach(states, function(state) { $stateProvider.state(state); });
$urlRouterProvider.otherwise('/');
})
.run( function run ($rootScope, $state, $stateParams) {
$rootScope.$state = $state;
$rootScope.$stateParams = $stateParams;
});
controllers.js
'use strict';
angular.module('StickyStateDemo.controllers', []);
angular.module('StickyStateDemo.controllers')
.controller('MainCtrl', function ($scope, $state) {
$scope.launchSmallView = function() {
$state.go('contentview.small', {myId: 1});
};
$scope.launchLargeView = function() {
$state.go('contentview.large', {myId: 1});
};
})
.controller('ContentViewCtrl', function ($scope) {
})
.controller('SmallViewCtrl', function ($scope) {
})
.controller('LargeViewCtrl', function ($scope) {
});
Plunker with the entire application: http://plnkr.co/edit/yvtoUle0ZUWkSOmjlCoQ?p=preview You can enter both states fine the first time, but trying to return to a previously activated state will fail.
I'm probably just missing something, but I've scoured the interwebs for examples and tried numerous variations, but everything I try results in this same behavior.
Turns out this is a bug in ui-router-extras: https://github.com/christopherthielen/ui-router-extras/issues/103. Reverting to ui-router v0.2.11 (and leaving ui-router-extras at v0.0.10) is a temporary fix.
UPDATE: This has since been fixed in ui-router-extras

unable to open a modal with angular and ui.routes

I am trying to follow this example to show a bootstrap modal on a certain state. It works fine without a modal (so the state config should be ok). All needed dependencies (ie angular bootstrap) should be available.
when I do a console.debug($stateParams) before $modal.open I get the correct data, within the $modal.open-method however the stateParams from the last state are returned (the state I am coming from)
Any hints?
EDIT
the relevant state cfg:
.state('publications.view', {
parent: 'publications.productSelection',
url: '/{productSlug:[a-zA-Z0-9-]+}/{docID:[0-9]+}_{slug:[a-zA-Z0-9-]+}',
onEnter: ['restFactory', '$state', '$stateParams', '$modal',
function(restFactory, $state, $stateParams, $modal) {
console.debug($stateParams.docID);
$modal.open({
templateUrl: 'partials/publication.html',
resolve: {
publication: ['restFactory', '$stateParams',
function(restFactory, $stateParams) {
console.debug($state.params);
console.debug($stateParams);
return restFactory.view($stateParams.language, $stateParams.productSlug, $stateParams.docID);
}
]
},
controller: ['$scope', '$sce', 'publication', '$rootScope',
function($scope, $sce, publication, $rootScope) {
$rootScope.pageTitle = publication.data.data.publication.Publication.title;
$scope.publication = $sce.trustAsHtml(publication.data.data.publication.Publication.content);
}
]
});
}
]
});
You can get around this issue by injecting the current $stateParams into the onEnter function, save them as state in some service, and inject that service instead into your modal resolves.
I am adapting the code from here: Using ui-router with Bootstrap-ui modal
.provider('modalState', function($stateProvider) {
var modalState = {
stateParams: {},
};
this.$get = function() {
return modalState;
};
this.state = function(stateName, options) {
var modalInstance;
$stateProvider.state(stateName, {
url: options.url,
onEnter: function($modal, $state, $stateParams) {
modalState.stateParams = $stateParams;
modalInstance = $modal.open(options);
modalInstance.result['finally'](function() {
modalInstance = null;
if ($state.$current.name === stateName) {
$state.go('^');
}
});
},
onExit: function() {
if (modalInstance) {
modalInstance.close();
}
}
});
};
})
Then in your app config section
.config(function($stateProvider, $urlRouterProvider, modalStateProvider) {
modalStateProvider.state('parent.child', {
url: '/{id:[0-9]+}',
templateUrl: 'views/child.html',
controller: 'ChildCtrl',
resolve: {
role: function(Resource, modalState) {
return Resource.get({id: modalState.stateParams.id}).$promise.then(function(data) {
return data;
});
}
}
});
}

AngularJS, What kind of $scope?

I have started with angular but I have some problem with kind of object in angular.
What kind of $scope in this screen? and how to get 'title' in that.
Here is my code.
define(['angularAMD', 'angular-route'], function(angularAMD) {
var app = angular.module("coreModule", ['ngRoute']);
app.config(['$routeProvider', '$locationProvider',
function($routeProvider, $locationProvider) {
$routeProvider
.when("/home", angularAMD.route({
templateUrl: 'home.html',
controller: 'HomeCtrl',
title: 'Home',
controllerUrl: 'ctrl/home',
})).
when("/list", angularAMD.route({
templateUrl: 'views/news.html',
controller: 'newsCtrl',
controllerUrl: 'ctrl/news'
})).
otherwise({
redirectTo: '/home'
});
$locationProvider.html5Mode({
enabled: true,
requireBase: true,
});
}
]);
app.run(['$rootScope', '$route',
function($rootScope, $route) {
$rootScope.$on('$routeChangeSuccess', function() {
console.log($rootScope);
});
}
]);
app.factory('Page', function() {
var title = 'default';
return {
title: function() {
return title;
},
setTitle: function(newTitle) {
title = newTitle;
console.log(title);
}
};
});
return angularAMD.bootstrap(app);
});
I want to get 'title' from controller.
Any idea? Thanks
I am still not sure what you are trying to do but here is my guess.
If you are trying to set the page title from the controller then here is how I would do it. And that is Not set it from the controller. I would set it on the state as you have already done and then pick it up on every state change.
aspStratMed.run(['$rootScope', function ($rootScope)
{
$rootScope.$on('$stateChangeStart', function (event, toState)
{
if (toState.data && toState.data.pageTitle)
$rootScope.pageTitle = toState.data.title;
});
And then in the HTML just use this where every you need the page title
{{pageTitle}}

Resources