How to run code when the view is completely rendered?


#1

Hi,

I have a template with a list in it. My Controller gets data from a service which is added to $scope in success function. So ng-repeat renders the list. After that I want to scroll to a specific item in the list but thats not possible because the rendering of the view is not finished when the $anchorScroll is called.

Service.getData(param)
    .success(function (data, status, headers, config) {
         $scope.data = data;
         $location.hash(1017);
         $anchorScroll();
    })
    .error(function (data, status, headers, config) {
    });

Does anyone know how to handle that?


#2

You would wrap this in a $timeout in the controller, or use $watch in a directive.


#3

Thank you for your fast replay.

Did someone have a similar problem?

In this http://jsfiddle.net/dnzY9/ they use $timeout and 1000ms. Thats 1second so it slows down the whole app for the user. I think thats not a good thing because you fetch data from a service…that needs time and then you add 1sec to this time.

Aren’t there a better solution?


#4

Agreed, adding an additional second is pretty bad for UX, but the example was meant to show that if you use a $timeout, angular will process that code in the next scope digest. So the additional time of 1000ms is irrelevant

Can you post a demo of this using the list demo?


#5

@roland I have a really rough solution for you. It needs lots of cleanup(remove watchers if the data will not update, etc).

I’ve created a directive “delayed-scroll”. The directive needs the attributes “scroll-to” and “total-items”. These are pretty self explanatory.

The controller must broadcast an event when the async call is completed. This could be removed, but I didn’t want the directive “watching” all day long.

Once the “items-loaded” event is received, the directive will $watch the child elements of the list. When the list contains the exact same number of elements as “total-elements”, you know the list is rendered. Then, the directive sets the anchor tag in the location and calls $ionicScrollDelegate.anchorScroll().

Right now, I’m using a list of 500 items that are returned after a timeout of 1200ms. It then picks some random item to scroll to. It works perfectly but probably would be considered a pretty ugly solution.

UPDATE : I’ve tried it with as many as 5000 records and it still works - with a big deal due to generating such a big list.


#6

Your support is just awesome. Very fast and always helping.

@mhartington I don’t really understand why the 1000ms are irrelevant? Maybe I don’t understand $timeout good enough. What did you mean with the next scope digest?

@Calendee
Thank you for your effort. I looked at it and I understand it. Maybe it would be cool for further versions of ionic to implement such a solution. I think many people will need to do something after a list or content is rendered completely.

Why did you say its a rough or ugly solution. What should we do to make a good solution of it? I am not an directive or angular expert so my question is maybe silly. =)

OK so does this 1200ms timeout really happen? Because if i try your codepen I can’t recognize it. And why exactly 1200ms?


#7

@roland

I said “ugly” because someone on the Ionic dev team could make this more stable and elegant than I have here. It works and I wouldn’t hesitate to use it if I needed to. However, the Ionic team could do it much better. I’m a bit of a hack.

1200ms : I just made that number up. You can change it to anything you like. I just wanted to simulate the delay of loading the content over a slow network connection. Play around with the number to see the different effect.

If you feel this type of feature is important, then just open a feature request on the Ionic GitHub issues page. I’m sure it will be considered.


#8

@Calendee ah ok now I understand it =D

About the 1200ms…does that mean if my connection is very slow and this time is to short it will not work?


#9

@roland : The 1200ms means nothing at all. Since the controller is providing fake data, it will populate the list immediately. So, I simply put it in there to simulate how waiting for a slow connection to return data would feel.

With a REAL AJAX call, the controller would populate the list in whatever time it took to get a response from the server. This solution would work in fast responses and slow responses.


#10

@Calendee Thank you! Worked perfectly for my needs. Did you open a github issue or should i?


#11

No, I din’t open an issue.


#12

I believe that the use of $timeout is not correct.
You can use the following code.

$scope.$watch(‘YourLastestBindedModel’, function () {
//this run after binding and ajax request
}, true);

according to https://stackoverflow.com/questions/27856758/how-to-intercept-the-end-of-data-binding-in-angular-js?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa