9

I have a template that looks something like this:

<template name="foo">
  <textarea name="text">{{contents}}</textarea>
</template>

I render it with:

Template.foo = function() {
  return Foos.find();
}

And I have some event handlers:

Template.foo.events = {
  'blur textarea': blurHandler
}

What I want to do is set the rows attribute of the textarea depending on the size of its contents. I realize that I could write a Handlebars helper, but it wouldn't have access to the DOM element being rendered, which would force me to do some unnecessary duplication. What I want, ideally, is for meteor to trigger an event after an element is rendered. Something like:

Template.foo.events = {
  'render textarea': sizeTextarea
}

Is this possible?

Trevor Burnham
  • 76,828
  • 33
  • 160
  • 196
  • possible duplicate of [Callback after the DOM was updated in Meteor.js](http://stackoverflow.com/questions/10109788/callback-after-the-dom-was-updated-in-meteor-js) – Trevor Burnham Jun 14 '12 at 00:43

4 Answers4

21

As of Meteor 0.4.0 it is possible to check if a template has finished rendering, see http://docs.meteor.com/#template_rendered

If I understand your question correctly, you should wrap your textarea resize code inside a Template.foo.onRendered function:

Template.foo.onRendered(function () {
  this.attach_textarea();
})
Sander van den Akker
  • 1,545
  • 11
  • 13
16

I think the current 'best' way to do this (it's a bit of a hack) is to use Meteor.defer ala Callback after the DOM was updated in Meteor.js.

Geoff is one of the meteor devs, so his word is gospel :)

So in your case, you could do something like:

 <textarea id="{{attach_textarea}}">....</textarea>

and

 Template.foo.attach_textarea = function() {
   if (!this.uuid) this.uuid = Meteor.uuid();

   Meteor.defer(function() {
     $('#' + this.uuid).whatever();
   });

   return this.uuid;
 }

EDIT

Note, that as 0.4.0, you can do this in a much ad-hoc way (as pointed out by Sander):

Template.foo.rendered = function() {
  $(this.find('textarea')).whatever();
}
Community
  • 1
  • 1
Tom Coleman
  • 3,037
  • 18
  • 16
  • To make sure I understand - there's nothing magical about having a dynamic id here, just that this function will be called each time the element is rendered? I.e. you could do this with a data attribute or whatever? – 7zark7 Jun 14 '12 at 00:29
  • Hmm, `Meteor.defer` is just a wrapper around `setTimeout(..., 0)`, right? That approach occurred to me, but it could cause visible flicker. I really need a post-render hook that precedes the event loop. – Trevor Burnham Jun 14 '12 at 00:40
  • Having said that, I'm going to accept this answer because my question is a duplicate of the one that you linked to (even though the accepted answer on that one is far from ideal). – Trevor Burnham Jun 14 '12 at 00:42
  • @7zark7: The dynamic id is just there so you can find the relevant element in the Defer call. It's up to you how to do this, using `Meteor.uuid` is just a suggestion. – Tom Coleman Jun 14 '12 at 00:43
  • @TrevorBurnham: yes, (well Meteor.setTimeout, see docs). So you want something to run after the DOM nodes are attached, but before the nodes are rendered by the browser; i.e. before the rendering thread returns? AFAIK there is no way to hook into that, sorry. – Tom Coleman Jun 14 '12 at 00:45
  • @7zark7: Oh, I just re-read your comment, you are right, the id will change each time, this is actually a mistake :) Usually I'd attach the uuid to the context (`this`) if it didn't have one already.. – Tom Coleman Jun 14 '12 at 00:48
2

Since about June 2014, the correct way to do this has been to set a callback using Template.myTemplate.onRendered() .

foobarbecue
  • 6,780
  • 4
  • 28
  • 54
0

Yeah I think so - not sure if it's "the right way", but this works for me:

In your app JS, the client section will run whatever javascript there on the client. For example:

if (Meteor.is_client) {
    $(function() {
        $('textarea').attr('rows' , 12) // or whatever you need to do
    })
    ...

Note the example here uses JQuery, in which case you need to provide this to the client (I think :-). In my case:

I created a /client dir, and added jquery.js file under this.

Hope this helps.

7zark7
  • 10,015
  • 5
  • 39
  • 54
  • 1
    The problem is that although this might work on the initial draw, it's going to run into issues if the element ever reactively redraws. – Tom Coleman Jun 14 '12 at 00:10
  • Also, isn't jQuery included with Meteor? I don't have a jquery.js file anywhere and I haven't added any special jQuery package, but I can use jQuery just fine in my Meteor applications. – Mike Turley Jul 22 '12 at 13:43
  • 1
    I had to 'meteor add jquery' iirc – Vic Goldfeld Aug 18 '12 at 03:04