How to prevent route changing? - angularjs

I have a service in which inside I bind a click event:
$('button').click(function() {
alert('Clicked');
return false;
});
The issue is when I do not start at the default "/" route (i.e. "/testroute"), then that same button when clicked, causes the page url to go to "/" and not fire my event at all. When I click on it again after the route changes to "/", the event triggers as normal. How do I make it such that if I were to start at /testroute (even though it has the same view, different controller, but shares the same service, the alert will fire?

Use locationChangeStart. Also read the link Andrey posted.
$rootScope.$on('$locationChangeStart', function(e) {
e.preventDefault();
});

You might want to use these events to prevent route changing.

Related

How to distinguish link click vs transitionTo

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.

AngularUI Router - scroll to element on state change

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.

How to change the URL without reloading the page when back button is clicked in angularjs?

I am using angularjs for my app. It contains a newsfeed. If user needs to view the particular news, he has to click on that particular news and it will redirect to that news. And after viewing the particular news, if user wants to go back to news feed(previous page), he has to click on the browser back button. So, in this case, if user clicks on the browser back button, the newsfeed page is reloading again. But, I dont want like this. I want to disable the reload and take the user to the place where he was before. I browsed a lot on this issue, but there was no absolute solution given. Please, help me out.
When you go back, previous route will be triggered and data will be reloaded. If you want to prevent reloading, place a service in between and cache the data.
$routeProvider.
when('/loadFeeds',{
controller:'LoadFeedCtrl',
templateUrl:'pages/feeds.html',
resolve:{
initData : function(FeedService){
return $q.all(
{
data: FeedService.load()
}
);
}
}
})
And in your FeedService, instead of making http call try to see the data is already available
.service('FeedService',function($q,$timeoute){
this.feeds=[];
this.load = function(){
var deferred = $q.defer();
$timeout(function(){
if(feeds.length===0){
this.feeds.push({title:'First','id':1})
this.feeds.push({title:'Second','id':2})
this.feeds.push({title:'Third','id':3})
this.feeds.push({title:'Fourth','id':4})
}
deferred.resolve(this.feeds);
},2000);
return deferred.promise;
};
})
The timeout service could be replaced with $http or $resource. I used the timeout to simulate the delay
you can take an anchor link and on click event of anchor call this
javascript function
window.window.history.back();
here is the html code for it
<input type="button" id="alnkBack" onclick="window.window.history.back();" value="Back" class="button" />

Order of routeChangeStart event and rendering

I have a run function for a module and inside it there is a $routeChangeStart event binding. I would like to know time of the first routeChangeStart event triggered. I am expecting that it should be called immediately after first request but before any page render but it is not as I expected. It seems that the event is called after page started to be rendered.
module.run(function ($location, $rootScope) {
$rootScope.$on("$routeChangeStart", function (event, next, current) {
//do something with next.xxx
});
})
What is the expected behaviour? Or this is a bug?
The event is fired before the page starts rendering, but that doesn't mean you'll catch it before the rendering begins. The event gets fired, then the next thing in the call stack is when Angular begins the page rendering (fetching the template, waiting for the route resolve property, etc) and you catch the event after that. From the angular docs...
Broadcasted before a route change. At this point the route services
starts resolving all of the dependencies needed for the route change
to occur. Typically this involves fetching the view template as well
as any dependencies defined in resolve route property. Once all of the
dependencies are resolved $routeChangeSuccess is fired.
If you need to do something like conditionally preventing the change, try using the $locationChangeStart event instead. For example...
$scope.$on('$locationChangeStart', function (event) {
if (someCondition) {
event.preventDefault(); // prevent the change
}
});
This will be run before Angular starts loading the new page.

Backbone View injected links reload Site

After rendering a Backbone View I inject HTML generated with jQuery. This HTML also includes links within the application. If you click those links they reload the site.
How can I bind those links so they will trigger the router and don't reload the site?
You have to bind a click event to those links and call Router.navigate. It's important that you return false from your event handler as this will prevent the borwser to actually follow the link. Another important thing is to pass trigger: true to actually have your router execute (otherwise it will only change the url displayed in the address bar).
events : {
'click a.changeView' : 'changeView'
},
changeView : function(e) {
Router.navigate(e.target.href, { trigger: true });
return false;
}
Also, you might have to tweak your href a bit if it contains protocol, domain, etc... for instance if your href is http://mydomain.com/mypage you might need to pass only mypage to the router.

Resources