VideoJS with Meteor 0.8 Blaze - meteor

Previously I used the rendered function to initialize videoJS when the Video Changed.
Now in Meteor 0.8. the rendered is only fired once, when the template was created.
The problem is: the template is used in each page, I navigate through, so it is never rerendered and just changed the attributes.
Is there any way to get VideoJS working in Meteor 0.8?
Something like rendered function for template fields that fires always
or a way to force the complete template to rerender
or a way to run a callback when the content of a helper is inserted.

I have found a solution to force the behaviour of Meteor < 0.8:
Make 2 Handlers:
UI.registerHelper "handler1", (data) ->
Session.set("loading", true);
UI.registerHelper "handler2", (data) ->
if Session.get("loading")
Session.set("loading", false);
return true
else
return false
Define 2 Template:
<template name="videoPlayer">
{{handler1 seed="videourl"}}
{{#if handler2}}
Loading Player...
{{else}}
{{> videoPlayerInternal}}
{{/if}}
</template>
<template name="videoPlayerInternal">
<!-- VideoJS-Player-Code -->
</template>
Now, I can hook the rendered method of videoPlayerInternal and this works like meteor < 0.8.
This works because:
In Initialization, only handler1 is called. This sets the variable "loading" to true.
After that I have a if-then-else that in the initial state shows a loading text. Because the condition is calculated by a helper that has a side effect (setting the session variable loading to false) it will be called immediatly after that.
So If I load another exactly same page with another video url, it needs to re run the handler1, wich sets the session variable to true again, that deletes the template from the dom and reinserts that. The rendered is called again and voila it works ;-)
Oh... and of course, the rendered method:
Template.videoPlayerInternal.rendered = ->
videojs.options.flash.swf = "/video-js.swf"
# Delete old players and reset.
if videojs.players.videoJsPlayer
videojs.players.videoJsPlayer.dispose()
# Initialize the player
$vid_obj = _V_ "videoJsPlayer", {}, ()->
console.log "video is ready.";
return true

Related

How make a dynamic value in MeteorJS

I need to set a variable or array in meteor JS which whenever changes. Wherever it is used on the page changes.
So far I have tried to set values in session.
let in = Session.get("in");
and this in HTML. The following works fine. This changes whenever it detects a change in array
{{#each in}}
<span class="selectable-tags"> {{this}} </span>
{{/each}}
But whenever I try to add these tags to other div using following. Then the ones added to other div does not change.
"click .selectable-tags"(e, t) {
// sets the tags inside the Method box on click
var el = e.target.cloneNode(true);
el.setAttribute('contenteditable', false);
document.querySelector('[contenteditable]').appendChild(el); },
using meteor with blaze UI. This can be used as reference link
Edit: Session.get or set is given for reference . This was to tell that these values are changing as they on any event triggered wherever set.
You need to add a helper that returns the session variable and show the helper in your html code :
Template.yourtemplate.helpers({
inHelper: ()=> {
return Session.get('in');
}
)}
And in html :
<div>{{inHelper}}</div>
Every modification on in by Session.set('in', newValue) will change your HTML.

Template.instance() and context messed with with Blaze block helpers

I'm using a simple template block helper that displays the a loading animation, hiding whatever is within it. This is very helpful for submitting forms and preventing the button from being pressed twice.
<template name="waiting">
{{#if isLoading}}
{{> loader}}
{{else}}
{{> UI.contentBlock}}
{{/if}}
</template>
I decided to put it in a block helper because I've never tried it before and I wanted to keep my code DRY -- I'm using this pattern in several places.
I'm running into issues using this block helper to access the Template.instance() not of the block helper but of the template it is within. I'm also running into problems with the template context. Here are the details of my problem:
I'm setting up a confirm-delete button like so:
{{#waiting isLoading=loadingDelete}}
{{#if confirmDelete}}
<button class="confirm">Are you sure?</button>
{{else}}
<button class="delete">Delete</button>
{{/if}}
{{/waiting}}
I'm also putting the loadingDelete and confirmDelete reactive variables in the template instance so I don't contaminate the Session:
Template.editRecord.created = ->
#loadingDelete = new ReactiveVar(false)
#confirmDelete = new ReactiveVar(false)
Template.editRecord.helpers
loadingDelete: () -> Template.instance().loadingDelete.get()
confirmDelete: () -> Template.instance().confirmDelete.get()
Then I create some events like this:
'click .delete': (e,t) ->
t.confirm.set(true)
'click .confirm': (e,t) ->
t.loadingDelete.set(true)
_id = #_id
Meteor.call 'deleteRecord', _id, (err) ->
t.loadingDelete.set(false)
if err
console.log err
else
Router.go "home"
The problem with this implementation is that the Template.instance() refers to the waiting template in the confirmDelete helper here:
confirmDelete: () -> Template.instance().confirmDelete.get()
The second problem is that the data context in the event refers to the context of the waiting template and thus I need to use _id = Template.parentData()_id instead of _id = #_id. But I am not able to access the editRecord template instance or any of its variables from here which is frustrating.
I changed the template to this which fixes first problem.
{{#if confirmDelete}}
<button class="confirm">Are you sure?</button>
{{else}}
{{#waiting isLoading=loadingDelete}}
<button class="delete">Delete</button>
{{/waiting}}
{{/if}}
But this is ugly and not what I was intending. I was hoping just to replace my #if block with this block helper but I've ended up writing much more code while trying to be DRY with my templates. This just doesn't seem right.
I noticed that #if blocks don't cause these context and Template instance problems. Is there something I am missing?
So it turns out that the Meteor team has recognized this error and are working to fix it. See this PR.

Render a different template for a user who is not logged in while preserving the URL

If a user is not logged in, I want to render a SignIn template for him while preserving the URL of the page. When he does log-in, then I want to continue rendering of the URL he original tried to visit.
The following bit of CoffeeScript shows the intent of what I am trying to accomplish. A version close to this worked until recently, until I updated to Meteor 0.8:
# If the user is not signed in, render the signin template instead of the
# actual page. However, keep the URL the same.
mustBeSignedIn = (pause) ->
if not Meteor.user()?
# How to render a different template from the intended one here?
### vvv ----
#render('masterLayout'
yieldTemplates:
signIn:
to: 'content'
)
pause()
Router.onBeforeAction(mustBeSignedIn, {
except: [ 'signIn' ]
})
My layoutTemplate contains a yield region with the name "content":
<template name="masterLayout">
<div id="container-content">
{{> yield region="content"}}
</div>
</template>
The signingIn and signIn templates are defined and other paths render properly when I go to them directly.
I think you just need to return the result of the render function.
mustBeSignedIn = (pause) ->
if not Meteor.user()?
return #render('masterLayout'
yieldTemplates:
signIn:
to: 'content'
)
Also its good practice to favor Meteor.userId() over Meteor.user() since userId() is only reactive if the userId changes where as user() will cause your onBeforeAction to be run any time there is a change to the current users record.
The correct syntax for yield-ing to templates is described in the DOCS.md file:
You can render manually by calling the render function. There are
three ways to call the render method:
this.render(): Render all of the templates for the Route or RouteController. This renders the main template into the main yield region, and all of the yieldTemplates into their associated {{> yield region='name'}} regions.
this.render('templateName'): Render the template named 'templateName' into the main yield {{> yield}}.
this.render('templateName', {to: 'region'}): Render the template named 'templateName' into the region named 'region' {{> yield
region='region'}}.
The third point answers the question about how to render a template to a named region.

Meteor template gets rendered twice

My template is getting rendered twice on first load. I notice this because in
Template.home.rendered = function() {
console.log('rendered'); // => this is printed out twice
console.log(Data.find({}).count()); // => this is initially 0, then 1 the second time
}
Furthermore, on the first load, no Data is available. Yet on the second load, the Data is there.
Does anyone know what this problem might be, and why the data only appears the second time?
You need to find a way to render the template when your data is available.
Using this template structure, the if block content, which happens to be the template displaying your data, will be rendered only when the myDataIsReady helper returns true. (thus triggering the rendered callback only once, with data immediately available).
<template name="displayData">
<p>This is my data : {{this}}</p>
</template>
<template name="home">
{{#if myDataIsReady}}
{{#each data}}
{{> displayData}}
{{/each}}
{{/if}}
</template>
You have to define a subscription handle (an object returned by Meteor.subscribe) in order to use it's reactive ready method : we'll reference it in the myDataIsReady helper to track data availability, and the helper will automatically rerun when the state of ready changes.
Meteor.startup(function(){
// this subscription should return your data subset
myDataHandle=Meteor.subscribe("myData");
});
Template.home.myDataIsReady=function(){
return myDataHandle.ready();
}
Template.home.data=function(){
return Data.find({});
}
But that's quite annoying for such a simple task.
That's why I suggest using the Iron Router which makes things way simpler !
Add it to your project using "mrt add iron-router", then in a client/router.js and client/router.html, use this boilerplate code :
Router.configure({
loadingTemplate:"loading"
});
Router.map(function(){
this.route("home",{
path:"/",
// we indicate which subscription has to be marked ready in order to load the template
waitOn:function(){
return Meteor.subscribe("myData");
}
// the result of this function will become our target template data context
data:function(){
return Data.find({});
}
});
});
<template name="home">
{{#each this}}
{{> displayData}}
{{/each}}
</template>
<template name="loading">
<p>Data isn't ready yet...</p>
</template>
As you can see, the Iron Router allows us to specify simply what we painfully achieved manually in the first code example (waiting on a particular subscription to render a template), and of course we get free routing, loading mechanisme, layout management, etc...
Search the web for a complete iron-router tutorial (my code is untested, but I hope it is ok and should get you started), it's so awesome that it's gonna be merged to Meteor ultimately.
I had a body.html in /client and a appBody.html in /client/templates, with, in iron router:
Router.configure({
layoutTemplate: 'appBody',
});
Both body templates were rendered (and happened to be the same). Obviously, the body.html in /client needed to be removed.

Setting {reactive: false} when searching a collection in Meteor still updates the template

I've got a news feed idea I'm trying out in Meteor, but I'm having issues with making the damn thing behave :) I want it to load up the news feed on page load / refresh, but not when the data changes. I found in the documentation that adding {reactive: false} to the find method of a collection should make it stick to the results generated on render, but it doesn't seem to work for me. Meteor keeps updating the template right away.
Here's the code I've got:
On the server side:
Meteor.publish("newsfeed", function () {
return Newsfeed.find({});
});
On the client side:
Meteor.subscribe('newsfeed');
Template.feed.feed_data = function() {
var feed = Newsfeed.find({}, {
sort: {updated_time: -1},
limit: 10,
reactive: false
});
return feed;
};
In the template:
<template name="feed">
<div id="feed-wrapper">
<ul>
{{#each feed_data}}
<li>
<div class="message">{{message}}</div>
</li>
{{/each}}
</ul>
</div>
</template>
If I then run Newsfeed.update({_id: 'some_random_id'}, {$set: {date_created: 'some_random_date'}}) in Dev Tools, the template updates the sorting of my news feed and changes it.
How do I make it not do that? :D
This is arguably a bug in Meteor. Passing reactive: false means that minimongo itself doesn't set up some code to say "observe and if it changes, invalidate". But #each has its own separate observeChanges call which uses the observe callbacks directly (not a reactive "invalidate and recalculate") to update the list. Probably we should not do this if the cursor has reactive: false on it. Track this in https://github.com/meteor/meteor/issues/771 !
Thats a bit odd, it ought to work. You could also use preserve:
Try adding this line in your client js
Template.feed.preserve(['#feed-wrapper']);
Btw is the template name="feed" in another template? Does this template have any reactive variables in it?

Resources