I have got a controller named newGroupCtrl whose definition is like :
.state('new_group', {
url: '/new_group',
templateUrl: 'templates/new_group.html',
controller: 'newGroupCtrl'
})
.controller('newGroupCtrl', function ($scope, $rootScope,$ionicHistory,$window) {
$rootScope.roomId = $scope.getRoom();
$scope.getRoom = function () {
var date = new Date;
var minutes = date.getMinutes();
var hour = date.getHours();
return 'room_' + hour + '' + minutes;
};
}
I reach this contoller from previous page by :
$window.location.href = ('#/new_group');
That's good until now. $rootScope.roomId variable is initialized in the newGroupCtrl controller properly.
From this new_group page, I navigate to another page. And when I navigate back to this page by calling $window.location.href = ('#/new_group');,
$rootScope.roomId is not initialized again, instead its old value is still there. The state of the newGroupCtrl is preserved.
How can I completely reinitialize newGroupCtrl?
You need to tell state that reload controller each time when URL is getting accessed via browser by just adding adding reload option of state to true like reload: true.
Code
.state('new_group', {
url: '/new_group',
templateUrl: 'templates/new_group.html',
controller: 'newGroupCtrl',
reload: true //will reload controller when state is being access
});
You should use $state.go('new_group') instead of doing $window.location.href = ('#/new_group'); which will ensure that the route changes will recognize by ui-router.
Same SO answer here
Since you are using Ionic Framework (Good Job), you can do this:
.controller('YourCtrl', function($ionicView){
$ionicView.enter(function(){
//code that you want to run, each time the view is active
});
});
Remove the controller from :
.state('new_group', {
url: '/new_group',
templateUrl: 'templates/new_group.html',
})
And add the controller at "new_group.html" page with parent tag of the page like:
<div ng-controller="newGroupCtrl"></div>
Also I found helpful (for Ionic Framework) to use
.state('new_group', {
url: '/new_group',
templateUrl: 'templates/new_group.html',
cache: false
})
Reference to similar question and problems:
Reloading current state - refresh data or in sjm's answer in Reinitialize Controller every time when visiting View - Ionic Framework
Related
I am using UI Router with html5Mode enabled, states are loaded from JSON.
Expected behavior after F5 or when pasting URL is, respectively, having current state reloaded or navigating to the said state, instead the initial application state is loaded.
For e.g. root/parent/child gets redirected to root/.
By the way, navigating with ui-sref works fine.
So, how can the state be retained after page reload?
In order to retain the state of page after reload app, a url represent the state should be gave. when you include ui-route module, url will be parsed and sent to corresponding state. You don't need to parse the url handly in most cases, ui-route born to do this.
Please can you post your code here? Specifically the $stateProvider.
This is an example of a correct $stateProvider and it works fine:
$stateProvider.state('main.admin', {
url: '/admin',
resolve: {},
views: {
'main-content#main': {
controller: 'AdminController as admin',
templateUrl: 'main/admin/admin.tpl.html'
}
}
});
Seems a bit hacky, but works for now.
app.run(['$location', '$state', function ($location, $state) {
function stateFromUrl () {
var path = $location.path(),
hash = $location.hash();
// do JSON states map parsing and find a corresponding to the URL state
return state;
}
if (stateFromUrl) {
$state.go(stateFromUrl);
} else {
$state.go('home'); // initial state
}
}]);
I'm starting out with Angular through the Ionic Framework but I am failing to understand why the controller only runs once i.e. I change state, the controller runs, change to another state and then back again and the controller does not run a second time. This is my state:
$stateProvider.state( 'container.previous', {
url: 'previous',
views: {
main : {
templateUrl : 'views/previous.html',
controller : function( $scope, $cordovaSQLite ){
$scope.firms = [];
$cordovaSQLite.execute(window.db, "SELECT * FROM recent GROUP BY phone ORDER by id DESC").then(function(res) {
for (i = 0; i < res.rows.length; i++) {
$scope.firms.push(res.rows.item(i));
}
}, function (err) {
console.error(err);
});
}
}
},
onStateChangeStart : function(){
backButton = true;
}
});
In another state, if you click on a button related to a "firm", it saves the "firms" data to local storage. The above state shows the firms in which you have previously clicked on. But I cannot figure out how to update the $scope.firms correctly as the controller never runs again.
Can anyone help me out?
You can put the code you want to run in $ionicView.enter:
controller : function( $scope, $cordovaSQLite ){
$scope.$on('$ionicView.enter', function() {
// code to run each time view is entered
});
...
});
See "View LifeCycle and Events": https://ionicframework.com/docs/v1/api/directive/ionView/
Building on #brandyshea's answer, I would like to add if you want to specify no caching in one area/controller/state, and take advantage of the caching in other areas, you can simply use the cache parameter in your $stateProvider for that state.
Disable cache within state provider
$stateProvider.state('myState', {
cache: false,
url : '/myUrl',
templateUrl : 'my-template.html'
})
Alternatively, you can use one of the other methods too:
Disable cache with an attribute
<ion-view cache-view="false" view-title="My Title!">
...
</ion-view>
Disable cache globally
The $ionicConfigProvider can be used to set the maximum allowable views which can be cached, but this can also be use to disable all caching by setting it to 0.
$ionicConfigProvider.views.maxCache(0);
References: http://ionicframework.com/docs/api/directive/ionNavView/ and http://ionicframework.com/docs/api/directive/ionView/
You don't need to disable entire app cache.
If you want to re-run controller every time you enter on it you should clear cache before you leave it:
$scope.$on("$ionicView.afterLeave", function () {
$ionicHistory.clearCache();
});
Ionic has a cache mechanism inside. You can disable caching globally in your config function like this :
$ionicConfigProvider.views.maxCache(0);
Put this in your ion-view.
<ion-view cache-view="false">
I'm new in AngularJS Community and I'm developping my first app with this Framework.
I created a new controller with this code :
.controller('AccountCtrl', function($scope, $location) {
alert('test');
})
And my route :
.state('app.account', {
url: "/account",
views: {
'menuContent': {
templateUrl: "templates/account.html",
controller: 'AccountCtrl'
}
}
})
The alert popup is shown the first time I access to the controller. But, if I change URL and I come back to AccountCtrl (with a classic html a), the alert popup is not shown again.
Could somebody explain to me why ?
Thanx for your help !
In Ionic Framework views and controllers will be cached by default. You ma add a listener to the views scope to receive a notification when the view is re-active again. For more information see: http://ionicframework.com/docs/api/directive/ionView/
and http://ionicframework.com/docs/api/directive/ionNavView/
You may also disable the cache on a view <ion-view cache-view="false">
.controller('AccountCtrl', function($scope, $location) {
$scope.$on('$ionicView.beforeEnter', function () {
// update campaigns everytime the view becomes active
// (on first time added to DOM and after the view becomes active after cached
alert('test');
});
})`
to reload Controller each time in ui router, use reload: true option on the .state
$stateProvider
.state('app.account', {
url: "/account",
reload: true //forcefully reload route and load controller again
})
I'm trying to get my app working so that I can update the URL but without re-loading the whole view. I simply want to update the model and change the URL to reflect the new item being displayed.
I'm using this solution to achieve this: http://joelsaupe.com/programming/angularjs-change-path-without-reloading/
But I have a couple of issues with it:
1) The back/forward buttons on the browser no longer work - so I basically need to update the model when the URL changes and not just update the URL when the model changes..?
2) Once I've updated the URL without reloading the page, clicking on further links, such as menu options of the sort 'Books' no longer work. I can only get the navigation to work again by refreshing the page.
Does anyone have a solution to these problems? I would have expected that this sort of behaviour is common in a single page application, so it feels like I'm doing something wrong.
By the way, I'm using the angular-route module, but I'm happy to switch to angular-ui-router module if it makes life easier.
EDIT: Adding current code examples
I currently have something like this in the .config block of my main app module:
$routeProvider
.when('/books', {
title: 'Books',
templateUrl: CONFIG.static_url + '/html/books.html',
controller: 'BooksCtrl',
})
.when('/book/:itemId', {
title: 'Books',
templateUrl: CONFIG.static_url + '/html/books.html',
controller: 'BooksCtrl'
})
.otherwise({
redirectTo: '/books'
});
Then, in the run block, I have the code taken from the linked solution above:
// prevent reloading of view if reload = false
// TODO: fix issue where back button does not reload previous view
// TODO: fix issue where menu links no longer load page after
var original = $location.path;
$location.path = function (path, reload) {
if (reload === false) {
var lastRoute = $route.current,
un = $rootScope.$on('$locationChangeSuccess', function () {
$route.current = lastRoute;
});
}
return original.apply($location, [path]);
};
Finally, when I asynchronously change the model to load in a new item, I update the URL:
// update the url
$location.path('/book/'+id, false);
I have angularjs project implemented multi-language and using ui-router for routing. Every language will be have different url. Ex:
http://example.com/!#/en-us/english-title
http://example.com/!#/es-es/spanish-title
All state with url registered automatically when app run and load them from database. Ex:
angular.module('bxApp').run(["$http", function ($http) {
$http.get('/Home/Routes').success(function (result) {
result = result || {};
if (angular.isDefined(result) && result !== null) {
_.each(result.Routes, function (route) {
stateProvider.state(route.Name, {
url: route.Url,
templateUrl: route.TemplateUrl,
controller: route.Controller,
});
});
}
});
}]);
It work well but it will not work when user copy this link and paste to browser or click this link from other website . I think because of state can't found so it will be redirect to default and it does not keep url that user enter or copy.
In this case , How to do that?
Thanks,
You're declaring your states as a result of an HTTP call to your server: the problem is that these states are defined too late for the user to navigate to them when he pastes the URL in a new tab.
To understand, let's deconstruct what happens :
The user is on the initial page / other website, and copies the URL.
He pastes it in a new tab
Your angular application loads, finishes its config phase without having declared any of those states, and sends an HTTP call.
ui-router fails to route to a state matching the pasted URL, since the corresponding state is not here yet, and redirects to default
The HTTP response comes back, and your states are created (but too late).
How to make it work ?
My first reaction would simply not to store your states on your server. Unless you want the very core of your UX to be language-dependent, you don't have to do that.
But hey, let's say we want to do it anyway. I suggest you try this : declare a toplevel 'language' state, and have it load the other states in a resolve clause. This will 'block' the routing until the other states are declared :
angular.module('bxApp')
.config(['$urlRouterProvider', function ($urlRouterProvider) {
$urlRouterProvider
.state('language',{
url: '/:language',
resolve: {
childrenLoaded: ['$http', function ($http) {
// returning a promise is essential to have the 'waiting' behavior
return $http.get('/Home/Routes').then(function (data) {
var result = data.result || {};
if (angular.isDefined(result) && result !== null) {
_.each(result.Routes, function (route) {
$stateProvider.state(route.Name, {
url: route.Url,
templateUrl: route.TemplateUrl,
controller: route.Controller
});
});
}
});
}]
}
})
}]);
Again, this approach is probably asking for trouble : I strongly recommend you hardcode your states instead of storing them in a database. If all that varies from one language to another is the text and URL, then you will be fine with an URL param.