I am trying to remember the scroll position of a page using that code:
$rootScope.$on('$locationChangeStart', function(angularEvent, nextRoute, currentRoute) {
$rootScope.scrollPosCache['dailyController'] = $window.pageYOffset;
});
When the page infinitely-scrolls I am using ui-router's transitionTo to modify the current url in the browser history like that:
$state.transitionTo('daily', { page: pageIndex }, { notify: false, location: 'replace' });
the transition changes the search string to e.g.: http://example.com/?page=1/2/3/4/etc
so, the $locationChangeStart code is running both when I make the transition and when the user leaves the list page to follow a link to a detail page.
How do I know the location change has come from a transition and not from a click through? (I only want to remember the scroll position when the page is left)
The solution is to use $stateChangeStart and not $locationChangeStart.
Related
I have an Angular app with various different states defined. I do not want the user to be able to go back to previous states using the back button, as they are part of a simulation and it disturbs the simulation flow.
Is there a way I can override the browser back button to take users to the starting state of the simulation?
angular.module('participant').config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('simulations', {
url: '/',
controller: 'SimulationIndexController',
templateUrl: '/angular_templates/simulations/index.html',
})
.state('simulation.content', {
// other routes
});
I want to go to the 'simulations' state when the user presses the back button on the browser but I am not sure how to accomplish this.
Use location: 'replace' when doing state transitions:
$state.go("simulation.content.state2",{location:'replace'});
By using the replace option, the individual simulation steps will not be stored in the browser history. When the user hits the back button, the user will be taken back to the beginning instead of the previous content.
You could add on top
.run(function($state) {
$(window).on('popstate', function(event) {
// This event fires on current history change
$state.go("simulations");
}, false);
})
I have searched on StackOverflow for the last five hours and none of the related answers quite solve my problem. I have an UI-Router state that loads a long list of messages generated from a custom directive. This page is linked too in many places pointing to a different message. I want to scroll to the currently selected message.
I can get this to work using $anchorScroll if I surround the call with a $timeout. $timeout(function(){$anchorScroll()};) but if the $timeout is not there a call to $anchorScroll does nothing since the View has not completely loaded.
Here is most of the relevant code.
<message id='message{{message.id}}'
ng-repeat='message in messages'
message='message'
ng-class="{'current':current == 'message{{message.id}}'}" >
</message>
In the controller I set current to $scope.current = $location.hash(). This all works.
If I load the page like #/messages#message100 directly the page will correctly scroll. However, if from a different view I use the a link such as this:
<button ui-sref="message-state({'#':'message{{message.id}}'})>
Go To Message {{message.id}}
</button>
The page will not automatically scroll to the correct anchor since the message list has not been made yet. But by putting the call to $anchorScroll() in a $timeout I can make the page scroll.
I don't like using $timeout for this purpose. I know I am not supposed to manipulate the DOM in a controller like this.
I have tried registering the call to $anchorScroll() with many of the $stateProvider events such as:
$state.$on('$viewContentLoaded', function(event) {
$anchorScroll();
});
But even at the time the $viewContentLoaded fires the message list does not exist in the DOM and the page does not scroll.
IWhat is the best way to make the UI-Router scroll based on the $location.hash().
Even I was facing a similar situation and after days of try and error, I came up with this.
In ui router add an id parameter to the state on which you want to enable the scroll.
$stateProvider.state('index', {
url: '/',
params: {
id: null
}
})
Then in the html use ui-sref
<li><a ui-sref="index({id: 'about-us'})" >About Us</a></li>
At last in the app.run module detect the state change using
$rootScope.$on('$viewContentLoaded', function(event){
if ($state.current.name == 'index') {
if($stateParams.id) {
$anchorScroll.yOffset = 150;
$location.hash($stateParams.id);
$timeout(function(){$anchorScroll()}, 1000);
}
}
});
Hope this helps. Would do a plunkr if needed.
I try to do some functionality that accepts a state navigation (using $state.go(otherState)), refreshing the associated url in the adress/url bar but it blocks (or redirects to not allowed page) if user directly puts this url in the adress/url bar.
Could it be done by ui-router rules or something inside ui-router module?
I put the example code:
$stateProvider.state("main", {
url: "/index.html",
templateUrl: "main.html"
}).state("notAccessibleScreenByBar", {
url: "/private/example.html",
templateUrl: "example.html"
});
From main view (index.html), the next angular code will be executed:
$state.go("notAccessibleScreenByBar");
This action changes the view, loading example.html and refreshing the url bar to /private/example.html.
If user puts /private/example.html in the adress/url bar, ui-router must block this request (or redirect to not-allowed page).
What you are trying to do seems very similar to any web authentication standard, but, if you don't want that, you could use $locationChangeSuccess (docs here)
A basic example inspired by this sample:
$rootScope.$on('$locationChangeSuccess', function(e, newUrl, oldUrl) {
// Prevent $urlRouter's default handler from firing
e.preventDefault();
if(isThisTransitionValid(newUrl, oldUrl)) {
// Ok, let's go
$urlRouter.sync();
});
});
I have my app that you need to login to get in to the other pages.
so the first page is "login" and it checks if you are already logged, if so you will be redirected to the main page app, if not it will show you the login page.
now the problem is when the user is inside the logged page area, and he clicks back he will get to the "login" page and than redirected back to the main page, as he is logged in already.
So he is stuck in an infinite loop.
how can I remove the login page from the history.
just like in android "android remove activity from history stack"
here is the solution!
simply use:
$ionicHistory.nextViewOptions({
disableBack: true
});
example for login function:
$scope.login = function () {
Security.login($scope.cred.email, $scope.cred.password)
.success(function(data) {
Security.setUser(data.data[0]);
$ionicHistory.nextViewOptions({
disableBack: true
});
$state.go('posts', {}, {location: "replace", reload: true});
}).error(function(data) {
$scope.showAlert();
});
};
For a pure AngularJS way to accomplish this (rather than ionic or javascript in the other answers), use the $location service's replace() method (documentation) :
Use $location.url('/newpath'); or $location.path('/newpath'); as you normally would to do the redirection in angular. And then just add $location.replace(); right after it. Or you can chain the commands like this:
$location.url('/newpath').replace();
Quick search: https://stackoverflow.com/a/8969975/185672
Top answer:
Instead of using window.location = url; to redirect,
try window.location.replace(url);.
after using replace() the current page will not be saved in session
history, meaning the user won't be able to use the Back button to
navigate to it.
How to config UI Router to reenter or reload the state by default?
E.g. user wants to refresh page, so he clicks the link that follows to that page. But currently the link isn't clickable, as it goes to the same page and the state doesn't change. Refreshing with browser button does work, so it reloads entire SPA again - isn't desirable.
This question - Reloading current state - refresh data - describes similar effect. Is it possible to change this solution - https://stackoverflow.com/a/23198743/404099 - to define the default behavior?
By the way, probably my approach is incorrect and I'm missing some basic idea in UI Router. Please point out if this is the case.
I second what #Sabacc said, but if you still instead, here you go:
angular.module('app')
.config(function($provide) {
$provide.decorator('$state', function($delegate)
{
$delegate.go = function(to, params, options)
{
return $delegate.transitionTo(to, params, angular.extend(
{
reload: true,
inherit: true,
relative: $delegate.$current
}, options));
};
return $delegate;
});
});