Checking equality in Blaze? - javascript

The user can only delete a post if he was the one who posted it.However a user can see all the posts.The javascript code is:
var postedBy = Meteor.user();
var currentPost = this._id;
Posts.insert({
name:postName,
createdAt:new Date(),
postId:currentPost,
postedBy:postedBy
});
The HTML code is:
<template name="posts">
{{#if currentUser}}
{{> addPost}}
<ul>
{{#each post}}
<li>{{> postItem}}</li>
{{/each}}
</ul>
{{/if}}
</template>
<template name="postItem">
<li>
<h4>{{name}}</h4>
<i>Posted by {{postedBy.username}} on {{createdAt}}</i>
[Delete]
</li>
</template>
<template name='addPost'>
<input type='text' placeholder='Add post here' name='postName' id ='myinput'>
<button class="btn btn" type="button" id='btn'>Post</button>
</template>
Both currentUser.username and postedBy.username are displaying the names of the logged in user and the user who posted a particular post respectively.
I am trying to work with the Delete anchor tag.
{{#if currentUser.username==postedBy.username}}
[Delete]
{{/if}}
But it shows error in command prompt.I know it is wrong but I can't think of any other way.How do i write this 'if' statement to check if the current user was the one who posted this post?
Please help as I am new to Meteor.Sorry for bad English.

You can't use arbitrary JavaScript expressions in spacebars. Add a helper like this:
Template.postItem.helpers({
canDelete: function (){
return Meteor.user().username === this.postedBy.username;
}
});
Which you can then use in your template like this:
{{#if canDelete}}
Delete
{{/if}}
Also note, instead of copying the user object into each post, the recommended way is to store the user's id in postedBy.

Related

How to know if an insertion was successfull in a MongoDB Collection with Meteor.JS (inside the Template)

The situation
Let's break this question down to a simple todo list of which the entries are listed in a \li:
//main.html
<ul>
{{ #each listEntries }}
<li class="item">
{{ title }}
</li>
{{ /each }}
</ul>
Serverside:
//main.js
TodoCollection = new Mongo.Collection('todo_collection');
Now I am calling manually from the console in the client:
TodoCollection.insert({title: 'My first entry'});
Up to this point everything's fine.
Now meteor.JS works asynchronously which means that the changes that are made in the client also have effect on the DOM right away without knowing if the database insertion was successfull or not. If not, the DOM Element will be removed again (so first meteor inserts the new <li>, then it removes it again if insertion failed).
How can you get the information from meteor that something comes actually from the database?
What I need:
//main.html
<ul>
{{ #each listEntries }}
<li class="item">
{{ title }}
{{ #if isInDatabase }}
- i am actually stored!
{{ /if }}
</li>
{{ /each }}
</ul>
You can use the callback of the insert method of the collection. The callback is called with the error (null if there is none) and the object Id that was stored in the database
Below you can see the code to test this:
html:
<head>
<title>simple</title>
</head>
<body>
<h1>Welcome to Meteor!</h1>
{{>test}}
</body>
<template name="test">
<ul>
{{#each item in list}}
<li>{{item.name}}</li>
{{/each}}
</ul>
{{#if insertResult}}
<div class="insert_result">{{insertResult}}</div>
{{/if}}
{{#if insertError}}
<div class="insert_error">{{insertError}}</div>
{{/if}}
<form>
<input type="text" name="name" />
<input type="submit" value="Add" />
</form>
</template>
Javascript:
import { Template } from 'meteor/templating';
import { ReactiveVar } from 'meteor/reactive-var';
collection = new Mongo.Collection('collection');
if (Meteor.isClient) {
Template.test.onCreated(function () {
this.insertResult = new ReactiveVar();
this.insertError = new ReactiveVar();
});
Template.test.helpers({
list() {
return collection.find();
},
insertResult() {
return Template.instance().insertResult.get();
},
});
Template.test.events({
'submit form'(event, instance) {
event.preventDefault();
collection.insert({
name: event.target.name.value
},function(err,result) {
if (err) {
instance.insertError.set(err);
instance.insertResult.set(null);
} else {
instance.insertResult.set(result);
instance.insertError.set(null);
}
});
},
});
}
As you can see in the previous answer, it is quite cumbersome in Meteor to know what causes a reactive update.
I would suggest a different approach: Don't insert on the client. Make a Meteor.call() to a server method which does the insert, and then let the client update reactively. Then you are always sure that what you see on the screen is actually in the database.
I think I found the most trivial solution myself:
Adding a hook on server-side that will add the date of creation with obj.onCreated = new Date(); helps identifying that it came from the server because this will not exist on the client.
{{#each item}}
{{ #if item.onCreated }}
<li class="success-db">{{name}}</li>
{{ else }}
<li class="pending-db">{{name}}</li>
{{ /if }}
{{/each}}
(Please do not hesitate to improve this answer if you find it contradictory to how Meteor.JS works)
If you want to show the data which title exist then you can write the code like this.
<ul>
{{ #each listEntries }}
<li class="item">
{{ title }}
{{ #if title }}
- i am actually stored!
{{ /if }}
</li>
{{ /each }}
</ul>

Template is looping through users collection when autopublish is removed

I've written code for a website which allows you to login and chat with other users. The root page has a list of the users you can chat to. Here's the code:
<!-- Top level template for the lobby page -->
<template name="lobby_page">
{{> available_user_list}}
</template>
<!-- display a list of users -->
<template name="available_user_list">
<h2 class="cha_heading">Choose someone to chat with:</h2>
<div class="row">
{{#each users}}
{{> available_user}}
{{/each}}
</div>
</template>
<!-- display an individual user -->
<template name="available_user">
<div class="col-md-2">
<div class="user_avatar">
{{#if isMyUser _id}}
<div class="bg-success">
{{> avatar user=this shape="circle"}}
<div class="user_name">{{getUsername _id}} (YOU)</div>
</div>
{{else}}
<a href="/chat/{{_id}}">
{{> avatar user=this shape="circle"}}
<div class="user_name">{{getUsername _id}}</div>
</a>
{{/if}}
</div>
</div>
</template>
and the helper functions:
Template.available_user_list.helpers({
users:function(){
return Meteor.users.find();
}
})
Template.available_user.helpers({
getUsername:function(userId){
user = Meteor.users.findOne({_id:userId});
return user.username;
},
isMyUser:function(userId){
if (userId == Meteor.userId()){
return true;
}
else {
return false;
}
}
})
I've written publish/subscribe code for Chats collection but that's for when you click on one of the users and sends them a message. Now that I've removed autopublish, in the root page, the user can't see any other users to click on. Can someone please help with this issue?
Meteor.users will only publish the current users profile if autopublish is removed.
Add the below publish to your server code:
Meteor.publish(null, function () {
if (!this.userId) return this.ready();
return Meteor.users.find({});
});
A null publish will be auto-published and auto-subscribed by the client if autopublish is removed.
Also, remember to include only those fields that are not sensitive. For, Eg. you might want to omit the password field or the services field.
Something like this:
Meteor.users.find({}, {
fields: {
profile : 1,
emails : 1
}
});

How to access handlebar expression inside the options?

I am new to Handlebar.js and trying to learn it. I have a scenario where I want to insert handlebar expression inside the extra options.
In below sample code I want to set the title of each link based on its text for example "Click to go Google"
This is what I have tried but no one is working:
title="Click to go (this.text)"
title="Click to go this.text"
title="Click to go "+this.text
Data:
var links=[
{text:"Google",url:"http://www.google.com"},
{text:"Yahoo",url:"http://www.yahoo.com"}
];
Sample code:
<script type="x-handlebars-template" id="links">
{{#each this}}
{{link url text title="Click to go (this.text)"}}<br>
{{/each}}
</script>
Complete code:
Links:
<div class="links"></div>
<script type="text/javascript">
Handlebars.registerHelper("link",function(url,text,options){
var attrs=[];
for(var attr in options.hash){
attrs.push(attr+"=\""+options.hash[attr]+"\"");
}
var escapedURL=Handlebars.escapeExpression(url);
return new Handlebars.SafeString('<a href=\"'+escapedURL+'\"'+attrs+'>'+text+'</a>')
});
</script>
<script type="x-handlebars-template" id="links">
{{#each this}}
{{link url text title="Click to go (text)"}}<br>
{{/each}}
</script>
<script type="text/javascript">
var links=[
{text:"Google",url:"http://www.google.com"},
{text:"Yahoo",url:"http://www.yahoo.com"}
];
var template=Handlebars.compile($("#links").html());
$(".links").append(template(links));
</script>
take a look on this answers: Pass JavaScript object/hash to Handlebars helper?
use only options in your helper, add text=title in template and pass text to SafeString.

loading meteor template on click events

So, Basically i'm new to meteor(0.8.2) and trying to create a basic app having two templates(addnewPlace and Map) and a single button. What i need to get is that, when i click on "Add new Place" button, template "addNewPlace" should be loaded in body or else template "Map" should be loaded. Help will be appreciated :)
My html code:
<body>
{{> menu}}
{{> body}}
</body>
<template name="body">
{{#if isTrue}}
{{> addnewPlace}}// tested this template individually, it works.
{{else}}
{{> maps}} // tested this template individually, it works too.
{{/if}}
</template>
<template name="menu">
<h1>Bank Innovation Map</h1>
<input type="button" value="Add new Place">
</template>
My js code:
Template.body.isTrue = true;
Template.menu.events({
'click input': function(){
//load a new template
console.log("You pressed the addNewplace button");//this fn is called properly
Template.body.isTrue = true;
}
});
Well first of all you obviously aren't changing anything in the click event (true before, true after). But also if you did, I think you might be better off using a session variable for this, to maintain reactivity.
Session.setDefault('showAddNewPlace', false)
Template.body.isTrue = function() { Session.get('showAddNewPlace'); }
Template.menu.events({
'click input': function(){
//load a new template
console.log("You pressed the addNewplace button");//this fn is called properly
Session.set('showAddNewPlace', true)
}
});
Meteor 0.8.2 comes in with the dynamic template include feature. Just set a session variable value on click event and you would like to use the template name on the event.
Session.setDefault('myTemplate', 'DefaultTemplateName');
"click input": function (event) {
Session.set("myTemplate", 'template_name');
}
You can now write this:
<body>
{{> menu}}
{{> body}}
</body>
<template name="body">
{{> UI.dynamic template=myTemplate}}
</template>
<template name="menu">
<h1>Bank Innovation Map</h1>
<input type="button" value="Add new Place">
</template>
You may like to take a look at this article for the reference:
https://www.discovermeteor.com/blog/blaze-dynamic-template-includes/

Ember.js using each, get count

Using Ember.js with handlebars, and looping through results like:
{{#each transaction in transactions }}
<p>Transaction: {{ transaction.name }}</p>
{{else}}
<p>No results...</p>
How can I look at the total count of transactions and if greater than 10, add a simple load more:
<p><a {{action loadMoreResults}}>Load more transactions...</a></p>
Implement a custom handlebar helper, something like if_gt
{{#if_gt transactions.length compare="10"}}
<p><a {{action loadMoreResults}}>Load more transactions...</a></p>
{{/if_gt}}
And your Helper will be defined something like this
Handlebars.registerHelper('if_gt', function(context, options) {
if (context > options.hash.compare)
return options.fn(this);
return options.inverse(this);
});
In that case you can try this.. just move the element to outside the loop
{{#if something}}
{{#each transaction in transactions }}
<p>Transaction: {{ transaction.name }}</p>
{{/each}}
{{else}}
<p>No results...</p>
{{/if}}
{{#if_gt total_transactions compare="10"}}
<p>Load more...</p>
{{/if_gt}}

Categories

Resources