Angular: Fixed Top Menu, switching page but not scrolling top - angularjs

I have a fixed top menu in Angular but when I try to switch page (within the app) the browser windows is not scrolling up.
I try to do this in my controller (this code is loaded every time i switch page within the app):
$('body').scroll();
window.scrollTo(0, 0);
$("html, body").animate({ scrollTop: 0 }, 100);
None of which is working.
Is there any trick that i am missing?
I tried this as well:
$location.hash('#top');
// call $anchorScroll()
$anchorScroll();
but without success

First of all, you should never attach DOM events or modify DOM from controller. You can use directives for that.
As per you question - AngularJS has an event called '$routeChangeSuccess'.
You can attach handler to this event with $scope.$on('$routeChangeSuccess', function () {...}) and run scrolling code inside.

Related

Angularjs UI-Router state change changes functionality of Google-API directive

I am using a google places autocomplete directive: vs-google-autocomplete
which works fine. The problem is, if we change the $state (by back / forward button, or just ui-sref="testroute", or $state.go()), it suddenly does not work the way it worked before.
I set up a plnkr:
google.maps.event.addListener(autocomplete, 'place_changed', function() {
console.log("place_changed");
});
google.maps.event.addDomListener(element[0], 'keydown', function(event) {
if (event.keyCode == 13 || event.keyCode == 9)
console.log("keydown");
});
http://plnkr.co/edit/wbhEWds1pY1bWrguV40U?p=preview
You can enter an address and just hit enter. Then open the console. You will see:
keydown
place_changed
but if you now click on route2 and then back on route1, enter another address and press the enter button, console will log:
place_changed
keydown
The order of the eventhandlers changed. It seems that google search / - functionality is somehow broken, when google is loaded once, then the $state changes and you again try to use google.
Also, there is a second .pac container in the dom, and I guess google is somehow loaded twice or something while the controller just reloads.
Do you know why this behaviour happens and how I can prevent that or do you have at least an idea on how to workaround this problem? I need keydown to be before place_changed. The google search still works in the plnkr, but it is buggy a bit. I think it is a problem with angularjs/$state loading the controller / view and the directive or something.
//edit:
I guess it is not really a problem with the vs-google directive nor google itself, maybe just they way of them being initiated. Vs-google takes the element of the directive and initializes its code. Because google-API is included in the index.html file and a directive loads on state change, it seems that it reinitializes the DOM element or something, but still, the event is just called once

$location.hash() breaking my function

I'm very close to finishing up my page, and I ran into this odd bug.
When I use ng-include, the pages load fine, but they resume scrolling from the previous position, so they don't start at the top with every click.
I resorted to using anchor scroll, but it doesn't work properly. I have to click the link again, for it to load the contents, and if I click the same link again, it offsets the page to some weird position.
This is my code in the controller:
$scope.toPage = function (index, id) {
$scope.missiveIndex = index;
$scope.contentsDown();
$location.hash(id);
};
and this is the HTML part:
<article id="{{articles.ids}}" class="stories-anim" ng-repeat="articles in stories" ng-hide="!isMissiveSlideIndex($index)" ng-include="articles.content" [autoscroll]>
</article>
the id is passed in via ng-click="ng-click="toPage($index, button.ids);"
is there a way to put the location.hash in the [onload] expression and autoscroll that way?
thanks
Probably the anchor scroll didn't work because the content of the page was not fully loaded when it was called.
You can solve that by using a timeout.
$timeout(function() {
$anchorScroll();
},500);

Run code when link is clicked, even if I stay on the same page

I have a collapsible sidebar navigation, and any time users click a link on it, I have the sidebar hide automatically. I achieve this in the run method by using the following code:
app.run(function($rootScope) {
$rootScope.$on('$routeChangeSuccess', function () {
$rootScope.closeNavigation();
})
});
Where app is my Angularjs module.
The problem is that it gets a little unintuitive to use, when you click a link in the navigation for the page you're already on, and then nothing happens. What I would like is to have the sidebar close anyway, so that the users still get focus on the content, even if it's the same content.
But Angularjs doesn't execute the $routeChangeSucess event, if there is no route change happening. So what can I use instead?
You simply need to use ng-show = isPanelVisible and ng-click = closePanel() on the html sidepanel tag (e.g. a <div>).
Then, define $scope.closePanel() in the controller associated to the actual view. For instance
$scope.closePanel = function() {
$scope.isPanelVisible = false;
}
See an example here. Code is here. Note that it doesn't use ng-show, but the behaviour is the same.

angularJS doesn't scroll to top after changing a view [duplicate]

This question already has answers here:
Changing route doesn't scroll to top in the new page
(18 answers)
Closed 8 years ago.
For example:
A user scrolls down on view A;
Then the user clicks on a link, which takes the user to view B;
The view is changes,
but the user's vertical location remains lthe same, and must scroll manually to the top of the screen.
Is it an angular bug?
I wrote a small workaround that uses jquery to scroll to the top; but I don't find the correct event to bind it to.
edit after seeing the comment:
How and WHEN do i pull myself to the top? i'm using jquery but the $viewContentLoaded event is too soon (the method runs, but the page doesn't scroll at that time)
The solution is to add autoscroll="true" to your ngView element:
<div class="ng-view" autoscroll="true"></div>
https://docs.angularjs.org/api/ngRoute/directive/ngView
Angular doesn't automatically scroll to the top when loading a new view, it just keeps the current scroll position.
Here is the workaround I use:
myApp.run(function($rootScope, $window) {
$rootScope.$on('$routeChangeSuccess', function () {
var interval = setInterval(function(){
if (document.readyState == 'complete') {
$window.scrollTo(0, 0);
clearInterval(interval);
}
}, 200);
});
});
Put it in your bootstrap (usually called app.js).
It's a pure javascript solution (it's always better not to use jQuery if it's easy).
Explanation: The script checks every 200ms if the new DOM is fully loaded and then scrolls to the top and stops checking. I tried without this 200ms loop and it sometimes failed to scroll because the page was just not completely displayed.
It seems that you understand why the problem is happening based on #jarrodek's comment.
As for a solution, you could either follow #TongShen's solution of wrapping your function in a $timeout or you can put the function call within the partial that you're loading.
<!-- New partial-->
<div ng-init="scrollToTop()">
</div>
If you view change is fired after a click event, you could also put the function call on that element. Just comes down to timing though. Just depends on how things are set up.

AngularJS + Protractor wait for all ajax calls to end / full page load, before running the tests

Is there a better way to wait until all page is loaded,
my angular pages are loaded with promise, it means that if all ajaxs call haven't ended yet
there is a loader on the screen.
i'm currently using ptor.sleep(10000), like in the following example:
beforeEach(function(){
ptor = protractor.getInstance();
driver = ptor.driver;
ptor.get(base_url);
ptor.sleep(10000);
});
is there a better way to do it?
If you're using ng-if to hide/show your content when loading starts/finishes, you can use the following syntax to wait until a certain element appears on the page (i.e. ng-if will prevent the element from being in the DOM until the page finishes loading):
ptor.findElement(by.id('element-only-shown-after-loading')).then(function (myElement) {
// Your page should be loaded at this point
});

Resources