rivets
rivets copied to clipboard
Is there any event or callback to know when the DOM has finished updating?
I'm making a grid of elements and after the DOM has been populated with rv-each
I need to dynamically set the width and height of the grid elements using jQuery.
How would this be done?
This can be done. But...I hope someone else chimes in with a better solution, cause mine is a little dirty I think.
Check out this fiddle: http://jsfiddle.net/af8qwh8j/
The gist of it is to make a new each binder, I called mine evented-each-*
and call the regular each binder while wrapping all its methods in your custom events.
rivets.binders['evented-each-*'] = {
block : true,
priority : 4000,
bind : function() {
$('#fireEventsHere').trigger('bind:begining');
rivets.binders['each-*'].bind.apply(this, arguments);
$('#fireEventsHere').trigger('bind:complete');
},
unbind : function() {
$('#fireEventsHere').trigger('unbind:begining');
rivets.binders['each-*'].unbind.apply(this, arguments);
$('#fireEventsHere').trigger('unbind:complete');
},
routine : function() {
$('#fireEventsHere').trigger('routine:begining');
rivets.binders['each-*'].routine.apply(this, arguments);
$('#fireEventsHere').trigger('routine:complete');
},
update : function() {
$('#fireEventsHere').trigger('update:begining');
rivets.binders['each-*'].update.apply(this, arguments);
$('#fireEventsHere').trigger('update:complete');
}
};
As you remove names from the list, you will see new events fire. Pretty cool stuff.
Hope this helps.
Thanks again for your help!
When does the update callback get triggered?
It is an internal method inside the each-*
binder.
It looks like it gets called when, after initially looping though the collection and building the initial DOM, one of the items in the collections model changes.
It would be great if those callbacks or events were included by default on Rivets.
Can you mark it as a feature request?
@PierBover I am not a collab on this repo, I cannot mark stuff as bug etc.
Though, from lurking on this Repo pretty hard for the last year or so, my feeling is that the community would rather you just write your own binders. If you really feel strongly about it you should ping mikeric
.
I am currently working on a each-*
binder that will have full event support bove and will also keep the DOM in order. It will fire beforeEnter
afterEnter
and beforeExit
events on the iterated models so you can easily animate the iterated items in and out of the DOM like,
<ul>
<li rv-each-item='model.collection' rv-on-beforeEnter='set height to zero' rv-on-afterEnter='animate into DOM ' rv-on-beforeExit='animate out of DOM' ></li>
</ul>
The only problem with this right now is that Rivets does not keep the actual DOM elements in order.
For example, if you splice the center item out of an array of 3 items that is bound via each-*
. You would expect it to just remove the middle element from the DOM. But, it actually removes the last item from the DOM and then re-binds the second item in the DOM with the model of the previous third item in the collection. Anyhow, I will keep a note to Ping you when I finish my each-*
binder. It sounds like it could be useful to you.
This is interesting. Yes please, ping me when it's finished.
Agree, I think there should be some way to get notified when a model get bound and rendered, so further DOM manipulations can be made without hacks (setTimeout or something).
Can someone add the "feature request" label, please?
@NVO and @PierBover Here is a previous issue thread talking about something similar. Ammo for your arsenal?
I personally feel that (since rivets does not currently send any special events) that maybe you should make a rivets plugin? evented-rivets
or something like that. Then you can monkey patch events into all the binders you want? In the apps I work on, I am usually only concerned about when the items are entering and exiting the DOM. rv-if
rv-show
etc. So that I might animate them without attaching animation logic to the model informing the DOM.
I believe rivets.bind
is sync. So you know rivets is done binding then that method is finished.
What exactly are you looking for rivets to support? just on-bind
or other events as well?
What exactly are you looking for rivets to support? just on-bind or other events as well?
I'm new to Rivets so I can't really say a general case, but my particular problem was that I needed a callback whenever some piece of the DOM was updated by Rivets.
What I ended up doing any time I changed the model was to unbind()
Rivets, update the objects Rivets is reading, bind()
, and then do my DOM stuff.
:+1:
+1 for a callback that gets called after some piece of the DOM is updated by rivets. It would allow our parent views to listen for subview changes and potentially run DOM post-processing across the entire view.
Example use case: say you want to make all inputs and buttons have disabled = true if some top level view attribute called "readOnly" is true, but these inputs and buttons are getting rendered by subviews. To solve this, you could observe rivets to know when a subview changed, and then apply disable=true to all DOM elements in the DOM subtree of the parent view.
Looking for the same thing but on top of a component.
Actually my example doesn't work :(
You could try this if you want to know when your componente was rendered:
rivets.components['your-component'] = {
template: function() {
[...]
},
initialize: function(el, data) {
var controller = this;
var $el = $(el);
var ready = function() {
// do your stuff after view is rendered here
}
/*
* Detect DOM changes
*
* Note: This event has been deprecated in favor of the Mutation Observer API
*
* Be very careful with this event it is easy to cause an infinite loop if you decide to change the DOM inside the event handler,
* so it is better to bind the event only once with ` $el.one('DOMSubtreeModified', ready);` instead of `$el.on('DOMSubtreeModified', ready);`
*
* @see https://developer.mozilla.org/en-US/docs/Web/Events/DOMSubtreeModified
*/
$el.one('DOMSubtreeModified', ready);
return controller;
}
};
or this:
rivets.components['your-component'] = {
template: function() {
[...]
},
initialize: function(el, data) {
var controller = this;
var observer;
var ready = function(mutationsList) {
// do your stuff after view is rendered here
observer.disconnect(); // if you want just detect the first update
}
/*
* Create an observer instance linked to the callback function
* @see https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
*/
observer = new MutationObserver(ready);
// Create an observer instance linked to the callback function
observer.observe(el, {
attributes: true,
childList: true
});
return controller;
}
};
Both work for me