Meteor.js mplement a singleton confirm box - javascript

I try to create a reusable confirm box, but i'm unsure how to implement this the meteor way.
I have a template for the confirm box. The text and button value should be dynamic.
<template name="confirm">
{{#if show}}
{{text}}
<button class="cancel">cancel</button>
<button class="confirm">{{action}}</button>
{{/if}}
</template>
And i have a user template with an delete button.
<template name="user">
<h1>{{name}}</h1>
<button class="delete">delete user</button>
</template>
In the app template i display a list of users and render the confirm template.
<template app="app">
{{#each user}}
{{> user}}
{{/each}}
{{> confirm}}
</tempalte>
Now when i click the delete button of a user item i want to display the confirm box.
Template.confirm.helpers({
text: function(){
return Session.get('confirmText');
},
action: function(){
return Session.get('confirmAction');
},
show: function(){
return Session.get('showConfirm');
},
});
Template.user.events({
'click .delete': function(){
Session.set('confirmAction', 'delete');
Session.set('confirmText', 'Are you sure?');
Session.set('showConfirm', true);
}
});
My confirm box displays as it should but how can i trigger the user deletion from the confirm box?
Am i even on the right track? I tried to render a confirm template inside of every user template but there should only be one active confirm box at a time.

You can certainly make it work using this pattern. The only addition you need to make is to set the user id you intend to delete in the Session, so it is accessible to your deletion method:
Template.user.events({
'click .delete': function(){
Session.set('confirmAction', 'delete');
Session.set('confirmText', 'Are you sure?');
Session.set('showConfirm', true);
/* addition - this._id refers to the id of the user in this template instance */
Session.set('userToDelete', this._id);
}
});
And then:
Template.confirm.events({
"click button.confirm": function(){
Meteor.call(
"deleteUser",
Session.get("userToDelete"),
function(error, result){
Session.set("userToDelete", null);
}
);
}
});
However a more flexible and extensible pattern would be to get and set the user you are confirming deletion of internal to the user template, using a ReactiveVar or ReactiveDict attached to the template instance. That way you are not loading up the global Session object with keys that really only involve one piece of behavior. And you could reuse your confirm template in other, unrelated contexts.
UPDATE
Here is a way to reuse a confirm button across contexts with a private reactive-var. To see if another confirmation box is open you can first check a Session property.
Session.setDefault("confirming", false);
The text and action properties in the confirm template are set from its user parent:
<template app="app">
{{#each user}}
{{> user}}
{{/each}}
</template>
<template name="user">
<h1>{{name}}</h1>
<button class="delete">delete user</button>
{{#if show}}
{{> confirm text=text action=action}}
{{/if}}
</template>
<template name="confirm">
{{text}}
<button class="cancel">cancel</button>
<button class="confirm">{{action}}</button>
</template>
And we set the helpers and events for it in the user parent as well:
Template.user.created = function(){
this.show = new ReactiveVar(false);
}
Template.user.helpers({
name: function(){
return this.name;
},
show: function(){
return Template.instance().show.get();
},
text: function(){
return "Are you sure?";
},
action: function(){
return "delete user";
}
});
Template.user.events({
"click button.delete": function(event, template){
if (Session.get("confirming")){
console.log("You are already confirming another deletion.");
return;
}
Session.set("confirming", true);
template.show.set(true);
},
"click button.confirm": function(event, template){
Meteor.call(
"deleteUser",
this._id,
function(error, result){
template.show.set(false);
Session.set("confirming", false);
}
)
}
});
Now you can give the confirm template a different context somewhere else based on its parent.

Related

Meteor js condition with each loop

I am very new to meteor js and trying to build a small messaging app.
What I want to do is I want to check a condition within the loop with
Probably, something like this.
<div class="messages-box">
{{#each messages}}
{{#if isCurrentUserCan}}
<p>{{msg that user can do bla bla}}</p>
{{else}}
<p>{{msg that user can't do}}</p>
{{/if}}
</div>
{{/each}}
</div>
js
Template.body.helpers({
'isCurrentUserCan': function(){
if ( random message box's user ID == Meteor.userId() ){
return 'This user can do bla bla';
}else{
return 'This user can't do';
}
}
});
How can I achieve it?
You're iterating over a collection of messages. Let's say that each message includes a userId key. You can check to see if the userId of the message is the same as the current user and return true or false accordingly.
Template.body.helpers({
'isCurrentUserCan'() {
return this.userId === Meteor.userId();
}
});
Inside the {{each}} this is set to the current message object so this.key directly accesses the corresponding key.

Changing template on Link Click Meteor

There is a button :
<a id = "login" class="waves-effect white blue-text text-darken-2 btn"><i class="fa fa-pencil"></i> Write</a>
and there are two templates, firstpage, and secondpage.
Now, I want Meteor to change templates when I click that link, and render the second page.
How can I do this?
I used aldeed:template-extension but it doesnt work.
You can use some helpers here, and template variables.
Lets say you have this template.
<template name="example">
{{#if clicked}}
{{> firstPage}} <!-- the firstPage template will be rendered if the var is == false -->
{{else}}
{{> secondPage}} <!-- this will be render when the session is equals to true -->
{{/if}}
</template>
Now the Javascript.
First on the onCreate function declare the default values (similar so Session.setDefault)
Template.example.onCreated( function(){
var self = this;
self.vars = new ReactiveDict();
self.vars.setDefault( 'clicked' , true ); //default is true
});
Now the event to change the state of the clicked to false (Similar to Session get/set).
Template.example.events({
'click .waves-effect':function(event,template){
var instance = Template.instance();
instance.vars.set('clicked', false) //set to true.
}
})
Now we something to listen our variables changes, lets use a helper
Template.example.helpers({
clicked:function(){
var instance = Template.instance(); //http://docs.meteor.com/#/full/template_instance
return instance.vars.get('clicked') //this will return false(default) | true
}
})
NOTE Here we are using reactive-dict wich share the same syntaxis of a Session.
meteor add reactive-dict
Here is the MeteorPad Example

Getting Meteor 0.9.1.1 click event to update object

I'm just playing around with different patterns and am very new to programming, however I've got everything to work in my test app so far except this. I've tried a bunch of variations with no luck, but I suspect I'm missing something really simple.
Basically what I want to happen is for a user to click a button and for it to then update the value of two specific attributes of the current object.
In this example I'm wanting the update to occur when the user clicks the "Return" button (the other buttons shown below are working fine).
Here's the HTML template for the button in question:
<template name="bookDetails">
<div class="post">
<div class="post-content">
<h3>{{title}}</h3><span> {{author}}</span>
{{#if onLoan}}
<i class="fa fa-star"></i>
On loan to: {{lender}}{{/if}}
</div>
{{#if ownBook}}
Edit
Lend
<div class="control-group">
<div class="controls">
<a class="discuss btn return" href="">Return </a>
</div>
</div>
{{/if}}
</div>
</template>
Here's the .js file which contains my Template event. Basically I want to set the values for the "lendstatus" and "lender" attributes.
Template.bookDetails.helpers({
ownBook: function() {
return this.userId == Meteor.userId();
},
onLoan: function() {
return this.lendstatus == 'true';
}
});
Template.bookLoan.events({
'click .return': function(e) {
e.preventDefault();
var currentBookId = this._id;
var bookProperties = {
lendstatus: "false",
lender: "",
}
Books.update(currentBookId, {$set: bookProperties}, function(error) {
if (error) {
// display the error to the user
throwError(error.reason);
} else {
Router.go('bookPage', {_id: currentBookId});
}
});
},
});
If I type the following into the Browser console while on the page for the object with id ZLDvXZ9esfp8yEmJu I get the correct behaviour on screen and the database updates so I know I'm close:
Books.update({ _id: "ZLDvXZ9esfp8yEmJu"}, {$set: {lendstatus: "false", lender: ""}});
What am I missing?
OK - so my problem was that I'd defined the event handler in the wrong template. I'd defined it in the bookLoan template instead of the bookDetails template. Thanks #saimeunt for pointing this out!

meteor: render a template in a specific context

I have two templates
<body>
{{>tmpl1}}
{{>tmpl2}}
....
</body>
in the tmpl1 I have a list of items, which can be clicked. When one is click, tmpl2 shown the details. How can this be achieved ?
So, just to make the idea clearer, here is how I get the list of items
Template.tmpl1.items = function () {
return Items.find({}).fetch();
};
tmpl1 displays them as follows
<template name="tmpl1">
{{#each items}}
{{title}}
{{/each}}
....
</template>
So tmpl2 template might look like this
<template name="tmpl1">
<h1>{{title}}</h1>
<p>{{content}}</p>
</template>
Any suggestions how to link the selected item in tmpl1 with tmpl2 ?
First, put your templates in a container so that you can manipulate the context. Also, put the details template in a #with context:
<template name="box">
{{> list}}
{{#with item}}
{{> details}}
{{/with}}
</template>
Now, add the event handlers for the box template. Assuming your entries in the list looks like this:
<div class="listItem" data-id="{{_id}}">{{title}}</div>
Write the handler:
Template.box.events({
'click .listItem': function(e, t) {
t.data.itemId = $(e.target).data('id');
t.data.itemDep.changed();
}
});
Finally, create the data helper and dependency for the selected item:
Template.box.created = function() {
this.data.itemDep = new Deps.Dependency();
};
Template.box.item = function() {
this.itemDep.depend();
return Items.findOne(this.itemId);
};

Helpers in templates

Seeing if I can insert a helper into a template. Seems like I'm doing something wrong because you can't actually click the buttons in my program.
HTML:
<head>
<title>BubblePopper</title>
</head>
<body>
{{loginButtons}}
{{>home}}
</body>
<template name ="grid">
<div id="container">
{{#each buttons}}
<button class="button" type="button"></button>
{{/each}}
</div>
</template>
<template name = "home">
<h1> Welcome to bubblePopper</h1>
<p> Current Game Status:
//this is the part I'm confused about is it ok to insert the grid helper into this
//if statement in the template?
{{#if game.active}}
Game in progress. Finish Game<br>
<center>{{>grid}}</center>
{{else}}
{{#if game.finished}}
Game done or another player left.Start a new game
{{else}}
Waiting for a new player to login. Find a new game
{{/if}}
{{/if}}
</p>
<p><strong> Current Game ID: </strong>{{game._id}}</p>
<p><strong> Current Game Player Count: </strong>{{game.players.length}}</p>
<p><strong> Current Game Active: </strong>{{game.active}}</p>
</template>
Client.JS:
if (Meteor.isClient) {
Deps.autorun(function(){
gameSubscription = Meteor.subscribe("myGames",Meteor.userId());
});
Template.home.game = function(){
return gameCollection.findOne({current: true});
};
Template.home.events({
"click #newGame" : function() {
Meteor.call('newGame')
},
"click #finishGame": function(){
var game = gameCollection.findOne({current: true});
Meteor.call('finishGame', game._id);
}
});
//was confused if I should just include buttons as a part of homes template
Template.grid.buttons = function (){
var list = [];
for(var i=1; i<=64; i++){
list.push({value: i});
}
return list;
}
Template.button.events({
'click .button': function(ev) {
$(ev.target).css('visibility', 'hidden');
console.log("pop")
}
});
}
I didn't include the server.js because it has nothing to do with any of the template helper relationship. Is this the right way to insert the grid? Also is it an error in my HTML that isn't allowing the buttons to be clicked?
Looks like you've mixed up the name of your template. If it's the buttons in the grid template you're referring to, you need to change the line Template.button.events({ to Template.grid.events({ and then you should see the function being executed when a button is clicked.

Categories