'$renderComplete' event?

1,986 views
Skip to first unread message

Daniel Nelson

unread,
Nov 14, 2011, 12:14:50 PM11/14/11
to ang...@googlegroups.com
In preparation for incorporating AngularJS into my first production
app, I'm starting to update my AngularJS in Rails demo to AngularJS
0.10.x (Speaking of the demo, thank you Igor for the t-shirts! They
arrived last week).

While updating, I noticed the new event system. Is there now an event
for when a container has finished updating? Someone on this list
helped me with a "defer" service in AngularJS 0.9.x, but the solution
is broken in 0.10.x, and before trying to fix the old way, I would
like to know if something akin to a $renderComplete callback exists in
the 0.10 branch. For example, I'd like to be able to do something like
the following:

angular.directive("my:cycle", function(expr,el){
return function(container){
this.$on('$renderComplete', function() {
$(container).cycle({ fx: 'fade',
speed: 500,
timeout: 3000,
pause: 1,
next: '#next',
prev: '#prev'});
});
}
});

Thank You,

Daniel

Igor Minar

unread,
Nov 14, 2011, 12:29:21 PM11/14/11
to ang...@googlegroups.com
On Mon, Nov 14, 2011 at 9:14 AM, Daniel Nelson <dan...@populr.me> wrote:
In preparation for incorporating AngularJS into my first production
app, I'm starting to update my AngularJS in Rails demo to AngularJS
0.10.x (Speaking of the demo, thank you Igor for the t-shirts! They
arrived last week).

cool!

I'm giving a talk at a ruby meetup tomorrow and I'm going to reuse some of the stuff you created for your rails presentation. I hope it's ok with you.

btw do you have your slides posted somewhere?
 

While updating, I noticed the new event system. Is there now an event
for when a container has finished updating? Someone on this list
helped me with a "defer" service in AngularJS 0.9.x, but the solution
is broken in 0.10.x, and before trying to fix the old way, I would
like to know if something akin to a $renderComplete callback exists in
the 0.10 branch. For example, I'd like to be able to do something like
the following:

angular.directive("my:cycle", function(expr,el){
  return function(container){
     this.$on('$renderComplete', function() {
         $(container).cycle({ fx: 'fade',
                              speed: 500,
                              timeout: 3000,
                              pause: 1,
                              next: '#next',
                              prev: '#prev'});
     });
  }
});

There isn't such a thing (yet). What should it do? do you want this code to run every time angular finishes rendering the view? More likely you want it to run just once when the first compilation/linking is finished. in 0.10.x you don't need the to use $defer (but it should work with it too!). This code should work just fine with 0.10.5:

angular.directive("my:cycle", function(expr,el){
  return function(container){
         container.cycle({ fx: 'fade',

                              speed: 500,
                              timeout: 3000,
                              pause: 1,
                              next: '#next',
                              prev: '#prev'});
  }
});


can you create a js fiddle if you are still having problems with this?

/i

Daniel Nelson

unread,
Nov 14, 2011, 1:21:21 PM11/14/11
to ang...@googlegroups.com
> I'm giving a talk at a ruby meetup tomorrow and I'm going to reuse some of
> the stuff you created for your rails presentation. I hope it's ok with you.
> btw do you have your slides posted somewhere?

Great! Please use whatever you like. The slides can be downloaded from
here: http://www.slideshare.net/dnelson-cs/javascript-frameworks-for-well-architected-immersive-web-apps-9735260
(these are the re-worked slides from my Bar Camp Nashville
presentation; they don't include some parts from the video--such as
file location within the hierarchy or how to include the CSRF
token--if you want those, let me know, and I'll provide you with those
slides, too).

> There isn't such a thing (yet). What should it do? do you want this code to
> run every time angular finishes rendering the view? More likely you want it
> to run just once when the first compilation/linking is finished.

Given:

Widget:


angular.directive("my:cycle", function(expr,el){
return function(container){
this.$on('$renderComplete', function() {

$(container).cycle({ ... });
});
}
});

And template:
<div id="photos" my:cycle>
<div class="photo" ng:repeat="photo in photos">...</div>
</div>

And controller:
self.photos = Photos.index(...);

Then:
$renderComplete would not fire until the photos data were received and
the .photo divs within the #photos div were fully rendered. If the
data in self.photos were updated, then the $renderComplete event
should fire again after the contents of the #photos div finished
updating to represent the new data in self.photos.

In this particular example, this is necessary because jQuery Cycle
needs to be applied after all the divs are present in the dom, but it
seems like a good general purpose callback to be able to be notified
whenever the dom is updated to reflect data changes.

> can you create a js fiddle if you are still having problems with this?

I'll try to get it working with defer again.

Thank You,

Daniel

Daniel Nelson

unread,
Nov 14, 2011, 2:12:55 PM11/14/11
to ang...@googlegroups.com
$watch seems to be exactly what I was looking for:

angular.directive('my:cycle', function(expr,el){
return function(container){

this.$watch(function() {
if ($(container).children().length) {


$(container).cycle({ fx: 'fade',
speed: 500,
timeout: 3000,
pause: 1,
next: '#next',
prev: '#prev' });
}
});
}
});

Best,

Daniel

Igor Minar

unread,
Nov 14, 2011, 7:57:54 PM11/14/11
to ang...@googlegroups.com
be careful when creating watches, the first argument is expression or function that should be executed on every digest and its return value should be compared with the previous value. Only if the values  differ the second function should be called.

So if anything, you likely want this:

angular.directive('my:cycle', function(expr,el){
 return function(container){
   var scope = this;

   scope.$watch(exp, function() {
     if ($(container).children().length) {
       scope.evalAsync(function() {   // <<< new 0.10.x api to do stuff after digest completes (in your case after the nested ng:repeater is finished rendering)

         $(container).cycle({ fx: 'fade',
                              speed: 500,
                              timeout: 3000,
                              pause: 1,
                              next: '#next',
                              prev: '#prev' });
       });
     }
   });
 }
});

HTH

/i


Daniel

--
You received this message because you are subscribed to the Google Groups "AngularJS" group.
To post to this group, send email to ang...@googlegroups.com.
To unsubscribe from this group, send email to angular+u...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/angular?hl=en.


Daniel Nelson

unread,
Nov 15, 2011, 10:33:13 AM11/15/11
to AngularJS
On Nov 14, 6:57 pm, Igor Minar <i...@angularjs.org> wrote:
> be careful when creating watches, the first argument is expression or
> function that should be executed on every digest and its return value
> should be compared with the previous value. Only if the values  differ the
> second function should be called.

That is a lot of overhead (especially since the "exp" could be non-
trivial). A '$renderComplete' event such as what I outlined above
would make this much simpler, but perhaps there is already an
idiomatic way to do this in AngularJS.

How would you, personally, go about making a callback that got fired
only after the contents were in the dom? This 'cycle' example is one
case, but another came up on the irc channel yesterday: how would you
go about applying an animation effect to content so that it animated
into view after it became available from a resource future object?

Thank You,

Daniel

Daniel Nelson

unread,
Nov 15, 2011, 10:40:16 AM11/15/11
to AngularJS
> That is a lot of overhead (especially since the "exp" could be non-
> trivial). A '$renderComplete' event such as what I outlined above

To clarify, I meant a lot of 'code overhead', not necessarily
computational overhead. It seems like a lot of extra code to write to
do a common thing, and that extra code has nothing to do with what we
are actually trying to achieve, which is confusing.

Daniel Nelson

unread,
Nov 17, 2011, 4:47:04 PM11/17/11
to ang...@googlegroups.com
Hi Igor,

Just want to make sure that the $renderComplete conversation (feature
request?) isn't lost. It seems pretty complicated to build such
functionality at this point. I actually had to revert back to my
unoptimized $watch solution for the cycle widget because when I
started running my Rails demo app in production mode, jQuery Cycle
threw an error on the more fleshed out version you provided.

That is, jQuery Cycle threw an error in Rails production environment using this:
https://github.com/centresource/angularjs_rails_demo/blob/de71c15eb508e45c8f955820be4ff4ec37bcda55/app/assets/javascripts/widgets.js

But it didn't throw an error using this:
https://github.com/centresource/angularjs_rails_demo/blob/8c38370dfd1f21764dfb20c25c92384d48379390/app/assets/javascripts/widgets.js


It would be awesome if we could do the following and know that the
$renderComplete function would fire once each time the contents of
"container" were updated:

angular.directive("my:cycle", function(expr,el){
return function(container){

this.$on('$renderComplete', function() {


$(container).cycle({ fx: 'fade',
speed: 500,
timeout: 3000,
pause: 1,
next: '#next',
prev: '#prev'});
});
}
});

Thank You,

Daniel

Igor Minar

unread,
Nov 18, 2011, 3:00:19 AM11/18/11
to ang...@googlegroups.com
what was the exception?

/i

Thank You,

Daniel

Daniel Nelson

unread,
Nov 18, 2011, 10:20:13 AM11/18/11
to ang...@googlegroups.com
> what was the exception?

Cannot read property 'cycleW' of undefined. It seems specific to
jQuery cycle, but is hard to debug because it arises in production
only, which is when source code has been obfuscated.

Igor Minar

unread,
Nov 18, 2011, 10:39:26 AM11/18/11
to ang...@googlegroups.com
I've seen that happen when cycle is called on a container that contains no images.


Daniel Nelson

unread,
Nov 18, 2011, 12:31:07 PM11/18/11
to ang...@googlegroups.com
> I've seen that happen when cycle is called on a container that contains no
> images.

Yes, but it only happens when in production, so it is hard to figure
out why (especially since your solution appears to prevent itself from
being called when the container has no children).

Thanks,

Daniel

Reply all
Reply to author
Forward
0 new messages