shorter preventDefault() with iron:router when using pathFor - meteor

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();
});

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());
}
});
});

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 how to create global event?

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

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

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