1

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().

1 Answer 1

3

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.