show element in template if owner meteor js - javascript

I am writing a messaging app which has a delete / edit function for a user for a given message that is submitted. What I would like to do is write something like:
{{#if currentUser._id === this._id}}
<!-- Show -->
{{/if}}
But this is probably wrong I have a template written for the message record:
<template name="message">
<div class="row message-row">
<div class="col-md-12">
<div class="message-container">
<div class="message-avatar">
<img src="{{userAvatar}}">
</div>
<p>{{message}}</p>
<div class="message-time">{{prettifyDate time}}</div>
<!-- this is the div to hide / show based on the conditional -->
<div class="message-controls">
<button class="btn btn-link btn-xs" type="button" id="deleteMessage"><i class="fa fa-trash-o"></i></button>
<button class="btn btn-link btn-xs" type="button" id="editMessage"><i class="fa fa-edit"></i></button>
</div>
<!-- end -->
</div>
</div>
</div>
</template>
And I am using the following in my client.js
Template.messages.messages = function() {
return Messages.find({}, { sort: {time: -1} });
}
But at this point I am stuck

Assuming your message documents have a userId field, you can simply do this:
Template.message.helpers({
isOwner: function() {
return this.userId === Meteor.userId();
}
});
and:
{{#if isOwner}}
<!-- controls -->
{{/if}}
You could also make a more flexible, reusable global helper for this:
Template.registerHelper('isCurrentUser', function(userId) {
return userId === Meteor.userId();
});
<!-- in this example, the document might have an `ownerId` field rather than `userId` -->
{{#if isCurrentUser ownerId}}{{/if}}
Of course, you also need to validate the updates on the server with the allow/deny API or with custom methods.

Related

Where does template.data of Blaze form go after first submit?

I use {{> ArticleForm}} for create and update Articles in arabic-russian dictionary. I use blaze and ReactiveDict in my templates, after some problems with Autoform plugin.
First I was using it for update Article and everything works good. Now I added same form for create Article. I placed {{ > ArticleForm}} to {{> Header}} component, inside bootstrap modal, and call it by "+Add" button in top menu. It opens my form. First insert of Article works good. In DB there is new article, and even I redirected to new article. But at second call, template.data is empty and form is not interactive, it fires errors, because after update any field, ArticleForm should write ReactiveDict from template.data, but it doesn't exist. I can't understand, where goes template.data after firs successful insertion.... Please answer if someone knows...
Here is how it looks:
Here is data context of my form :
Template.ArticleForm.helpers({
article() {
console.log("helper-article");
if (!this.words) this.words = [{ note: "", word: "" }];
if (!this.translations) this.translations = [{ translation: "" }];
if (!this.synonyms) this.synonyms = [];
if (!this.roots) this.roots = [];
if (!this.subjects) this.subjects = [];
//newWords, newTranslations - это добавление имен к элементам формы,
//по которым можно будет отслеживать все изменения в форме
let newWords = this.words.map((elem, index) => {
return { note: elem.note, word: elem.word, wordId: `words.${index}` };
});
let newTranslations = this.translations
? this.translations.map((elem, index) => {
return {
translation: elem.translation,
translationId: `translations.${index}.translation`,
examples: elem.examples
? elem.examples.map((elem2, index2) => {
return {
example: elem2.example,
translation: elem2.translation,
exampleId: `translations.${index}.examples.${index2}`
};
})
: []
};
})
: [];
this.words = newWords;
this.translations = newTranslations;
this.picture = Session.get("picture");
Template.instance().reactiveForm.set("article", this);
const article = Template.instance().reactiveForm.get("article");
return article;
},
deleted() {
return this.deleted ? "checked" : "";
},
showMiddleHarakat(speachPart, index) {
return speachPart == "глагол, I порода" && index == 0;
},
picture() {
return Session.get("picture");
}
});
Here is my template {{> ArticleForm}}
<template name="ArticleForm">
<form id="articleForm-{{_id}}" class="panel panel-default article {{#if notPublished}}-opacity-06{{/if}}">
<div class="panel-heading">
<div class="panel-title words">
<div class="label label-info speach-part">{{speachPart}}</div><br />
<!-- Глагол 1й породы имеет дополнительную информацию для вывода, поэтому
особый шаблон его вывода, например, среднекорневую глассную и масдары -->
{{#each article.words}}
<div class="wordEdit editField" id="{{wordId}}">
<i class="glyphicon glyphicon-remove remove-word -remove" id="remove.{{wordId}}"></i>
<input type="text" placeholder="прим." value="{{note}}" name="{{wordId}}.note" class="form-control note">
<input type="text" placeholder="слово" value="{{word}}" name="{{wordId}}.word" class="form-control word -arabic-text-mid">
</div>
{{#if showMiddleHarakat ../speachPart #index}}
<div class="note middleHarakat" title="среднекорневая гласная настоящего времени">
<input type="text" placeholder="скгнв" value="{{../middleHarakat}}" name="middleHarakat" class="form-control note">
</div>
{{/if}}
{{/each}}
<div class="add-word">
<i class="glyphicon glyphicon-plus"></i>
</div>
</div>
</div>
<div class="panel-body">
<div class="translations">
{{#each article.translations}}
<div class="translation">
<div class="editField editTranslation" id="{{translationId}}">
<input type="text" name="{{translationId}}" value="{{translation}}" class="form-control" placeholder="перевод">
<i class="glyphicon glyphicon-remove remove-translation -remove" id="remove.{{translationId}}"></i>
</div>
<div class="examples examples-form-{{../_id}}-{{#index}}">
{{#each examples}}
<div class="exampleEdit editField" id="{{exampleId}}">
<input type="text" placeholder="пример" value="{{example}}" name="{{exampleId}}.example" class="form-control example -arabic-text-mid">
<input type="text" placeholder="перевод примера" value="{{translation}}" name="{{exampleId}}.translation" class="form-control translation">
<i class="glyphicon glyphicon-remove remove-example -remove" id="remove.{{exampleId}}"></i>
</div>
{{/each}}
<button class="btn btn-default btn-xs add-example" id="addExampleFor.{{translationId}}">
<i class="glyphicon glyphicon-plus"></i>Пример
</button>
</div>
</div>
{{/each}}
<button class="btn btn-default btn-sm add-translation">
<i class="glyphicon glyphicon-plus"></i>Перевод
</button>
</div>
{{> TagsSubjects}}
{{> TagsSynonyms}}
{{> TagsRoots}}
<!--
<div class="uploadImage">
{{> uploadForm}}
picture: {{picture}}
</div>
-->
</div>
<div class="panel-footer">
<button class="btn btn-primary article-save">Сохранить</button>
<button class="btn btn-default article-edit-cancel">Отмена</button>
</div>
</form>
</template>
This could be because you are not clearing the form template properly when the modal closes? Remember the modal is just hidden, the template is not removed.
I came across a similar issue when adding AutoForm support to my boostrap modal package.

Check if json array is empty at store vuex

I want to show a button if my array of object has some data, so basilcy in my store(vuex) i defined a array like this:
state: {
document: []
},
i append data to this array from other components and i already checked that the data is appending right, no problem here.
So i want to show the button just if there is some data:
<div class="row margin-above">
<div class="panel panel-primary" v-for="section in this.$store.getters.getDocument">
<div class="panel-body quote" >
<p>{{section.key}}</p>
</div>
</div>
<div v-if="this.$store.getters.getDocument != '[]'">
<button class="btn btn-success btn-block">Create Document</button>
</div>
</div>
there is the button, i want to hide the whole div with the button if the condition matches, but it is not working the button is always there, any help?
Check its length property.
<div v-if="this.$store.getters.getDocument.length != 0">
<button class="btn btn-success btn-block">Create Document</button>
</div>
Or assign the vuex variable to null when there are no elements. Than this should work.
<div v-if="this.$store.getters.getDocument">
<button class="btn btn-success btn-block">Create Document</button>
</div>
In your store did u define the getter "getDocument", if so add a computed property in your component, it much cleaner and more reusable then referencing the store getters in the template directly:
computed : {
document: function() {
return this.$store.getters.getDocument;
}
}
in the template:
<div v-if="document.length">
<button class="btn btn-success btn-block">Create Document</button>
</div>

How to access current row data in angular-datatables using templates?

I am using angular-datatables. There is a column Actions which I render using an inline template. I want to access current row data in that template. How do that?
controller
$scope.dtOptions = DTOptionsBuilder.newOptions().withOption('ajax', {
url: '/api/department',
type: 'GET'
})
.withDataProp('data')
.withOption('processing', true)
.withOption('serverSide', true)
.withPaginationType('full_numbers')
.withOption('createdRow', function (row, data, dataIndex) {
return $timeout(function() {
// Recompiling so we can bind Angular directive to the DT
return $scope.$apply($compile(angular.element(row).contents())($scope));
});
})
.withBootstrap();
$scope.dtColumns = [
DTColumnBuilder.newColumn('id').withTitle('ID'),
DTColumnBuilder.newColumn('name').withTitle('Name'),
DTColumnBuilder.newColumn('actions').withTitle('Actions').withOption("searchable", false)
];
view
<div class="hbox hbox-auto-xs hbox-auto-sm" ng-controller="DepartmentsController">
<!-- Inline Template -->
<script type="text/ng-template" id="actions.html">
<button class="btn btn-primary btn-xs"
ng-click="edit(/** CURRENT ROW ELEMENT ID */)"><i class="fa fa-edit"></i> Edit</button>
<button class="btn btn-danger btn-xs"
ng-click="delete()"><i class="fa fa-trash"></i> Delete</button>
</script>
<div class="bg-light lter b-b wrapper-md">
<h1 class="m-n font-thin h3">Departments</h1>
</div>
<div class="wrapper-md">
<div class="panel panel-default">
<div class="panel-body">
<div class="row">
<div class="col-xs-6">
<button class="btn m-b-md btn-md btn-primary " ui-sref="manager.departments.create">
<i class="fa fa-plus"></i> <span class="hidden-sm hidden-xs">Add Department</span></button>
</div>
</div>
<div class="row">
<div class="col-sm-12 m-b-xs">
<table datatable="" dt-options="dtOptions" dt-columns="dtColumns" class="table table-striped b-t b-b">
<thead>
<tr>
<th style="width:20%">ID</th>
<th style="width:60%">Name</th>
<th style="width:20%">Actions</th>
</tr>
</thead>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
Here is plunkr to help you: http://plnkr.co/edit/iAZBof7g6cp68RnM0X8H?p=preview
After hours of struggle, I found the solution. It's quite obvious when you see it.
I created a new scope and added data to it before passing it to $compile in createRow callback. Creating a new scope is necessary to pass unique data to each row. If you simply passed by $scope.row then each row will have the same row equal to the last row processed.
controller
.withOption('createdRow', function (row, data, dataIndex) {
// Create a new scope for each row, otherwise, data will
// not be unique for each row becuase of data bindings
var $newScope = $scope.$new(true);
$newScope.row = data;
// Pass any methods you are using in current scope
$newScope.delete = $scope.delete;
return $timeout(function() {
// Recompiling so we can bind Angular directive to the DT
return $scope.$apply($compile(angular.element(row).contents())($newScope));
});
});
view
<script type="text/ng-template" id="actions.html">
<button class="btn btn-primary btn-xs" ui-sref="manager.departments.edit({id: {{ row.id }} } )"><i class="fa fa-edit"></i> Edit</button>
<button class="btn btn-danger btn-xs" ng-bootbox-confirm="Are you sure you want to delete this department?" ng-bootbox-confirm-action="delete(row.id)"><i class="fa fa-trash"></i> Delete</button>
</script>
I used the above accepted answer, and it worked fine. However, later when we moved to production and the rows per page changed from 20 to 500, I saw significant performance issues through chrome developer tools (Most time spent on hundreds of setTimer and listener events)
I found the official document here which gives us an example as below:
.withOption('createdRow', createdRow);
// ...
function createdRow(row, data, dataIndex) {
// Recompiling so we can bind Angular directive to the DT
$compile(angular.element(row).contents())($scope);
}
This piece of code does not use the $timeout or $apply functions, but still works well. If you run into performance issues as I did, this may help.

Meteor template not updating on changed data

I'm currently building a nifty little 'talent point distributor' view, similar to what popular RPG games offer. I didn't want a huge wall of HTML code for all the buttons and textboxes, so I created a template to which I pass two parameters:
the name of the stat I want to alter
the initial value of the stat
The template renders correctly, and I notice that when I log the results to the console, the variable seems to be changed correctly. However, the displayed value does not change and will always stay at 0.
Here is the template itself:
<template name="attributeStepper">
<div class="row" style="margin: 1em;">
<div class="col-sm-3 col-md-2">
<h4>{{toUpper attribute}}</h4>
</div>
<div class="col-sm-6 col-md-4">
<div class="btn-group" role="group">
<button type="button" class="btn btn-default btn-value-dec">
<span class="glyphicon glyphicon-chevron-down"></span>
</button>
<button type="button" class="btn btn-default disabled">{{attributeValue}}</button>
<button type="button" class="btn btn-default btn-value-inc">
<span class="glyphicon glyphicon-chevron-up"></span>
</button>
</div>
</div>
</div>
</template>
Here is the helper I defined for the template:
Template.attributeStepper.helpers({
toUpper : function(str) {
return str.substring(0, 1).toUpperCase() + str.substring(1);
}
})
Template.attributeStepper.events({
'click .btn-value-inc' : function(event, tmpl) {
tmpl.data.attributeValue ++;
},
'click .btn-value-dec' : function(event, tmpl) {
tmpl.data.attributeValue --;
}
});
And this is how I call the templates from the actual view:
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Attributes</h3>
</div>
{{ >attributeStepper attribute="strength" attributeValue="0"}}
{{ >attributeStepper attribute="courage" attributeValue="0"}}
{{ >attributeStepper attribute="intelligence" attributeValue="0"}}
{{ >attributeStepper attribute="agility" attributeValue="0"}}
{{ >attributeStepper attribute="dexterity" attributeValue="0"}}
{{ >attributeStepper attribute="intuition" attributeValue="0"}}
{{ >attributeStepper attribute="charisma" attributeValue="0"}}
</div>
I hope you can make any sense out of this and tell me what I'm doing wrong, because I feel like I'm not following the mindset behind Meteor correctly yet.
Cheers!
There is nothing wrong but also nothing reactive in your code. For the attributeValue you should use a template based ReactiveVar which is created at the onCreate Event
Template.attributeStepper.onCreated(function() {
if (! _.isUndefined(this.data.startingValue))
this.attributeValue = new ReactiveVar(Number(this.data.startingValue));
else
this.attributeValue = new ReactiveVar(0);
})
You can use some initialValue from Template as you like
See complete example at the MeteorPad I created for you.
http://meteorpad.com/pad/Zw7YnnW57uuGKcu3Q/MultipleTemplateUsage
This should solve your question
Cheers
Tom
Do you have idea about reactive-var in meteor (Meteor Doc) or you can also use Session instead of reactive-var (ReactiveVar is similar to a Session variable)
Have a look at changes as per your code.
Here is the template(.html)
<template name="attributeStepper">
<div class="row" style="margin: 1em;">
<div class="col-sm-3 col-md-2">
<h4>{{toUpper attribute}}</h4>
</div>
<div class="col-sm-6 col-md-4">
<div class="btn-group" role="group">
<button type="button" class="btn btn-default btn-value-dec">
<span class="glyphicon glyphicon-chevron-down"></span>
</button>
<button type="button" class="btn btn-default disabled">{{getAttributeValue}}</button>
<button type="button" class="btn btn-default btn-value-inc">
<span class="glyphicon glyphicon-chevron-up"></span>
</button>
</div>
</div>
</div>
</template>
Here is helpers for your template(.js)
Template.attributeStepper.created = function(){
this.attributeValue = new ReactiveVar(parseInt(this.data.attributeValue));
}
Template.attributeStepper.helpers({
toUpper : function(str) {
return str.substring(0, 1).toUpperCase() + str.substring(1);
},
getAttributeValue : function(){
return Template.instance().attributeValue.get();
}
});
Template.attributeStepper.events({
'click .btn-value-inc' : function(event, tmpl) {
tmpl.attributeValue.set(tmpl.attributeValue.get()+1)
},
'click .btn-value-dec' : function(event, tmpl) {
tmpl.attributeValue.set(tmpl.attributeValue.get()-1)
}
});
Template.attributeStepper.created = function(){...} method called before your template's logic is evaluated for the first time.

Javascript toggle hide and show buttons in a loop Laravel 5

I am writing a Laravel 5 project with a comment section code below
#foreach($Comment as $Comment)
<div id="comment-{!! $Comment->comments_id !!}" class="comment-wrapper">
<div class="btn btn-lg btn-info btn-xs" class="show">Show</div>
<div class="btn btn-lg btn-success btn-xs" class="hide">Hide</div>
<div class="btn btn-lg btn-warning btn-xs" class="toggle">Toggle</div>
<div class="watch" class="jumbotron alert-info">
<ul class="list-group">
<li class="list-group-item list-group-item-success">{!! $Comment->author !!}</li>
<li class="list-group-item"> {!! $Comment->text !!}</li>
</ul>
#if ($Comment->author == Auth::user()->name)
<p>Delete</p>
#endif
<h6><small>CREATED ON: {!! $Comment->created_at !!}</small></h6>
</div>
</div>
#endforeach
and I have a javascript file which looks like this
$(document).ready(function () {
$('.show').click(function () {
$(this).closest('.comment-parent').find('.watch').show('slow');
});
$('.hide').click(function () {
$(this).closest('.comment-parent').find('.watch').hide('slow');
});
$('.toggle').click(function () {
$(this).closest('.comment-parent').find('.watch').toggle('slow');
});
});
The trouble is the toggle/hide javascript function only works on one set of buttons and hides all of the comments. I want to have the set of buttons that work for each comment individually. I've tried to increment the watch class and buttons div id by adding 1 and incrementing it for each comment but can't get it to work. Any help would be appreciated thanks.
You may try something like this:
$('#show').click(function () {
$(this).next('.watch').show('slow');
});
Try same approach for other methods, so only the next first div with class of watch will be acted and also, you could have wrapped each set in a single parent container using a unique id attribute in addition to a class, for better grouping. For example:
#foreach($Comment as $Comment)
<div id="comment-{{$comment->id}}" class="comment-wrapper">
<div class="btn btn-lg btn-info btn-xs show">Show</div>
<!-- More... -->
<div class="watch" class="jumbotron alert-info">
<!-- More... -->
</div>
</div>
#endforeach
This way, you could have done the jQuery slecting more specifically, for example:
$('#show').click(function () {
$(this).closest('.comment-parent').find('.watch').show('slow');
});
Update (Thanks to haakym for pointing me that): Also, an id must be unique so instead of using id='show' use it as a class and then use:
$('.show').click(function () {
$(this).closest('.comment-parent').find('.watch').show('slow');
});

Categories

Resources