I am following an ember-rails tutorial. It's using coffeescript and I'm writing in javascript. Essentially I have a form that when I submit text on it it should place the text below.
My controller looks like this:
Emberapp.ApplicationController = Ember.Controller.extend({
entries: [],
actions: {
addEntry: function(){
this.entries.pushObject name: this.get('newEntryName');
this.set('newEntryName', "");
}
}
});
My template looks like this
<div id = "container">
<h1>Emberails</h1>
{{ input value=newEntryName enter='addEntry' }}
<ul>
{{#each entries}}
<li>{{name}}</li>
{{/each}}
</ul>
</div>
When I reload the page I get an error stating that 'name: this.get('newEntryName');' is an Unexpected identifier. I've been checking for the syntax rules online but I'm not sure if it is a coffeescript to javascript error or something else.
this.entries.pushObject name: this.get('newEntryName');`
is not valid JS. You want do do
this.entries.pushObject({name: this.get('newEntryName')});
Controller,
Emberapp.ApplicationController = Ember.Controller.extend({
newEntryName: '',
entries: [],
actions: {
addEntry: function(){
this.get('entries').pushObject({name: this.get('newEntryName')});
this.set('newEntryName', "");
}
}
});
in hbs,
<div id = "container">
<h1>Emberails</h1>
{{ input value=newEntryName enter='addEntry' }}
<ul>
{{#each entries as |value|}}
<li>{{value.name}}</li>
{{/each}}
</ul>
</div>
Like Lux suggested consider ember-cli and read http://guides.emberjs.com
Related
I have a custom user field that get populated by the user on click of a button with an id of an item from another collection, however when i return it, i get a single list of the items in one html tag, instead of returning each saved item in its own tag with the result looking like this
i.e its like this
<p>CategoryPublication-98,CategoryPublication-2,CategoryPublication-57<p>
when it should be like this
<p>CategoryPublication-98</p>
<p>CategoryPublication-2</p>
<p>CategoryPublication-57</p>
this is my publish
Meteor.publish(null, function() {
return Meteor.users.find({_id:{$in:fields.name}}).fetch();
});
my html
<template name="userTimeline">
{{#if currentUser}}
<div class="timeline-user">
{{#each name}}
<p>{{name}}</p>
{{/each}}
</div>
{{/if}}
</template>
my helper
Template.userTimeline.helpers({
name: function() {
return Meteor.user().name;
}
});
my insert
Template.CategoriesMain.events({
'click .toggle-category': function(e){
var ob = this._id;
var id = $.makeArray( ob );
console.log(id);
e.preventDefault();
Meteor.call('addingCategory', id, function(error, user){ console.log(id)});
},
});
My methods
Meteor.methods({
addingCategory: function(name) {
console.log(Meteor.userId());
Meteor.users.update({
_id: Meteor.userId()
},
{
$addToSet: {
name: name
}
});
}
});
Where you have:
{{#each name}}
<p>{{name}}</p>
{{/each}}
There's ambiguity about the value of name in the inner <p></p>. Since you're just returning an array of strings instead of objects there is no name key in the array.
Instead do:
{{#each name}}
<p>{{this}}</p>
{{/each}}
This question already has answers here:
How do I check if an array includes a value in JavaScript?
(60 answers)
Closed 7 years ago.
I have two collections:
Group = {
users: [Array_of_User]
}
User = {
name: _string_
}
I'm listing groups ans I'm trying to know in the template if a user is in the groups:
mytemplate.js
Template.mytemplate.helpers({
groups: function(){
return Groups.find();
},
currentUsername: 'test'
});
mytemplate.html
<template name="main">
<ul>
{{#each groups}}
<li>
{{#if [the group contains currentUsername] }}
contains
{{else}}
doesn't contain
{{/if}}
</li>
{{/each}}
</ul>
</template>
The question is: what can I put on the helpers and instead of [the group contains currentUsername] to make it work?
Also, I'm not saying this is the way to do it. I'm open to any suggestions even if it means I have to change a lot.
You could use the Underscore.js function _.findWhere(list, properties) to check whether the group contains the username:
if (Meteor.isClient) {
Template.main.helpers({
groups: function() {
return Groups.find();
},
currentUsername: 'Matthias',
isInGroup: function(username) {
return !!_.findWhere(this.users, {
name: username
});
}
});
}
<template name="main">
<ul>
{{#each groups}}
<li>
{{#if isInGroup currentUsername}}
contains
{{else}}
doesn't contain
{{/if}}
</li>
{{/each}}
</ul>
</template>
if (Meteor.isServer) {
Meteor.startup(function() {
Groups.insert({
users: [{
name: "Matthias"
}, {
name: "Angie"
}]
});
});
}
Here is a MeteorPad.
Within your each block, your data context becomes the current group that is being iterated over. Therefore you can write a helper method that references that current data context like this:
userInGroup: function(username) {
var userInGroup;
this.forEach(function(groupUsername) {
if (username == groupUsername) {
userInGroup = true;
}
};
return userInGroup;
}
'this' within the userInGroup template helper references the current group as long as you use the helper within an a group iteration.
You can then use the helper like this:
<template name="main">
<ul>
{{#each groups}}
<li>
{{#if userInGroup currentUsername}}
contains
{{else}}
doesn't contain
{{/if}}
</li>
{{/each}}
</ul>
</template>
I try to integrate rubaxa:sortable to make my list sortable.
client/helpers.js
Template.getElements.helpers({
children: function() {
return Articles.find({ parent: this._id }, {sort: {order: 1}});
}
});
server/publications.js
Meteor.publish('articles', function() { return Articles.find({}, {sort: {slug: 1}}); });
Sortable.collections = 'articles';
template
<template name="getElements">
<ul class="sortable">
{{#each children}}
{{#sortable items=Articles sortField="order"}}
<li data-id="{{_id}}"><input type="text" name="keyword" value="{{title}}"></li>
{{/sortable}}
{{/each}}
</ul>
</template>
In the documentation (https://atmospherejs.com/rubaxa/sortable) I see the info:
Client:
{{#sortable items=<collection|cursor|array> sortField="order"}}
Server:
Sortable.collections = <collectionName>; // the name, not the variable
So what am I doing wrong? Right now no list-element is beeing shown.
I'm not an expert but based on integration this will fix your issues.
Server JS
Update the declaration to include the collation name in [].
Sortable.collections = ['articles'];
HTML Template
remove the following:
{{#each children}}
{{/each}}
Regards,
Vince
I am creating a dynamic form using json and trying to use jquery-validation plugin to add validation rules to input fields.
Json structure and helper method is :
var fields = [{
label: "Name",
type: {name: 'STRING'},
validationRules: {
required: true,
maxlength: 100,
minlength: 3
}
},{
label: "Currency",
type: {name: 'CHECKBOX'},
defaultValue: ['USD', 'INR'],
validationRules: {
required: true
},
sourceCollection: 'oNLFfi4L3zgNLhScv',
}] ;
Template.eventCreate.helpers({
fields: function(){
console.log("calling fields");
fields.forEach(function(field, index){
field.sourceCollectionData = StaticLists.find({_id: field.sourceCollection});
});
return fields;
}
});
Template looks like:
<template name="eventCreate">
<form id="newEventForm" class="form-horizontal">
{{#each fields}}
<div class="form-group">
<label class="col-xs-2 control-label">{{label}}</label>
<div class="col-xs-6">
{{#if equals type.name 'STRING'}}
<input name="{{label}}" id="{{label}}" class="form-control" placeholder="Enter {{label}}" value="{{defaultValue}}" />
{{/if}}
{{#if equals type.name 'CHECKBOX'}}
{{#each sourceCollectionData}}
{{#if isActive}}
<div class="col-xs-2 checkbox">
<label class="checkbox-inline">
<input type="checkbox" name="{{../label}}" id="{{../label}}" value="{{name}}" {{checked ../defaultValue}}> {{name}}
</label>
</div>
{{/if}}
{{/each}}
{{/if}}
</div>
</div>
{{/each}}
</form>
</template>
Now I am trying to add validation rule in rendered method:
Template.eventCreate.rendered = function(){
$('#newEventForm').validate({
....
});
fields.forEach(function(field, index){
if(field.validationRules){
$('#'+field.label).rules('add', field.validationRules);
}
});
}
It works in case of input text but throws exception for checkbox because checkbox DOM is still not laid out and there is no element with id "Currency".
I assume in meteor blaze rendered is called once only when DOM rendering is complete. Though it is called once here but before DOM rendering completes.
EDIT
Earlier I was hardcoding the JSON in js file itself and now I am retrieving it from mongo.
But its seems that rendered callback is invoked only first time and not invoked every time mongo collection changes(which in turn updates the DOM)
Template.eventCreate.helpers({
fields: function(){
var template = EventTemplate.findOne({name: 'Job Template'});
console.log("template", template);
if(template){
Session.set("template", template);
template.fields.forEach(function(field, index){
field.sourceCollectionData = StaticLists.find({_id: field.sourceCollection});
});
return template.fields;
}
}
});
Template.eventCreate.rendered = function(){
$('#newEventForm').validate({
...
...
console.log("rendering main template");
addValidationRules(Session.get('template'));
}
Now the console output is something like:
template undefined event_create.js?bfeba9389401dac358bc313bd9d4205818e356a1:52
rendering main template event_create.js?bfeba9389401dac358bc313bd9d4205818e356a1:98
template Object {_id: "iFDndmjavtFN8AdGQ", name: "Job Template", description: "Job Template", fields: Array[13]}
which shows that (and I tried it even with a break point in js script) that just when script loads template is undefined and no input field is rendered on front end but rendered callback is invoked. Now later when template gets populated with data, input fields are rendered but callback is not invoked again.
The recommended pattern is to put the contents of your {{#each}} blocks in separate templates and tap into the rendered event of those templates.
By the way, Meteor.defer is no longer required.
Lets say I have the following JSON and handlebars.js template :
JSON
{
rootPath: '/some/path/',
items:[ {
title: 'Hello World',
href: 'hello-world'
}, {
title: 'About',
href: 'about'
}, {
title: 'Latest News',
href: 'latest-news'
}
}
Template
<script id="test-template" type="text/x-handlebars-template">
<ul class="nav">
{{#each items}}
<li>{{title}}</li>
{{/each}}
</ul>
</script>
The template above works, until I want to filter items - lets say to have 2 lists one odd and the other even, here's a simple template for odd :
<script id="test-template" type="text/x-handlebars-template">
<ul class="nav">
{{#each items}}
{{#isOdd #index}}
<li>{{title}}</li>
{{/isOdd}}
{{/each}}
</ul>
</script>
And the registered helper :
// isOdd, helper to identify Odd items
Handlebars.registerHelper('isOdd', function (rawValue, options) {
if (+rawValue % 2) {
return options.fn(this);
} else {
return options.inverse(this);
}
});
The helpers work as expected and only the Odd items are rendered, however the reference to the parent context becomes lost, so the {{../rootPath}} directive ~~fails to render~~ renders an empty value.
Is there a way to pass the Parent context through the block Helper?
Change this:
<a href="{{../rootPath}}{{href}}">
to this:
<a href="{{../../rootPath}}{{href}}">
Why? because the if statement is in an inner context so first you need to go up a level and that's why you have to add ../
See more details in:
https://github.com/wycats/handlebars.js/issues/196