Question

I have created an AngularJS service that dynamically inserts a div into the DOM with content from a template and a custom controller that handles the bindings and directives within the template. The service, called myService, allows you to pass in the templateUrl and the controllerName as options. Below is simplified code:

function display(id, templateUrl, controllerName) {
  var scope = $rootScope.$new();
  scope.id = id;
  var element = angular.element('<div ng-include="\'' + templateUrl + '\'"></div>');
  var controller = $controller(controllerName, {$scope: scope});
  element.contents().data('$ngControllerController', controller);
  $compile(element)(scope);
  parentElement.append(elem);
}

I have a separate controller on the DOM that handles the ng-click on several anchor tags:

<a ng-click="handleClick(record.id, record.templateUrl, record.controllerName)">Click Me</a>

I'm not using a $routeProvider and there is no href and no id attributes on the anchor tags. The click function invokes my custom service to render the div:

$scope.handleClick = function($event, id, templateUrl, controllerName) {
  myService.display(id, templateUrl, controllerName);
};

After the page loads in the Chrome browser and I scroll down so that a link with the ng-click is visible and then click the link, the browser scrolls to the top of the page. I DO NOT want the page to scroll, just display the div next to the link. Nothing changes in the URL in the location. If I scroll back down, I see the new div displayed. If I click a different link with the ng-click, then no scrolling takes place (which is what I wanted for the first click as well). If I refresh the page, it doesn't matter which link I click first and the first click always causes the browser to scroll back to the top of the viewport.

If I don't put the ng-include directive in my new element and just hard-code the HTML of the template in the service instead, the scroll to the top of the page on the first click DOES NOT happen.

The ngInclude documentation says that you can specify an optional autoscroll attribute and it says that if the attribute is not set, then it will "disable autoscroll". It appears that this is not the case. I tried setting autoscroll to "false", but that didn't help.

I know that I can do $anchorScrollProvider.disableAutoScrolling() to disable all autoscrolling, but what can I do to disable autoscroll for specific tags? Is this a bug in Angular that I should report? If so, is there are work-around I can use until that bug is fixed?

EDIT: Here is a plunk that demonstrates the problem.

Was it helpful?

Solution

I had the exact same issue using Angular v1.2.2, having an ng-include in a template file that was not loaded into the page from the start. When the template file was compiled $anchorScroll got initialized for the first time and for some reason reset the scroll.

My solution:

var example = angular.module('example', [])
    //Force initialization of $anchorScroll, so that the scroll doesn't reset when compiling an ngInclude that has been lazy loaded.
    .run(['$anchorScroll', function () { }]);

That way $anchorScroll initializes on page load and does nothing when the ng-include statement compiles in the lazy loaded template.

OTHER TIPS

According to Philip Holly's comment there was a change with version 1.1.5 where if there is no hash $anchorScroll causes the page to scroll to the top. The fix is adding:

angular.module('myApp').value('$anchorScroll', angular.noop);

Though I would think setting the autoscroll attribute as you did should have worked. Perhaps that is a bug.

Alternatively it looks like doing:

$location.hash("!");

just before the $compile also works.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top