Meteor helper not called when Session changes - meteor

The following calls messages when the page loads but not when a Session value is changed. Here is the template code;
<head>
<title>Your welcome to chat</title>
</head>
<body>
{{> chat}}
</body>
<template name="chat">
<div class="ui list" style='height: 100px; overflow:scroll;' id='chatHistory'>
{{> currentChatList}}
</div>
<div class="ui large icon input">
<input type="text" class="field" id="message" placeholder="Type your message here" />
<i class="comment icon"></i>
</div>
</template>
<template name="currentChatList">
{{#each messages}}
{{/each}}
</template>
Here is the code;
if (Meteor.isClient) {
Template.chat.events ({
'keydown input#message' : function (event) {
if (event.which == 13) { // 13 is the enter key event
Session.set('time', new Date());
}
}
});
Template.currentChatList.helpers({
messages : function () {
debugger;
return [];
}
});
}
debugger statement is hit when the page loads, but not when the enter key is pressed on the textbox and Session.set('time'..) is executed. I thought a Session value change would cause the template to render.

saimeunt's answer will solve you problem. Your helper at the moment doesn't access any reactive variable (Session or Collection), which means it's never executed again.
Recently more and more people prefer to use reactive-var:
The idea is that you declare a reactive variable within your JS file and then USE that reactive variable in your helper. Every time you change the variable, all helpers using this variable are re-executed.

You do not depend on the Session variable you're assigning anywhere on your code. A reactive computation such as template helpers only reruns if one of its dependent reactive data sources is modified, which is clearly not the case in your example.
Try to depend on the Session variable inside your helper code to make it re-execute whenever you press enter.
Template.currentChatList.helpers({
messages: function () {
debugger;
var time = Session.get("time");
console.log("You pressed enter at",time);
return [];
}
});

FINALLY THE ANSWER: OMG.
https://blog.meteor.com/the-meteor-chef-reactive-dict-reactive-vars-and-session-variables-971584515a27
I have tried window.someVariableThatChanges = NOT WORKING
I have tried a Session.someVariableThatChanges = NOT WORKING
REACTIVE VARIABLE -- TOTALLY WORKING.
The difference is that you need to create a Template ON CREATED event, add your variables there. Simply use this variable in your even that changes the value, and your helper reference -- it works like magic and feels soooooo goooooood.

Related

This.data from #each-iteration

I'm trying to access a value inside an {{#each in}}-iteration:
{{#each room in channels}}
<form class="enterRoom">
<button type="submit" class="roomJoin">
<b>{{room.name}}</b>
<img src="{{room.roomBanner}}" alt=".">
<input type="hidden" value="{{room.name}}" name="name">
</button>
<div class="inRoom">
{{#each name in room.inRoom}}
{{name}}
{{/each}}
</div>
</form>
{{/each}}
Normally I would use this.name, for example, to get the name of it inside an event to use it further, like so
'submit .enterRoom'(event) {
event.preventDefault();
const isClosed = this.name; // room.name example here
}
But this doesn't work in this scenario. What I tried before was:
room.name
this.room.name
But those give the same error
chat.js:86 Uncaught ReferenceError: room is not defined
at Object.submit .enterRoom (chat.js:86)
at blaze.js?hash=51f4a3bdae106610ee48d8eff291f3628713d847:3818
at Function.Template._withTemplateInstanceFunc (blaze.js?hash=51f4a3bdae106610ee48d8eff291f3628713d847:3769)
at Blaze.View.<anonymous> (blaze.js?hash=51f4a3bdae106610ee48d8eff291f3628713d847:3817)
at blaze.js?hash=51f4a3bdae106610ee48d8eff291f3628713d847:2617
at Object.Blaze._withCurrentView (blaze.js?hash=51f4a3bdae106610ee48d8eff291f3628713d847:2271)
at Blaze._DOMRange.<anonymous> (blaze.js?hash=51f4a3bdae106610ee48d8eff291f3628713d847:2616)
at HTMLFormElement.<anonymous> (blaze.js?hash=51f4a3bdae106610ee48d8eff291f3628713d847:863)
at HTMLDivElement.dispatch (modules.js?hash=8331598f8baf48556a442a64933e9b70b778274a:9685)
at HTMLDivElement.elemData.handle (modules.js?hash=8331598f8baf48556a442a64933e9b70b778274a:9492)
Could someone explain to me how I could do it in this {{each in}}-setting properly?
The error has nothing to do with the each iterations of your template. What you try is to get the form data within the submit event handle. However, there is no context bound to this or room.
In order to get the room value, you need to access the input value.
Blaze offers a fast way of doing so, by using the Template's builtin jQuery (using templateInstance.$), which automatically scopes to the Template root instead of the whole document:
'submit .enterRoom'(event, templateInstance) {
event.preventDefault();
const roomName = templateInstance.$(event.currentTarget).find('input[name="name"]').val();
// ...
}

In Meteor How to copy data between templates?

I'm new to both meteor and JS.
I created a meteor app like this:
cd /tmp/
meteor create hello
cd hello
In hello.html I wrote this
<body>
<h1>Welcome to Meteor!</h1>
{{> t1}}
{{> t2}}
</body>
Then I added these templates:
<template name='t1'>
<span id='t1'>hello</span>
</template>
<template name='t2'>
<span id='t2'>world</span>
</template>
Then I wrote syntax inside of hello.js to get text from the DOM:
Template.t1.onRendered( function() {
mytext = $('span#t1').html() });
According to the debugger-console in my browser,
the above syntax works okay.
The debugger tells me that mytext == 'hello'
Question: How to share the mytext value with other parts of my Meteor app?
As written, mytext is stuck inside my anonymous function.
For example how would I make this call work:
$('span#t2').html(mytext)
??
You'll want to reactively watch your variable. An easy out-of-the-box solution for this is to use the Session variable. You can do it pretty easily like so:
Template.t1.onRendered( function() {
Session.set('mytext', $('span#t1').html());
});
Then in your second template, define and reference helper that returns that variable:
<!--html-->
<template name='t2'>
<span id='t2'>{{getMyText}}</span>
</template>
//js
Template.t2.helpers({
getMyText: function() { return Session.get('mytext'); }
});
The Session variable is reactive, so when the first template renders and sets the value of Session.mytext, the helper's result will be invalidated and the second template will update.

Content wrapped in currentUser re-rendering when user updated

I'm using Meteor and having an issue where my content is being re-rendered when I don't want it to.
I have my main content wrapped in a currentUser if statement which I feel is fairly standard.
{{#if currentUser}}
{{> content}}
{{/if}}
The problem with this is my content template is being re-rendered when I update my user object. Is there any way around this? I don't reference users anywhere inside the content template.
Thank you!
Here's a sample app to replicate my problem:
HTML
<head>
<title>Render Test</title>
</head>
<body>
{{loginButtons}}
{{> userUpdate}}
{{#if currentUser}}
{{> content}}
{{/if}}
</body>
<template name="userUpdate">
<p>
<input id="updateUser" type="button" value="Update User Value" />
User last update: <span id="lastUpdated">{{lastUpdated}}</span>
</p>
</template>
<template name="content">
<p>Render count: <span id="renderCount"></span></p>
</template>
JavaScript
if (Meteor.isClient) {
Meteor.startup(function() {
Session.set("contentRenderedCount", 0);
});
Template.content.rendered = function() {
var renderCount = Session.get("contentRenderedCount") + 1;
Session.set("contentRenderedCount", renderCount);
document.getElementById("renderCount").innerText = renderCount;
};
Template.userUpdate.events = {
"click #updateUser": function() {
Meteor.users.update({_id: Meteor.userId()}, {$set: {lastActive: new Date()}});
}
};
Template.userUpdate.lastUpdated = function() {
return Meteor.user().lastActive;
};
}
if (Meteor.isServer) {
Meteor.users.allow({
'update': function () {
return true;
}
});
}
Update:
I should've explained this example a little. After creating a user, clicking the Update User Value button, causes the render count to increment. This is because it's wrapped in a {{#if currentUser}}. If this is if is removed, you'll notice the render count remains at 1.
Also, you'll need to add the accounts-ui and accounts-password packages to your project.
Meteor will re-render any template containing reactive variables that are altered. In your case the {{currentUser}} is Meteor.user() which is an object containing the user's data. When you update the users profile, the object changes and it tells meteor to re-calculate everything reactive involving the object.
We could alter the reactivity a bit so it only reacts to changes in whether the user logs in/out and not anything within the object itself:
Meteor.autorun(function() {
Session.set("meteor_loggedin",!!Meteor.user());
});
Handlebars.registerHelper('session',function(input){
return Session.get(input);
});
Your html
{{#if session "meteor_loggedin"}}
{{> content}}
{{/if}}

meteor : setting fields post opening dialog

I'm trying to complete the parties demo
with an "edit party" feature
I understood the create Dialog opens upon setting Session showCreateDialog
{{#if showCreateDialog}}
{{> createDialog}}
{{/if}}
this shows the popin
but I want to set to fields post opening
and I don't see how to act after the opening action ?
You can set manipulate the DOM inside the Template's rendered event. But if you find yourself writing lots of glue code here ($("#someInput").val("someVal")) then watch out because you're likely on the wrong track!
Template.createDialog.rendered = function() {
// you can manipulate the DOM here
}
Remember, you can bind field values to instances, so something like the below will auto-bind your object
<template name="editDialog">
{{#with party}}
<input type="text" id="myPartyName" value="{{name}}" />
...
{{/with}}
</template>
Template.editDialog.party = function() {
return Parties.findOne(Session.get("selectedParty"));
};

returning findOne object to template

Having troubles understanding how to return and use an object from findOne().
my code is this:
Html:
<head>
<title>count</title>
</head>
<body>
{{> hello}}
</body>
<template name="hello">
{{showcount}}
</template>
Js:
var Database = new Meteor.Collection("counters");
if(Meteor.is_client) {
Template.hello.showcount = function () {
var c = Database.findOne();
return c;
};
}
if (Meteor.is_server) {
Meteor.startup(function () {
if(Database.find().count() === 0)
{
Database.insert({name: "counter", value: 0});
}
});
}
Now I'm wondering if there is any way I can access the data from my object.
changing from {{showcount}} to {{showcount.name}} doesn't seem to work at all.
This same issue got me a few times when I started out with Meteor...
When the Meteor client connects to the server the template is being rendered before the collections have finished being synchronised. i.e. The client collection is empty at the point you are calling findOne.
To see this in action stick a console.log(c) after your findOne call then try reloading the page. You will see two log entries; Once on initial page load and then again when the collection has finished being synchronised.
To fix this all you need to do is update your hello template to handle the fact the collection might not have been synchronised.
{{#if showcount}}
{{showcount.name}}
{{/if}}
I tested your code with the above change and it works.
The proper way to do this is with the #with tag.
<template name="hello">
{{#with showcount}}
{{name}}
{{/with}}
</template>
See the documentation below for more info on the #with tag
https://github.com/meteor/meteor/blob/devel/packages/spacebars/README.md

Resources