Edit one line in #each block - javascript

I have template:
{{#each action_log}}
<div>
{{Name}}
{{#if editing_score}}
<input type="text" id="set_score" parm="{{_id}}" value="" />
{{else}}
<div class="score" id="{{_id}}">{{Score}} .</div>
{{/if}}
</div>
{{/each}}
And I have a javascript code:
Session.set('editing_score', false);
Template.today_list.editing_score = function() {
return Session.equals('editing_score', true);
};
Template.today_list.events({
'click .score': function(e, t) {
Session.set('editing_score', true);
Session.set('editing_score_id', e.target.id);
Meteor.flush();
}
});
So, user can see list of actions, want to click on one of them and edit some value. But now, if user click on the action, the code display textboxes for all actions.
How can I display a textbox only for one action ?
I have action id in Session:
Session.set('editing_score_id', e.target.id);
But I can not do something like this:
{{#if editing_score && editing_score_id == _id}}
or
{{#if editing_score(_id)}}
What is the best way to do it ?
Thanks in advance.

With your template:
{{#if editing_score id}}
With your helper:
Template.today_list.editing_score = function(id) {
return Session.equals('editing_score_id', id);
};
However, I would refactor a bit so that you only have one Session variable — no need for two.
Also, your 'click .score' passes context, so you can id from this — which I find is more reliable than mucking around with the event that you are passing in.

Related

How to pass a variable to a helper and display its in the template?

I'd like to collect a variable(user _id)collected from a template, and pass it to another template using session. Then I want to display this variable.
Actually it seems to work in the collection of the variable and the pass to the other template, but I'm not able to display the user's info in the second template...
This is my code:
HTML
<template name="main"><!--Template 1-->
<table>
<tr>
<th>Patient</th>
</tr>
{{#each allUsers}}
<tr>
<th><label><input type="radio" class="selected" name="patient" value="{{this._id}}"><i class="fa fa-user"></i> {{this.profile.lastName}} {{this.profile.firstName}}</label></th>
</tr>
{{/each}}
</table>
{{>test}}
</template>
<template name="test"> <!--Template 2-->
<p>Name is <button class="test" name="patient" value="{{this._id}}">Test</button></p>
<div name="show">Name: {{this.profile.firstName}}</div>
</template>
JS
Template.main.events({
'click .selected': function (){
var selPat = $('input[name="patient"]:checked').val();
Session.set("selPat",selPat);
console.log("collect", selPat);
}
});
Template.test.events({
'click .test': function(){
var PAT= Meteor.users.findOne({ _id: Session.get("selPat")});
console.log("pass", PAT);
return PAT;
}
});
Template.patients.helpers({
allUsers: function() {
return Meteor.users.find({});
}
});
I want to display in the template 2 the first name of the user selected in the template 1 with {{this.profile.firstName}}
I believe this is what you are doing:
You are choosing patient's id from a list of patients via the radio buttons in the main template. [this implementation is correct]
You are setting the patient id in a session in the main template's events. [this implementation is correct]
When you click the "test" button in the test template, it should reveal the user's first name in the div below the button. [...not quite]
You are unable to display anything in <div name="show">Name: {{this.profile.firstName}}</div> because you don't have a relevant helper supplying the template with that information.
Although clicking a button to reveal the patient's firstName in the test template sounds a bit redundant, I'm sure you have some reason to do it in that manner.
I propose that you wrap the div inside an if block. The if condition renders true, when the button is clicked, and hence the div element is shown.
<template name="test"> <!--Template 2-->
<p>Name is <button class="test" name="patient" value="{{this._id}}">Test</button></p>
{{#if isButtonClicked}}
<div name="show">Name: {{data.profile.firstName}}</div>
{{/if}}
</template>
Your helpers and events will be like so:
Template.test.events({
'click .test': function(){
// set this session to true when the button has been clicked.
Session.set("testClicked", true);
}
});
Template.test.helpers({
isButtonClicked: function(){
// return the if block's validation.
return Session.get("testClicked");
},
data: function(){
// return the actual user data retrieved from the collection.
var PAT= Meteor.users.findOne({ _id: Session.get("selPat")});
console.log("pass", PAT);
return PAT;
});
Note:
You might want to make sure that the div does not stay open when you select a different patient from the list of radio buttons. Not doing so will make the div be visible when you first click the button, and remain open until you refresh the page, even when you select a different patient.
You could set testClicked to false or undefined in Template.main.events --> 'click .selected'

Meteor: Render a template to the DOM on click

I am having a seemingly simple problem that I cannot really find a solution to. I have 2 columns: One with an overview of different tasks, and one with an area where detailed information about a task should be displayed when the "More information" button attached to each task is clicked. My logic is:
Have 2 templates: task_short and task_long
When the button in task_short is clicked use Blaze.render to render task_long to a div in the second column.
when "More information" is clicked on another task_short, use Blaze.remove to remove the view.
My main problem is: How do I tell Meteor which task should be render in task_long? task_short gets its {{content}},{{name}} etc parameters through the each tasks loop. But how do I do it with a single task? Also, I don't really understand Blaze.remove. Where do I get the ViewId from that needs to be passed in?
I am insanely grateful for any help!
This can be solved with a session variable and some conditionals in your template. You shouldn't need to use Blaze.render/Blaze.remove unless you are doing something really fancy. I don't know exactly how your template is structured, but this example should give you and idea of what to do:
app.html
<body>
{{#each tasks}}
{{> task}}
{{/each}}
</body>
<template name="task">
<div class='short'>
<p>Here are the short instructions</p>
<button>More information</button>
</div>
{{#if isShowingLong}}
<div class='long'>
<p>Here are the long instructions</p>
</div>
{{/if}}
<hr>
</template>
app.js
if (Meteor.isClient) {
Template.body.helpers({
tasks: function () {
// return some fake data
return [{_id: '1'}, {_id: '2'}, {_id: '3'}];
}
});
Template.task.helpers({
isShowingLong: function () {
return (this._id === Session.get('currentTask'));
}
});
Template.task.events({
'click button': function () {
Session.set('currentTask', this._id);
}
});
}

How Do I Update A Button's Text in Meteor's Leaderboard Example?

I'm completely new to Meteor, and I was doing the leaderboard example. I have a little problem with my code.
I was trying to add a toggle button to toggle sorting. The toggling and all is working fine, but the button's text doesn't update.
My javascript code:
if (Meteor.isClient) {
Meteor.startup(function () {
Session.set("sortMethod", "score");
});
...
Template.leaderboard.players = function () {
if (Session.equals("sortMethod", "name"))
return Players.find({}, {sort: {name: 1}});
else if(Session.equals("sortMethod", "score"))
return Players.find({}, {sort: {score: 1}});
};
...
Template.leaderboard.sortMethod = function () {
return Session.get("sortMethod");
}
...
Template.leaderboard.events({
'click input.sortToggle': function () {
Session.equals("sortMethod", "name") ? Session.set("sortMethod", "score") : Session.set("sortMethod", "name");
}
});
}
My handlebars template:
<template name="leaderboard">
<!-- this is where it goes wrong, the button text doesn't update at {{sortMethod}} -->
<input type="button" class="sortToggle" value="sort by {{sortMethod}}">
<!-- -->
<div class="leaderboard">
{{#each players}}
{{> player}}
{{/each}}
</div>
{{#if selected_name}}
<div class="details">
<div class="name">{{selected_name}}</div>
<input type="button" class="inc" value="Give some points" />
</div>
{{else}}
<div class="none">Click a player to select</div>
{{/if}}
</template>
Note: I removed some irrelevant code.
It works if you use a button instead:
<button class="sortToggle">sort by {{sortMethod}}</button>
With the corresponding change to events:
'click .sortToggle': function () { ...
Changing the value of an input was reported as an issue in the past, but it was closed. Perhaps it needs to be reopened.
I am not sure if this is a bug or a feature. I think the problem stems from trying to update an input element that has focus. So the fix is to blur() the element on the end of your event handler. Like this:
'click input.sortToggle': function ( event ) {
Session.equals("sortMethod", "name")
? Session.set("sortMethod", "score")
: Session.set("sortMethod", "name");
$( event.currentTarget ).blur();
}

How to pass parameters with the action Helper of Ember.js inside an input field from an Handlebars template?

In my handlebars template I have this loop:
{{#each itemController="fund"}}
<li>
<label>{{title}}</label>
<span>{{amount}}</span>
{{input type="text" placeholder="new user"
value=newFullName action="createUser"}}
{{partial 'user-list'}}
</li>
{{/each}}
and need to pass the current object as parameter to the 'createUser' action.
Something like this:
action="createUser(this)"
or:
action 'createUser' this
But it seems that ember can't handle parameters for actions inside an input field...
Am i missing something?
You can now pass a function, along with values -
submit=(action 'setName' 'Sal')
http://emberjs.com/blog/2015/06/12/ember-1-13-0-released.html#toc_closure-actions
I think that isn't possible to do this using the action property from input view helper.
A workaround could be wrap your input in a form that use the action view helper using the submit event, like the following:
Template
{{#each}}
<li>
<form {{action "createUser" this on="submit"}}>
{{name}}
{{input type="text" value=name}}
</form>
</li>
{{/each}}
Route
...
actions: {
createUser: function(user) {
alert(user.get('name'));
}
}
...
So when the user hit enter, will have the event triggered.
The main difference between the action property and the action view helper is that the action view helper is more flexible and you can supply the context and put it inside of any tag:
<div {{action "someAction" someObject}} on="click">Click me</div>
In the route:
actions: {
someAction: function(someObject) {
// do something with the someObject
}
}
See the docs for further information
Please give a look in the jsfiddle to see that sample in action http://jsfiddle.net/marciojunior/UAgjX/
I hope it helps
Finally i ended up with this solution:
Template
{{input class="newUser" type="text" value=newFullName placeholder="add user"}}
<button {{action 'createUser' this newFullName}}>Send</button>
Controller
createUser: function (fund, newFullName) {
var fullName = newFullName;
var user = this.store.createRecord('appUser', {
fullName: fullName,
fund: fund,
payments:[]
});
user.save().then(function(){
fund.get('users').pushObject(user);
fund.save().then(function(){
fund.reload();
});
});
}
You can pass a parameter to an action helper :{{action "doSomething" xxx }}
Where doSomething is your controller method ,and xxx is anything in the current context of the template.

this.userId is undefined MongoDB property not inserted after submit

I have the following event in my client file:
Template.categories.events({
...
'keyup #add-category': function (e,t){
if (e.which === 13)
{
var catVal = String(e.target.value || "");
if (catVal)
{
lists.insert({Category:catVal,owner:this.userId});
Session.set('adding_category', false);
}
}
},
...
});
And this is the relevant template part:
<template name="categories">
<div id="categories" class="btn-group">
{{#if new_cat}}
<div class="category">
<input type="text" id="add-category" value="" />
</div>
{{else}}
<div class="category btn btn-inverse" id="btnNewCat">&plus;</div>
{{/if}}
{{#each lists}}
<div class="category btn {{list_status}}" id="{{_id}}">
{{Category}}
</div>
{{/each}}
</div>
</template>
So when a new Category is inserted, the owner should be set.. But it doesn't.
Here's the entry in MongoDB:
> db.lists.find()
{ "Category" : "test-admin", "_id" : "EsybjC3SLnNzCBx2t" }
Any idea what I'm doing wrong? (actually I'm following the "Getting Started with Meteor" book lending library example
EDIT it seems that:
console.log(this.userId);
undefined
Swap this line:
lists.insert({Category:catVal,owner:this.userId});
to this one:
lists.insert({Category:catVal,owner:Meteor.userId()});
this is probably not what you expect it to be inside that event. You should debug to confirm that that is the case. You are probably just getting undefined for this.userId. I would recommend assigning this to a variable (call it "self" or "that") outside of this event handler function but inside the scope where this will be what you actually want it to be. You can then reference that variable inside the event handler.
It should look like this:
function thatRegistersEvents() {
var self = this;
// ...
registerSomeEvent(function () {
return self.someThisProperty;
});
}
This is the correct behavior. If you read the official Meteor documentation for references to this.UserId, it is only available in Meteor.publish() and Meteor.methods(). this.UserId is not available in Meteor.template(), which you have done in the code sample above, so one must use Meteor.userId() in templates.

Categories

Resources