Help understanding _uihooks

Items = new Mongo.Collection('items');
if (Meteor.isServer) {
	Items.remove({});
	Items.insert({title: 'foo'});
	Items.insert({title: 'foo'});
	Items.insert({title: 'foo'});
}

if (Meteor.isClient) {
	Template.layout.helpers({
		items: function () {
			return Items.find();
		}
	});

	Template.layout.onRendered(function () {
		$('.container')[0]._uihooks = {
			insertElement: function (node, next) {
				$(node).insertBefore(next)
				console.log('Inserting an item.');
			}
		}
	});
}
<body>
	{{>layout}}
</body>

<template name="layout">
	<div class="container">
		{{#each items}}
			<div class="item">{{title}}</div>
		{{/each}}
	</div>
</template>

In my understanding this code should produce 3 console.logs in line with rendering each .item. But it does nothing…

Try it without using jQuery, f.e.:

this.find('.container')._uihooks

Nope. doesn’t work…

You add all items on the startup right? Just try to add them with some delay, f.e. 5 seconds after template got rendered. I think uihooks works only when you add new items after the rendering process.

in the time onRendered is run, all these 3 items are most probably already rendered.
Just add/remove them with mongol to check if it behaves as you expect when adding.

@XTA, @shock - you are right, hooks work only on elements added after tpl was rendered.
But that’s most unfortunate… how can I delay rendering of initial elements in {{#each}} block?

I dont think there is any logic reason to do it.
Maybe if you say what you are trying to accomplish we can propose some other solution.

Actually, I want to animate all .items. But I need to animate them on initial page load. And I have to call a custom animation function, that’s why I wanted to hook into the #each rendering process.

Is not enough that user have to wait till page loads, now you want him to wait even longer till some animation finish ?
I think animations are good to mask slow data, but not to extend unusability even more.

And you can create template level reactive var, which you will change in onRendered/
If you return in items helper null till that reactive var will be true, you can easily delay it that way.

Maybe it will also work if you create a template for your items, then you can call the onRendered method, f.e.

Template.item.onRendered (function () {....})

Yes, I’ve attached a simple Session to the helper and now _uihooks function runs. But now it doesn’t render the .items themselves! only runs console.log :angry:

Yes, that would be a possible solution. But how to animate Template.item?

That’s expected: https://github.com/meteor/meteor/blob/devel/History.md#blaze-5

Note that when you set one of these functions on a container element, Blaze will not do the actual operation; it’s your responsibility to actually insert, move, or remove the node (by calling $(node).remove(), for example).

Well, I have $(node).insertBefore(next) - isnt that enough?
btw, when I make

insertElement: function (node, next) {
  $(node).insertBefore(next)
  console.log(node)
  console.log(next)
}

it outputs markup for node but null for next - isn’t that strange?

Yes, it should be, but the docs I’ve looked at use this.find()._uihooks as @XTA suggested. Maybe worth another try?

And what would you expect be the next DOM element inside container before which you want to insert it?
When you are adding 1st element, that null sounds quite reasonable.

this undocumented stuff just refuses to work!

@avalanche1 I don’t know which tools you use to animate your items, but I would try it with https://atmospherejs.com/natestrauser/animate-css (Doc here).

Then, in your Template.item.onRendered() function I would add something like this:

$(".item").addClass("animated fadeIn");

I created a new meteor project, took the JS you have and replaced the JS in my new project with it completely. Did the same for the HTML and I get 3 console.logs.