Meteor how to create global event? - meteor

How can I create a event which will run on any page?
When creating a helper on the main layout template it doesn't work.
Template.layout.events
'click': ->
console.log "you clicked on the site"

You can use Template.body.events instead of Template.layout.events to create events for any template that will apply on anything in <body>
Docs: http://docs.meteor.com/#/full/template_body

you need a special package to create a global event.
install
meteor add gwendall:body-events
and you can use the events from Template.body.events in every template
example
Template.body.events({
'click .myClass':function(){
alert("BODY EVENT");
}
});
or if you like the new syntax
Template.body.events({
'click .myClass'(){
alert("BODY EVENT");
}
});

Neither answer currently is 'wrong' per se, they just work in different situations:
Event maps, Template.body.events({}), on Template.body do not get applied to elements added to the body via Blaze.render, Iron-Router, Flow-Router jQuery, or the DOM API, or to the body element itself. If you are using the above you will need to add the package body-events to be able to utilise the event map on body using the command below:
meteor add gwendall:body-events
If you are not using any of the template rendering packages above then you can directly add to the body event map using the code below:
Template.body.events({
'click': function () {
alert("clicked on the page. oh yeah!");
}
});
nb. it seems the latest version of Blaze allows directly adding event maps to body

Related

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!

Reinitialize library when new data is available

I'm currently developing a Meteor application where I use the video.js-Library.
I have the following template:
template(name='foo')
.video.embed-responsive.embed-responsive-16by9
with richMediaContent
video#video.video-js.vjs-default-skin.vjs-big-play-centered(controls='' preload='auto')
source(src='{{video.videoUrl}}' type='video/mp4')
p.vjs-no-js {{i18n 'videoTagNotSupported'}}
Initializing the video.js-Library after the template is rendered works fine.
Template.foo.onRendered ->
videojs document.getElementsByClassName('video-js')[0], {}
But the videojs-Library is not reinitialized if the same template is rendered with a different video (with a different richMediaContent).
I've already tried to move the video-Part in an own template and included it in the foo-Template so that the onRendered-Call should get called every time a new video is loaded. But this doesn't seem to work.
Do you have any idea how I can reinitialize the library if the video changes?
Thanks in advance!
New answer
Indeed, when your route changes but uses the same template, the said template does not get rendered again, therefore your js plugin call will not trigger a second time. What you can do instead is call your js plugin in an onAfterAction call, within your route definition:
Router.route('/video/:_id', {
name: 'video_page',
template: 'foo',
// ...
onAfterAction: function () {
videojs document.getElementsByClassName('video-js')[0], {}
}
});
Previous answer
I think you are looking for the almighty this.autorun. At the end of your onRendered function, it should look like this (I type it in pure javascript)
this.autorun(function () {
var video = Session.get("video"); // reactive data
videojs document.getElementsByClassName('video-js')[0], {}
});
The idea is that the first line must include, within the autorun function, a way to get your reactive data. In that case, I use the Session which is reactive. Collections are also reactive, so another way would be something like Videos.findOne();. This will depend on how you get that video element.
What this does is that any time the reactive data changes, the callback for this.autorun will run again, and your video plugin will be reset.

Meteor: Proper way to add 'confirm delete' modal

I want to create a confirm delete popup with Bootstrap 3. Is there any good comprehensive examples how to build one. I am very new to Meteor.
Use whatever example from Codrops, etc, just remember put the JSCode inside a
Template.nameTemplate.rendered = function() {}
So thats telling meteor to load that jscode, when the template has beed rendered and it can load any modal, etc...
So just follow whatever example you want, and just put whatever jQuery plugin etc, inside Rendered function
Also in some case the rendered its not enough, you need to use too,you can see timer docs here, anyways if you are having bad time, feel free to upload, some meteorPad, free nitrous box o repo on github and i can help you (i have a bad time with those modals on meteor to, they are a little trickys =p)
update answer
try to add meteor add iron:router, and on the client /app.js
Router.route('/', function () {
this.render('leaderboard');
});
And keep the same rendered like this.
Template.deleteBtn.rendered = function(){
$('.open-modal').on('click', function(e){
$('#confirm').modal()
.on('click', '#delete', function (e) {
// Remove selected player
Players.remove(Session.get("selectedPlayer"));
});
});
}
UPDATE
So using the peppelg:bootstrap-3-modalPackage, you can easy do the follow
First Create a template with the modal content
<template name="modal">
<!-- Modal Stuff -->
</template>
and easy call it on a Event handler.
Template.example.events({
'click #exampleButton':function(){
Modal.show('modal')
}
})
Now back to this example check this meteorpad from line 1-23 on app.'s and 41-62 on main.html

shorter preventDefault() with iron:router when using pathFor

I use the meteor package iron:router to route my templates. I tested my code in the browser and I see no reload when I click links. When I run my code on mobile the page is reloading. I know that I can disable this via a helper like:
Template.mytemplate.helpers({
myhelper: function(e){
e.preventDefault();
}
});
to keep my code simple I don't would like to create helpers for every template where I use links with:
mylink
Is there a easy way to handle this to minimalize redundant code?
You don't need to write the same helper in every template. You can reuse one for all templates:
Template.registerHelper('preventDefault', function(e) {
e.preventDefault();
});

How can I listen to when a template is rendered in Meteor?

I have some post-processing that I have to do on a list of HTML elements whenever they are updated from the backend. Is there some event (like, onRender) that I can listen to on the template to facilitate this?
For Meteor starting from 0.4.0 preview, you can use Template.myTemplate.rendered for this.
Template.myTemplate.rendered = function() {
console.log('Template has been (re-)rendered');
}
See also this conversation: Callback after the DOM was updated in Meteor.js
I used the technique to set Bootstrap tooltip popup events in the DOM after template (re)rendering in my CoffeeScript port of the Leaderboard example.
This in the template:
{{enable_tooltips}}
Calls this (CoffeeScript) template property method on the client:
enable_tooltips: ->
# Update tooltips after the template has rendered.
Meteor.defer -> $('[rel=tooltip]').tooltip()
''
Template.userDashboard.onRendered(function() {
// Initialize animate panel function
$('.animate-panel').animatePanel();
}
renamed in Meteor 1.0.4 from rendered to onRendered. Also it now takes a callback function.
http://docs.meteor.com/#/full/template_onRendered

Resources