Template.myTemplate.rendered in Meteor? - meteor

What is the use of Template.myTemplate.rendered in Meteor?. I had studied the document but i didn't understand the exact functionality.The document says Provide a callback when an instance of a template is rendered. What is the meaning of instance of a template is rendered.Can you please suggest me with an example?

When the callback is fired, an instance of the template has been rendered (added to the document). It can be useful if you for example want to manipulate the elements in the template through the use of a JavaScript library, for example CodeMirror, as I used in one of my projects. For example:
<template name="test">
<textarea></textarea>
</template>
Template.test.rendered = function(){
// Make the textarea highlight the code (kind of).
var myCodeMirror = CodeMirror.fromTextArea(this.find('textarea'))
}

Related

How to focus an input on subscriptionsReady using FlowRouter in Meteor

I'm currently getting used to using FlowRouter after a while using Iron Router and trying to set up some best practices. I'm subscribing to my collection at a template level.
Previously I've waited for a template to render using onRendered and then targeted my input field and applied focus(), however I am now trying to only show my template in Blaze when the subscriptions are ready using the following (please excuse the Jade but I think it's pretty clear in this case)
template(name="subjectNew")
unless Template.subscriptionsReady
+spinner
else
form
input(type="text" name="name")
So the basic idea is that until the subscriptions are ready the spinner shows. The issue I'm having is that now even when the template renders, the focus won't apply. I've tried various methods of wrapping it in an autorun call but not sure the best way of trying to target the first field when combined with this approach?
Template.subjectNew.onRendered(function() {
console.log('rendered');
$('input').first().focus();
});
Is it possible?
Many thanks for any ideas.
Your subjectNew is considered rendered even when it is only showing the spinner. Just stick your:
form
input(type="text" name="name")
Into a separate template and then attach your focus code to the onRendered handler of that other template.
template(name="subjectNew")
unless Template.subscriptionsReady
+spinner
else
+myForm
template(name="myForm")
form
input(type="text" name="name")
js:
Template.myForm.onRendered(function(){
$('input').focus()
});
I think using an autorun would be a good approach but then you would have to employ Tracker.afterFlush() to wait to set the focus after the form is rendered.
Something like:
Template.subjectNew.onRendered(function() {
this.autorun(() => {
if (this.subscriptionsReady()) {
Tracker.afterFlush(() => $('input').first().focus());
}
});
});

Why can't I access JS functions made in separate JS files in my html when using Meteor

Meteor says when you write some javascript in a JS file, every file automatically has access to it everywhere in the app, but when I write a function in a a separate file like that, I just get a console error saying that function could not be found when I call it in html. The only way I can get it to work is by writing the JS in the html file but I want to keep the languages separate. Any idea on what the problem is?
code:
html in one file:
<button onclick="dylan()"></button>
js in another file:
function dylan(){
console.log("hello");
}
the problem is, when I click the button, it says dylan is not a function.
Meteor docs do not spell this out but every individual javascript file is wrapped into a closure:
(function() { //the file content // })()
so all functions in a given file have their own scope.
Functions defined in a js file in Meteor normally only have file scope - that is, any object in that file can refer to them.
If you want to define a global function, create a global variable:
dylan = function(){
...
}
Note the absence of let or var which would restrict the function to file scope.
Now you can use this global in your onclick handler.
Note however, that normally in Meteor, you would define an event handler at the template level, ex:
Template.myTemplate.events({
'click button'(){
...your code here
}
});
As opposed to referring to event handlers in your html directly.
The purpose of using Meteor is not met if you do not harness the wonderfull features such as
Template.X.events({});,
Template.X.helpers({}); and also
Template.registerHelpers({});
You can write your desired code in below way:
Template.template_name.events({
'click .button_class' : function() {
console.log("Hello");
}
});
//HTML
<button class="button_class"></button>
If that click event has to be used in more than 1 HTML then you can use registerHelper methods than template click events.
Template.registerHelpers('dylan' : function() {
console.log("Hello");
});
//html
<button onclick="dylan"></button>
To access dylan(), you must first load the script file that contains that function into the html document.
You can do this by adding <script src="myfile.js"></script> anywhere before the button. (replace myfile with the name of your script)
Once loaded, <button onClick="dylan()"></button> will work!

Calling holder.js in Meteor

I'm new to Meteor and trying to get holder.js to work in the framework. It works on refresh, but when moving from one route to another, it breaks.
The documentation just says "Because Meteor includes scripts at the top of the document by default, the DOM may not be fully available when Holder is called. For this reason, place Holder-related code in a "DOM ready" event listener."
I assume I need a Template.foo.onRendered callback, but unsure how to format it. Here's the HTML:
<img class="holder" src="holder.js/120x120">
And here's the callback I've added in a .js file:
Template.contactSingle.onRendered(function() {
this.$('.holder').Holder.run();
});
Again, the holder.js images appear on refresh, but I can't get them to render when going from one page to another. I'm using FlowRouter for routing.
I'm sure it's something simple. Any help is greatly appreciated!
Change your code from:
Template.contactSingle.onRendered(function() {
this.$('.holder').Holder.run();
});
to:
Template.contactSingle.onRendered(function() {
Holder.run({images: document.querySelectorAll('.holder')});
});
Obviously you do not want to do the costly document.querySelectorAll('.holder'). If you can reduce that to you template using a class from its wrapper.
For example:
Template:
<template name="singlePost">
<div class="single-post">
<h2>This is the singlePost area.</h2>
<img class='holder' src="holder.js/300x200">
</div>
</template>
and onRendered
Template.singlePost.onRendered(function() {
Holder.run({
images: document.querySelectorAll('.single-post .holder')
});
});

Pass a template name as string to another template in Meteor/Handlebars

I have a template that contains a second template, I'd like to make the second template variable ie. it can change depending on what I pass as the template name.
<template name="template1">
<div>
{{> template2}}
</div>
</template>
So when my main page shows template1 I want to specify the template to use for template2.
<template name="main">
{{> template1 TemplateArgs }}
</template>
I know how to set up TemplateArgs - it would contain the name of the template I want to use for template2.
Is this possible?
A future version of meteor allows this with the new Meteor UI functionality. Currently you need to do this manually in a different way. See Meteor set overall template context.
Meteor UI
Beware meteor UI is still in a betaish and is a bit buggy. More details on the post in the references
If you use meteor UI (which you can use in preview mode with)
meteor --release template-engine-preview-5
Then you can do stuff like this
Template.main.template1 = function (value2) {
return Template["template2"].withData({foo: "bar", value2: value2}));
}
Then html like
{{>template1 "valueofvalue2"}}
Current Version / Spark rendering
There is a way in the current version of meteor but it wont work with the UI release since Meteor.render will be phased out in favour of using DOM objects
Template.main.template1 = function(value2) {
return Meteor.render(Template.template2({foo: "bar", value2: value2});
}
Then something like this in your html. You might have to play around with the data to get it working but its something like this
{{template1 "value2"}}
References:
https://groups.google.com/forum/#!topic/meteor-core/gHSSlyxifec
https://github.com/meteor/meteor/wiki/New-Template-Engine-Preview
http://www.youtube.com/watch?v=aPf0LMQHIqk

Callback after the DOM was updated in Meteor.js

I have this Meteor project: https://github.com/jfahrenkrug/code_buddy
It's basically a tool with a big textarea and a pre area that lets you enter source code snippets that automatically get pushed to all connected clients.
I'd like to automatically run the highlightSyntax function when the code was changed, but it doesn't really work.
I've tried query.observe, but that didn't work too well: The syntax highlight flashed up once and then disappeared again.
So my question is: How do I run code after the DOM was updated?
A hacky way to do it is:
foo.html
<template name="mytemplate">
<div id="my-magic-div">
.. stuff goes here ..
{{add_my_special_behavior}}
</div>
</template>
foo.js
Template.mytemplate.add_my_special_behavior = function () {
Meteor.defer(function () {
// find #my-magic-div in the DOM
// do stuff to it
});
// return nothing
};
The function will get called whenever the template is rendered (or re-rendered), so you can use it as a hook to do whatever special DOM manipulation you want to do. You need to use Meteor.defer (which does the same thing as settimeout(f, 0)) because at the time the template is being rendered, it isn't in the DOM yet.
Keep in mind that you can render a template without inserting it in the DOM! For example, it's totally legal to do this:
console.log(Template.mytemplate())
So when a template is rendered, there is not a 100% guarantee that it is going to end up in the DOM. It's up to the user of the template.
Starting with Meteor 0.4.0, Template.myTemplate.rendered provides a callback that
is called once when an instance of Template.myTemplate is rendered into DOM nodes and put into the document for the first time.
More info at http://docs.meteor.com/#template_rendered
As for the current version of Meteor (1.0), we can now use the .afterFlush() function of Tracker.
Tracker.autorun(function(e){
var data = Router.current().data();
if(data.key !== undefined){
//the data is there but dom may not be created yet
Tracker.afterFlush(function(){
//dom is now created.
});
}
});
There is no callback after the DOM is updated, however you can force all pending DOM updates with Tracker.flush().
After you call flush(), you know the DOM has been updated and so you can perform any manual DOM changes you need.
This question is quite old, but the two-year-later solution would be to integrate an operational transformation library with Meteor and use Ace or CodeMirror on the client, which does the syntax highlighting automatically. This has the additional benefit of allowing people to edit at the same time.
I've already done the work for you :)
In Blaze Components (I am one of authors) you have an API which calls methods when DOM is inserted, moved, or removed. You can see here how to make an reactive variable when DOM changes.
The downside with this approach is that it does not change when DOM element attributes change (like class change). Only when DOM elements themselves are changed. This works for most cases, but if you need the second, I suggest you simply use MutationObserver. In this case you will be able to respond also to outside changes.
It seems Template.myTemplate.rendered doesn't work properly or I don't get it...
I need to load TinyMCE inline after a template with all posts are rendered, so I have :
- a Template
<div id="wrapper">
{{#each posts}}
<div class="editable">{{post}}</div>
{{/each}}
</div>
- and a Function
Template.myPosts.rendered = function(){
console.dir($("div"));
tinymce.init({
selector: "div.editable",
inline: true,
plugins: [
"advlist autolink lists link image charmap print preview anchor",
"searchreplace visualblocks code fullscreen",
"insertdatetime media table contextmenu paste"
],
toolbar: "insertfile undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image"
});
}
However the console logs only the <div id="wrapper"> and not the <div class="editable"> divs, which contain my posts. So, it seems Template.myTemplate.rendered callback occures before the template is rendered, right?
EDIT: I put the Template.myTemplate.rendered code inside a setTimeout() and all seems to work, so I'm sure Template.myTemplate.rendered causes the problem.
I just found a little hack that seems to be working pretty well:
Template.myTemplate.onRendered(function() {
this.autorun(function() {
Meteor.setTimeout(function() {
// DOM has been updated
}, 1);
});
});
I'm not a Meteor expert so it might have some downsides, but I haven't found any for now — except that it's a bit dirty !
I think you might want to pass a callback to
Meteor.startup(callback)
see http://docs.meteor.com/#meteor_startup

Resources