Type: bug
Platform: all
following scenario:
?category=all?category=pants,tops,socks$ionicHistory.goBack()?category=all instead of the last params
Seems to be related to these other issues: #3551 #3884 #3551
Quicky walkthrough over ionicHistory file shows that it looks like view.stateParams are set only once during registration step and never update again hence getting out of sync with real $state.params.
https://github.com/driftyco/ionic/blob/master/js/angular/service/history.js#L361
Digging more into the ionic codebase, here is my interpretation so far:
Background: Ionic navigation data is persisted on $ionicHistory.viewHistory and each view in the history has the properties: stateName, stateParams and url.
Architecture Dissonance: Ionic navigation/history is structured in terms of "views" while the angular-ui-router library has the concept of "states", different interpretation of similar things. The cardinality between view and state is not necessary 1x1, you can navigate within the same view across different possible states (eg: search and search result; being two distinct states displayed in the same view ).
This introduce an synchronisation complexity, meaning you have to keep the current view information in sync with current state params, otherwise eventually you will lose information during navigation.
Issue
view.stateName and view.stateParams are not updated as user navigate thought different states ( within the same view ).
Workaround
As of now I've been spiking possible solution, and this code snipped seems to be doing the right think, I don't recommend using it in production by any means:
$rootScope.$on('$locationChangeSuccess', function () {
if (! $ionicHistory.currentView()) { return }
//extracted from $ionicHistory
function getCurrentStateId() {
var id;
if ($state && $state.current && $state.current.name) {
id = $state.current.name;
if ($state.params) {
for (var key in $state.params) {
if ($state.params.hasOwnProperty(key) && $state.params[key]) {
id += "_" + key + "=" + $state.params[key];
}
}
}
return id;
}
// if something goes wrong make sure its got a unique stateId
return ionic.Utils.nextUid();
};
var currentView = $ionicHistory.currentView();
currentView.stateId = getCurrentStateId();
currentView.stateName = $state.current.name;
currentView.stateParams = angular.copy($state.params);
});
The idea is to update currentView state every time there is an update on the url as well, this way the viewHistory will always be consistent with the $state.params.
In order to make this solution work I had to pull the getCurrentStateId() function out of the $ionicHistory.
If this is the right thing to do we should probably move this code snippet to inside the $ionicHistory itself.
Feeback
I am looking forward to hear from the more senior contributors if they see any problem with this approach.
More information on this.
I were able to reproduce issue when you have an ui-view inside an ion-nav-view:
State:
$stateProvider
.state('parent', {
template: '<ion-view>Parent View: <ui-view></ui-view></ion-view>'
})
.state('parent.child', {
template: 'Child View: {{childStateParam}}',
params: {
childStateParam: 'Initial Value'
}
})
.state('foo', { template: 'bar' })
Javascript*
/** activate state 'parent.child' with default param will register a new transition**/
$state.go('parent.child');
/** activate again state 'parent.child' but with different param will not register a new transition
because we are still in the same view **/
$state.go('parent.child', {childStateParam: 'New Value'});
/** activate a new view will register a new transition**/
$state.go('foo');
/** go back should register a transition back to previous view with the latest known params**/
$ionicHistory.goBack();
$state.params.childStateParam === 'InitialValue'; //(true but should be false)
Example
http://codepen.io/thiagofelix/pen/aOPJWZ/
Solution
Change navView.updateView function to update the current view information after $stateChangeSuccess event is fired.
It also require $ionicHistory to have this function exposed so it can receive updates requests.
Greetings @zwacky!
I've closed this issue because my sensors indicated it was old and inactive, and may have already been fixed in recent versions of Ionic. However, if you are still experiencing this issue, please feel free to reopen this issue by creating a new one, and include any examples and other necessary information, so that we can look into it further.
Thank you for allowing me to assist you.
So, a question...why are you modifying the stateParams for your view? You should expect that you got that data from a navigation, and using it again won't be correct.
Instead, it sounds like a better idea would be to cache their search and filtering history in a local storage or in-memory cache rather than relying on stateParams again. Something like:
$scope.$on('$ionicView.enter', function() {
$scope.filter = getStoredFilter('shoes') || $stateParams.filter;
});
I think I'm going to close for now, if only because we can hack uiRouter and our nav forever, but there is a really complex dance here. v2 will really simplify the navigation process and make this really easy to do.
Let me know if you have any additional thoughts.
EDIT: thanks for the snippet, I'm going to see if I can fix that specific state because I see what you're saying. That should be a unique navigation.
Thank you @mlynch for taking a look, I wish I had more time to dig further here, It is indeed hard to explain the navigation, I tried hard to provide context and enough detail, even them still hard to follow.
I kept the workaround snipped on the application I was working on and the temporary solution became the final one.
Congratz for the V2 stuff, I am playing with it and is really cool! =)
@thiagofelix Your fix worked for me. Thanks for posting it, it's been very frustrating trying to figure this one out.
The solution with ionic v1 is on back button click function that you called $ionicHistory.goBack();
so the state params not changed when navigating and you also pass objects in state params(productData) like this:
.state('app.product', {
url: '/product', //:prod_id
views: {
'menuContent': {
templateUrl: 'templates/product.html',
controller: 'ProductCtrl'
}
},
params: {productData : null},
cache: false
})
$ionicPlatform.registerBackButtonAction(function(event) {
if ($state.current.name == "app.home") {
navigator.app.exitApp(); //<-- remove this line to disable the exit
} else {
// navigator.app.backHistory();
$ionicHistory.goBack();//very important;
}
}, 100);
Thanks for the issue! This issue is being locked to prevent comments that are not relevant to the original issue. If this is still an issue with the latest version of Ionic, please create a new issue and ensure the template is fully filled out.
Most helpful comment
@thiagofelix Your fix worked for me. Thanks for posting it, it's been very frustrating trying to figure this one out.