How to get name in spacebar {{ <some name> }} in Meteor - meteor

I want to get the property name of spacebar Ex.
<template name="example">
{{#with object}}
{{level1.level2}}
{{permission.post.create}}
{{permission.post.read}}
{{/with}}
</template>
After I click on it I want to get the name of property
Template.example.events({
"click <selector>" : function(event,template){
//Question how to get name "level1.level2" ,"permission.post.create" ,"permission.post.read"
var name1 = ??? // I want name1 = "level1.level2" (string not it value)
//After I get the property name I can use it in MongoDB query like this
var key = {}
key[name1] = "newvalue" // now I got { 'level1.level2' : 'newvalue'}
Model.update({_id : "abc"}, key)
}
})
It very useful when you have to update deep nested document Ex.. table of permission list with checkbox

what about to add data- properties to the html elements, and then when you receive the event, you can do something like var -id = $(event.target).attr("data-id"); I didnt understand completely your question neither have access to you data structure but assuming that you want to get an information from the object that you render in a html element. My suggestion its the follow:
<template name="mytemplate">
{{ object.name }}
</template>
Template.<name>.events({
"click <selector>" : function(event,template){
//Question how to get name "level1.level2" ,"permission.post.create" ,"permission.post.read"
var name1 = $(event.target).attr("data-name");
//do whatever with you variable
}
})
Sorry if this its not what are you looking.

ncubica your answer was close that what I want.
I use
<template name="mytemplate">
{{level1.level2}}
</template>
Then I can use it like this
"click .toggle-checked" : function(event,template){
var pName = $(event.target).attr("data-name")
var updateAttr ={}
updateAttr[pName] = "theNewValue"
Collection.update({_id : this._id},{ $set : updateAttr})
}
Thank you for your hint.

Related

Displaying items from collection in a template

The below code is expected to insert a document of 3 pairs in the FooterButtons collection, then those values are shown as labels on 3 buttons in the footer template.
But when the "click .menuItem" is called, it only insert "YES" in the collection. Any idea why it is broker and best way to fix it? Thanks
Server and client code
FooterButtons = new Mongo.Collection('footerButtons');
Server code
Meteor.publish('footerButtons', function(){
return FooterButtons.find();
});
Client code
Meteor.subscribe('footerButtons');
//---main_menu.js--------------------
Template.mainMenu.events({
'click .menuItem': function (event) {
FooterButtons.insert({button:"NO", button:"EXTRA", button:"YES"});
}
});
//---footer.html---------------
<template name="footer">
{{#each footerButtons}}
<h1>
<button class="col-xs-4" type="button">{{button}}</button>
</h1>
{{/each}}
</template>
//---footer.js---------------
Template.footer.helpers({
footerButtons: function(){
return FooterButtons.find();
}
});
This command is totally wrong for the mongo insertion
FooterButtons.insert({button:"NO", button:"EXTRA", button:"YES"});
If you create a javascript object,
var obj = {button:"NO", button:"EXTRA", button:"YES"};
since all the keys is duplicated, your object will only has one key which has the value of the last one: Yes
You need to insert one by one
FooterButtons.insert({button:"NO"});
FooterButtons.insert({button:"EXTRA"});
FooterButtons.insert({button:"YES"});

Multiple events handlers invoked by single text input event

I have two separate form input's (both text type), one in template A, and one in template B. Template A invokes template B. All the specific names/properties of these two input form's are unique. I have event handlers for both, within their own properly named Template.name.events().
When I build a very simple test case of this, no problems, everything works fine. But in my larger and more complex actual app, when I enter text into the template B form, the correct template B submit event handler gets invoked. And then...the template A submit event handler gets invoked! This happens even when I do nothing but an event.PreventDefault call in handler B (side question: are event handlers ever invoked for reactive reasons, or strictly "event occurred" reasons?). I am able to work around this odd behavior for the moment by checking in the A event handler for an undefined name property and just exiting if that's the case, but that's just a kludge for something wrong somewhere. Any suggestions as to a likely culrprit for this odd behavior in my code? Thanks!
Here's the code for the two templates in the failing case; the first (entryHall, with the "new-room" form input) is the "A" template, the second (knock, with the "knock-room" form input) the "B" template. Underneath the event handling code for those two templates is the html+handlebars code for the template definitions and invocations. Sorry for the verbosity and lack of a simpler failing case!
Template.entryHall.events({
// NEW ROOM REQUEST PROCESSING
"submit.new-room": function (event) {
event.preventDefault();
if (event.target.roomName === undefined) {
console.log ("in submit new room and roomname in event is undefined");
return;
}
var rName = event.target.roomName.value;
// Is there already a room name of this same name in the Rooms collection?
var roomsCursor = Rooms.findOne({ roomName: rName });
if (roomsCursor != null) {
// It's a dup; don't allow it
event.target.roomName.value = "Duplicate room name, try again";
return(null);
}
var uName = Session.get ('userName');
// It's a unique name, put it in the Rooms collection.
Rooms.insert({
roomName : rName,
owner : uName,
members: [], // an array of user names
knockRequests: [], // an array of user names
chat : null,
files : null
});
// We have the room document added to the Rooms collection, now we have to
// add the room to the owned list for the user
var userEntry = PZUsers.find({ userName : uName }).fetch();
PZUsers.update({ _id : userEntry[0]._id},
{ $push: { ownedRooms: rName }});
ownedRoomCount++;
roomReactor.changed();
event.target.roomName.value = "";
}
});
Template.knock.events({
// Knock on a room request processing
"submit.knock-room": function (event) {
// Prevent default browser form submit
event.preventDefault();
var knockName = event.target.knockName.value;
event.target.knockName.value = "";
console.log("in knock room submit!");
// Can only knock on a room that exists!
var knockRoomCursor = Rooms.findOne({ roomName: knockName });
if (knockRoomCursor == null) {
console.log ("no such room found to knock on");
return;
}
// Add a knock request to this room, and add this room the the user's list of "open knocks" rooms
var roomEntry = Rooms.find({ roomName : knockName }).fetch();
console.log ("_id of room: " + knockName + " is: " + roomEntry[0]._id);
Rooms.update({ _id : roomEntry[0]._id },
{ $push: { knockRequests: Session.get('userName') }});
roomReactor.changed();
}
});
And here's the invoking html:
<template name="entryHall">
<h2>Welcome {{userName}}</h2>
<h3>Create a new room:</h3>
<div class="roomName">
<form class="new-room">
<input type="text" name="roomName" id="roomName" placeholder="Select a room name" />
</form>
</div>
{{markNoOwnedRooms}}
{{#each ownedRooms}}
{{#if firstOwnedRoom}}
<h3>Enter one of your own rooms:</h3>
{{/if}}
{{ > room }}
{{/each}}
{{markNoMemberRooms}}
{{#each memberRooms}}
{{#if firstMemberRoom}}
<h3>Enter one of your member rooms:</h3>
{{/if}}
{{ > room }}
{{/each}}
<h3>Knock to request entry:</h3>
{{ > knock }}
</template>
<template name="room">
<li>{{this}}</li>
</template>
<template name="knock">
<div class="knockName">
<form class="knock-room">
<input type="text" name="knockName" id="knockName" placeholder="Enter room name" />
</form>
</div>
</template>

Why isn't the URL being generated for this route?

So, I'm working on a Meteor project and I can't get this route to generate properly, or at all for that matter.
<template name="browseAll">
<h3>List of classes with books available!</h3>
<ul>
{{#each aggCount}}
<li>{{ _id }} ({{ count }})</li>
{{/each}}
</ul>
</template>
The data that is being iterated over is a result of aggregation using MongoInternals, and that is as follows:
(server/methods.js excerpt):
classCount: function() {
// Attempt aggregation of the books table to count by class, maybe.
var db = MongoInternals.defaultRemoteCollectionDriver().mongo.db;
var col = db.collection("books");
var aggregateSync = Meteor._wrapAsync(col.aggregate.bind(col));
var pipeline = [
{$group: {_id: "$class", count: {$sum: 1}}},
{$sort: {_id: 1}}
];
var theAnswer = aggregateSync(pipeline);
return theAnswer;
}
It seems that the data is coming through okay, and sample data from aggregation (coming into the template) looks like this:
[ { _id: 'ADNR1234', count: 2 }, { _id: 'ARTH1234', count: 1 } ]
That's the template code I've got, and this is the route that it's supposed to be working with:
this.route('browse-class', {
path: '/browse/:_class',
data: function() {
var booksCursor = Books.find({"class": this.params._class},{sort:{"createdAt": 1}});
return {
theClass: this.params._class,
numBooks: booksCursor.count(),
books: booksCursor
};
}
});
I don't understand it. The data is being SHOWN, and what I want to do is generate a URL for browse-class (route) that takes the value of {{ _id }} in the helper as a parameter, so as to generate something like this:
application.org/browse/CLSS
Be aware that {{pathFor}} must be called with a data context properly set :
{{#with class}}
{{pathFor "browse-class"}}
{{/with}}
Optionnaly it is possible to pass the data context as a parameter :
{{pathFor "browse-class" class}}
The data context provided to pathFor is used when generating the route path, if you defined a route path like this :
path: "/browse/:_id"
Then it will use the _id from the class to properly generate a URL.
For the text of the link, I doubt you want to display the _id, your class documents probably include a "label" so you could use this :
{{ label }}

Use a separate variable for each template created

Here's what I have:
home.jade
body
div {{> hello 'World' }}
div {{> hello 'Town' }}
hello.jade
template(name="hello")
button.sayHello Say {{name}}
hello.coffee
obj = {}
Template.hello.created = ->
obj.name = this.data
Template.hello.helpers
name: -> obj.name
Template.hello.events
'click .sayHello': -> console.log obj.name
It displays the two buttons correctly ("Say World" and "Say Town"). But if you click any button the output is always "Town" (the last one to be created and rendered).
How can I share a variable in a template so that it's unique for each template created? In other words I want to be able to set values on a variable in the created event and then be able to access them in the events (for each template created/rendered).
You just need to pass an object as the context to the hello template. Try replacing all of your code with:
hello.jade
body
div {{> hello name='World' }}
div {{> hello name='Town' }}
template(name="hello")
button.sayHello Say {{name}}
hello.coffee
Template.hello.events
'click .sayHello': (e, t) ->
console.log t.data.name
Recommended reading:
guide-to-meteor-templates-data-contexts
spacebars-secrets
In your example obj is shared by every instance of template hello.
Try to use instance of template as a key in obj:
obj = {}
Template.hello.created = ->
// this is instance of template
obj[this] = {name : this.data }
Template.hello.helpers
// here is problem, there is no access to template instance:
// see https://github.com/meteor/meteor/issues/1529
// name: -> obj[this].name
Template.hello.events
'click .sayHello': (e, tmpl)-> console.log obj[tmpl].name

Meteor - Select Parent ID of element clicked

Using Meteor, I am trying to loop through and display a list of notes from a database with an option to delete each note.
Here is the HTML (using Handlebars.js)
<template name="Notes">
{{#each NoteArr}}
<div class="Note">
<h2>{{Title}}</h2>
<p>{{Body}}</p>
<span class="deleteNote">Delete</span>
</div>
{{/each}}
</template>
And here is the client Javascript
Template.Notes.events = {
"click .deleteNote" : function(){
noteID = $('.deleteNote').parent().attr("id");
Notes.remove({ID:noteID});
}
};
This grabs the first instance of .deleteNote, so unless I'm trying to delete the first one, that won't help. How can I grab the parent of the particular instance of .deleteNote that was clicked, not just the first one it finds?
The reason why the first element is deleted is.. in your .click event, you are accesssing the div directly as $('.deleteNote').parent() which grabs the first node in the html which has a class .deleteNode.
Now to remove the specific notes, from the collection: Every document in the collection has a unique _id attribute which is generated automatically. assign that unique _id of the document to the span element as <span id= "{{_id}}" class="deleteNote">Delete</span>.
So the cilck event will look like:
Template.Notes.events = {
"click .deleteNote" : function(e){
var noteID = e.currentTarget.id;
Notes.remove({_id:noteID});
}
};
And the template will look like:
<template name="Notes">
{{#each NoteArr}}
<div class="Note">
<h2>{{Title}}</h2>
<p>{{Body}}</p>
<span id= "{{_id}}" class="deleteNote">Delete</span>
</div>
{{/each}}
</template>
Untested code, but hope this will help solving your issue.
The _id of a note is stored in 'this' as well. In addition, the remove function accepts '_id' as a string. So this should work as well:
Template.Notes.events = {
'click .deleteNote': function(){ return Notes.remove(this._id)}
}
A few benefits here. Less querying the DOM for information. Less jQuery. Fewer lines of code to think about. Cleaner templates.

Resources