Controller is not being reset after href call - angularjs

I have a AngularJs controller in Ionic Framework.
.controller('LocationDetailCtrl', ['$scope','$cordovaGeolocation','$cordovaCamera', '$cordovaFile','$stateParams','Location', LocationDetailCtrl]);
function LocationDetailCtrl ($scope, $cordovaGeolocation, $cordovaCamera, $cordovaFile, $stateParams, Location) {
$scope.locationRow = {};
$scope.test = "";
$scope.images = [];
Location.getById($stateParams.locationId).then(function(result){
//alert("I'm in");
$scope.locationRow = result;
});
}
I have code in view somewhere that does this:
<ion-item class="item-remove-animate item-icon-right" ng-repeat="location in locations" type="item-text-wrap" href="#/locations/{{location.id}}/all">
<h2>{{ location.aplicant_name}}</h2>
<p>{{ location.form_type }}</p>
<i class="icon ion-chevron-right icon-accessory"></i>
<ion-option-button class="button-assertive" ng-click="remove(location)" translate>Delete</ion-option-button>
</ion-item>
In my stateprovider I have this:
.state('location-detail', {
url: '/locations/{locationId}',
abstract: true,
templateUrl: 'templates/location-detail.html',
controller: 'LocationDetailCtrl'
})
.state('location-detail.all', {
url: '/all',
views: {
'loc-detail-view': {
templateUrl: 'templates/location/location-map-all.html'
}
}
})
My problem is, on the first href click I get the values for database, its all alright. But when I go back and press another list time, I would get the same value I got earlier.
Turns out Location.getById() is not being called the second time around.

Never-mind, I found the answer.
Turns out my controller is being cached by default.
I modified the state provider with this code and it now refreshes the view with new model.
.state('location-detail', {
url: '/locations/{locationId}',
cache: false,
abstract: true,
templateUrl: 'templates/location-detail.html',
controller: 'LocationDetailCtrl'
})
The difference here is cache:false.
Cheers!

Ionic views are cached by default, However you can manually set the cache to false in the view, this will make the controller to load again.
read more here, How ever what you have done is also correct, But I personally prefer the method I mentioned here as it will give more control

If you want to keep your page cached for any reason you could wrap all of your function you need to run inside of another funciton and then on the event $ionicView.beforeEnter or afterEnter or enter, you can call that function. Then you can keep the page cached and still have all of your functions run everytime the page is entered. For example in an app i made I did not want to have the homepage uncached, but i need some funcitons to pull
fresh data everytime the page is entered. So I did this:
$scope.$on('$ionicView.beforeEnter', function () {
$scope.doRefresh();
});
That way the page can stay cached but my app still behaves like I want it to. Take a look at some more of the ionicView methods: http://ionicframework.com/docs/api/directive/ionView/

Related

ionic $state.go not loading page or showing error

I'm using $state.go() other places in my app but it's not working in a simple function and I can't work out why. It's not showing an error or showing the right state called in $state.go().
I've tested it with $stateChangeStart, $stateChangeError, $viewContentLoading & $stateChangeSuccess. It reaches all the correct stages: $stateChangeStart, $viewContentLoading then $stateChangeSuccess with the right content in each however, doesn't load the page.
I originally tried it with ui-sref and that didn't work so I tried it with $state.go() and now that isn't working I'm really confused. I can't see any difference between this code and what I have in other places where $state.go() works.
HTML link:
<li ng-repeat="thing in things" class="item" ng-click="showThingDetails()">
Code in controller:
$scope.showThingDetails = function () {
$state.go('thingDetails');}
Code in state:
.state('thingDetails', {
url: '/thingDetails',
views: {
'menuContent': {
templateUrl: 'templates/thingDetails.html',
controller: 'thingDetails'
}
}
})
thingDetails.html
<ion-view view-title="Thing Details">
<ion-content>
<h1>{{title}}</h1>
</ion-content>
</ion-view>
thingDetails.js
angular.module('controllers')
.controller('thingDetails', function($scope, $stateParams) {
$scope.title = "thing";
});
I've just found the answer to my own problem. I had copied the state from another place in my app and defining the templateUrl and controller in the views object was causing it to play up. I took templateUrl and controller out of the views object and it worked.
Code in state is now as below and works:
.state('sweepstakeDetails', {
url: '/sweepstakeDetails',
templateUrl: 'templates/sweepstakeDetails.html',
controller: 'sweepstakeDetails'
})
If anyone can add a more detailed answer as to why then I'd appreciate it.
Do you have an ui-view called 'menuContent' where the view should be loaded?
Else you could try to use this state without the menuContent views
.state('thingDetails', {
url: '/thingDetails',
templateUrl: 'templates/thingDetails.html',
controller: 'thingDetails'
})

UI Router Refreshing Page Instead on State Change

I've had no luck with this particular issue. Everything I've looked up has to do with people having issues 'trying' to refresh the page instead of my issue where it's refreshing every time I go to a certain state. This ONLY happens in IE not chrome.
Code:
app.config(function ($stateProvider, $urlRouterProvider) {
$stateProvider
.state('box', {
templateUrl: templatePath + 'box.html',
controller: 'BoxController',
controllerAs: 'box',
url: '/Box/{folder:string}'
})
.state('compose', {
templateUrl: templatePath + 'compose.html',
controller: 'ComposeController',
controllerAs: 'compose',
url: '/Compose/{messageSentId:int}'
})
.state('view', {
templateUrl: templatePath + 'view.html',
controller: 'ViewController',
controllerAs: 'view',
url: '/Box/{folder:string}/{messageId:string}/{messageSentId:string}'
});
$urlRouterProvider.otherwise('/Box/');
});
The problem is with my compose state. If I go directly to that state like so:
vm.compose = function () {
$state.go('compose', { messageSentId: 0 }, { notify: true });
};
It works just fine. However, if I add a different number besides 0 and call from a different controller it does not work:
vm.reply = function() {
var id = Math.floor($stateParams.messageSentId);
$state.go('compose', { messageSentId: id }, { notify: true });
};
I thought maybe it was having issues because it thought id was a string and therefore didn't match to /Compose/{messageSentId:int} so I added the Math.floor() but that didn't help.
Something to note is that if I fire my compose function first and go to that state the reply function will work. However, if I attempt to navigate with my reply function first the page reloads.
Another thing that I can confirm is that my controller for that page and the page itself loads just fine. You can actually see the form pop up briefly. The problem is once the controller has loaded a refresh is triggered. No errors. No nothing. Simply fails in IE.
After many hours of research and having found nothing similar to my issue on the web I made a simple change. I moved my state change out of my controller and used ui-sref instead:
Code:
<div class="btn-group pull-right" ng-if="view.canReply()">
<a class="btn btn-primary" ui-sref="compose({messageSentId: view.replyMessageId})">
<i class="fa fa-reply"></i> Reply
</a>
</div>
Where 'view' is my controllerAs since I don't use $scope and I set my $stateparameter on the variable replyMessageId. Maybe this will help someone.

How to run controller each time angularjs ui-router named view is activated?

In regular angularjs ui-router state the controller runs each time the state is activated. I found this not to be the case when dealing with named views in an ionic application. The named view controller runs only once per element(game). Eg. user displays a game -> controller runs. Then user goes to another state and upon their return to displaying the same game controller does not run again - the view uses an already generated scope from before. I would like reinitialise that games scope with controller.
My code:
//app.js
.state('app.game', {
url: "/x/{gameID:int}",
views: {
'menuContent': {
templateUrl: "templates/html/my-game.html",
controller: 'GameCtrl'
}
}
})
...
//controllers.js
controllers.controller('GameCtrl', function ($scope, $stateParams, Game) {
//alert("running controller");
Game.get({id: $stateParams.gameID}, function(res){
$scope.game = res;
});
})
Edit: I actually use this code to go to the view of game (currently playing with guid idea from Steven Wexler)
<ion-view view-title="Games">
<ion-content>
<h1>Games</h1>
<ion-list>
<ion-item nav-clear menu-close href="#/app/x/{{game.id}}?guid= {{guid()}}" ng-repeat="game in games">
{{game.id}}
</ion-item>
</ion-list>
</ion-content>
</ion-view>
I Think your problem is already solved in this post Angular / Ionic - controller only runs once
brandyshea says that you need to add the code you want to run in the $ionicView.enter event
controller : function( $scope, $cordovaSQLite ){
$scope.$on('$ionicView.enter', function() {
// code to run each time view is entered
});
...
});
You probably are navigating to a state with the same url and params that was previously loaded. One way to force a reload is to pass in a guid as a parameter with your state and set reloadOnSearch=true (it's true by default). The second way to force a reload is to use the reload option added in version 0.2.5.
Option 1
.state('app.game', {
url: "/x/{gameID:int}/{guid}",
views: {
'menuContent': {
templateUrl: "templates/html/my-game.html",
controller: 'GameCtrl'
}
}
})
$state.go("app.game", { gameId: id, guid: guid });
function guid() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
return v.toString(16);
});
}
Option 2 (if you have version >= 0.2.5)
.state('app.game', {
url: "/x/{gameID:int}",
views: {
'menuContent': {
templateUrl: "templates/html/my-game.html",
controller: 'GameCtrl'
}
},
reload: true
})
Note: Awesome guid function copied from Create GUID / UUID in JavaScript?

AngularJS ui-router: reload:true also reloads parent state

In this plunk you have two ui-router states, a parent and a child. When the child is invoked by clicking on the link, since it has the option reload: true it is always reloaded. This is fine, but the problem is that the parent state is reloaded as well. Try to click on the 'Populate 11' link several times and you'll see that the parent timestamp also changes.
How can I reload only the child?
Javascript:
var app = angular.module("app", ['ui.router']);
app.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise("/");
$stateProvider
.state('state1', {
templateUrl: 'state1.html',
controller: function($scope) {
$scope.theTime1 = Date.now();
}
})
.state('state1.state11', {
templateUrl: 'state11.html',
controller: function($scope) {
$scope.theTime11 = Date.now();
}
});
});
It's actually very simple.
Don't use reload because that does exactly what you found. It reloads everything for the route.
Instead, add a parameter to your child route and every time the link is clicked make sure to change that parameter. That will force the child state to be reloaded.
I updated your plunk with an example. I just added a num parameter and increase a count variable each time the link is clicked.
http://plnkr.co/edit/qTA39rrYFYUegzuFbWnc?p=preview
A changing parameter as Mathew Foscarini suggested, is (for sure) way to go. There could be also another solution, technique with state reloader. Below, and in this updated plunker we can see simplified version, but we can even pass some params there to make it more general
.state('state1.reloader', {
controller: function($state) {
$state.go('state1.state11')
}
})
And we can call it like:
// instead of this
<a href="#" ui-sref="state1.state11" ui-sref-opts="{reload: true}">
// we can do this
<a href="#" ui-sref="state1.reloader" >
Check it here

AngularJs: Reload page

<a ng-href="#" class="navbar-brand" title="home" data-translate>PORTAL_NAME</a>
I want to reload the page. How can I do this?
You can use the reload method of the $route service. Inject $route in your controller and then create a method reloadRoute on your $scope.
$scope.reloadRoute = function() {
$route.reload();
}
Then you can use it on the link like this:
<a ng-click="reloadRoute()" class="navbar-brand" title="home" data-translate>PORTAL_NAME</a>
This method will cause the current route to reload. If you however want to perform a full refresh, you could inject $window and use that:
$scope.reloadRoute = function() {
$window.location.reload();
}
**Later edit (ui-router):**
As mentioned by JamesEddyEdwards and Dunc in their answers, if you are using angular-ui/ui-router you can use the following method to reload the current state / route. Just inject $state instead of $route and then you have:
$scope.reloadRoute = function() {
$state.reload();
};
window object is made available through $window service for easier testing and mocking, you can go with something like:
$scope.reloadPage = function(){$window.location.reload();}
And :
<a ng-click="reloadPage" class="navbar-brand" title="home" data-translate>PORTAL_NAME</a>
As a side note, i don't think $route.reload() actually reloads the page, but only the route.
location.reload();
Does the trick.
<a ng-click="reload()">
$scope.reload = function()
{
location.reload();
}
No need for routes or anything just plain old js
Similar to Alexandrin's answer, but using $state rather than $route:
(From JimTheDev's SO answer here.)
$scope.reloadState = function() {
$state.go($state.current, {}, {reload: true});
}
<a ng-click="reloadState()" ...
If using Angulars more advanced ui-router which I'd definitely recommend then you can now simply use:
$state.reload();
Which is essentially doing the same as Dunc's answer.
My solution to avoid the infinite loop was to create another state which have made the redirection:
$stateProvider.state('app.admin.main', {
url: '/admin/main',
authenticate: 'admin',
controller: ($state, $window) => {
$state.go('app.admin.overview').then(() => {
$window.location.reload();
});
}
});
Angular 2+
I found this while searching for Angular 2+, so here is the way:
$window.location.reload();
This can be done by calling the reload() method in JavaScript.
location.reload();
It's easy enough to just use $route.reload() (don't forget to inject $route into your controller), but from your example you could just use "href" instead of "ng-href":
<a href="" class="navbar-brand" title="home" data-translate>PORTAL_NAME</a>
You only need to use ng-href to protect the user from invalid links caused by them clicking before Angular has replaced the contents of the {{ }} tags.
On Angular 1.5 - after trying some of the above solutions wanting to reload only the data with no full page refresh, I had problems with loading the data properly. I noticed though, that when I go to another route and then I return back to the current, everything works fine, but when I want to only reload the current route using $route.reload(), then some of the code is not executed properly. Then I tried to redirect to the current route in the following way:
$scope.someFuncName = function () {
//go to another route
$location.path('/another-route');
};
and in the module config, add another when:
.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/first-page', {
templateUrl: '/first-template',
controller: 'SomeCtrl'
}).when('/another-route', {//this is the new "when"
redirectTo: '/first-page'
});
}])
and it works just fine for me. It does not refresh the whole page, but only causes the current controller and template to reload. I know it's a bit hacky, but that was the only solution I found.
<a title="Pending Employee Approvals" href="" ng-click="viewPendingApprovals(1)">
<i class="fa fa-user" aria-hidden="true"></i>
<span class="button_badge">{{pendingEmployeeApprovalCount}}</span>
</a>
and in the controller
$scope.viewPendingApprovals = function(type) {
if (window.location.hash.substring(window.location.hash.lastIndexOf('/') + 1, window.location.hash.length) == type) {
location.reload();
} else {
$state.go("home.pendingApproval", { id: sessionStorage.typeToLoad });
}
};
and in the route file
.state('home.pendingApproval', {
url: '/pendingApproval/:id',
templateUrl: 'app/components/approvals/pendingApprovalList.html',
controller: 'pendingApprovalListController'
})
So, If the id passed in the url is same as what is coming from the function called by clicking the anchor, then simply reload, else folow the requested route.
Please help me improve this answer, if this is helps. Any, suggestions are welcome.
This can be done by calling the reload() method of the window object in plain JavaScript
window.location.reload();
I would suggest to refer the page. Official suggestion
https://docs.angularjs.org/guide/$location

Resources