I am using package aslagle:reactive-table
I want to pass an argument to the collection option of the reactive table
I have checked this also Meteor Reactive Table Helper Arguments but the comments on the post didn't help.
Html Code:
{{#each staffCode}}
{{> reactiveTable collection=collectionDetails settings=settingsResult}}
{{/each}}
Helper:
collectionDetails: function(staffCode){
return someCollection.find({staff_code: staffCode});
},
settingsResult: function(){
return {
rowsPerPage: 20,
showFilter: false,
showNavigation: 'auto',
fields: [
{
key: 'some_key', label: 'Some Label' ,
}
]
}
}
So far I tried putting
{{#each staffCode}}
{{> reactiveTable collection=collectionDetails ../code settings=settingsResult}}
{{/each}}
But this doesn't work and gives the following error in the terminal
Can't have a non-keyword argument after a keyword argument
Those who have the same issue, I have solved the problem, here's the way I approached it.
{{#each staffCode}}
{{#with collectionDetails code}}
{{> reactiveTable collection=this settings=settingsResult}}
{{/with}}
{{/each}}
Related
So, I have an object like this:
object = {
"group_1": [
{
"name": "Foo"
}
],
"group_2": [
{
"name": "Bar"
}
]
}
And in my hbs view I'm doing like this:
{{#each group_1}}
<p>{{name}}</p>
{{/each}}
{{#each group_2}}
<p>{{name}}</p>
{{/each}}
Is there any way of concatenating both and not repeating code? The solution would be something like this:
{{#each group_1 + group_2}}
<p>{{name}}</p>
{{/each}}
Any idea how to do this?
Handlebars itself does not support this.
But you can still do:
object.groups = object.group_1.concat(object.group_2);
{{#each groups}}
<p>{{name}}</p>
{{/each}}
Which seems to be a straightforward solution.
Alternatively you can put both your groups into an object and iterate over it like this:
let object = {
groups: {
'group_1': [
{
'name': 'Foo'
}
],
'group_2': [
{
'name': 'Bar'
}
]
}
};
{{#each groups}}
{{!-- you can refference group name as #key here --}}
{{#each this}}
{{name}}
{{/each}}
{{/each}}
I'd like to create a template in Meteor that has a Tracker.autorun which exclusively runs when part of a document changes --- but not when other parts of the document change.
So here is sample code using a minimongo collection and template.autorun
parent.html
{{#each items}}
{{> child}}
{{/each}}
child.html
<div>{{title}}</div>
<p>{{description}}</p>
Minimongo Collection
LocalProject.findOne() output:
"items": [
{
"title": "hi",
"description": "test"
},
{
"title": "hi 2",
"description": "test 2"
},
],
"otherstuff:{//etc}
child.js
Template.child.onRendered(function(){
this.autorun(function() {
var data = Template.currentData();
doSomething(data.title,data.description)
});
});
addnewitem.js
LocalProject.update(currentEditingProjectID,{ $push: { 'items': newItem }},function(error,result){
if(error){console.log(error)}
});
The problem is, whenever I run addnewitem.js, all of my Template.child autoruns execute even though their reactive data source (Template.currentData()) has not changed unless it was the specific item I updated. Similarly if I want to update an existing item, not just add a new one to the array, all of the autoruns for each item get executed.
So is there a way, using this model, to create a dependency for autorun that is reactively granular to specific portions of a document?
I don't think the way to go is by using an autorun. I would either set up individual reactive dependencies on each item, or use observe/observeChange.
First idea
parent.html:
{{#each items}}
{{> child}}
{{/each}}
parent.js:
Template.parent.helpers({
// Returns only item ids
items: function() {
return Items.find({}, { fields: { _id: 1 } });
}
});
child.html:
{{#each items}}
{{#with item=getItem}}
<div>{{item.title}}</div>
<p>{{item.description}}</p>
{{/with}}
{{/each}}
child.js:
Template.child.helpers({
getItem: function() {
// Get the item and set up a reactive dependency on this particular item
var item = Items.find(this._id);
// After item has been displayed, do something with the dom
Tracker.afterFlush(function () {
doSomething(item.title, item.description);
});
return item;
}
});
Second idea
parent.html:
{{#each items}}
{{> child}}
{{/each}}
parent.js:
function do(item) {
Tracker.afterFlush(function () {
doSomething(item.title, item.description);
});
}
Template.parent.onCreated({
this.items = Items.find({});
this.handle = this.items.observe({
added: function(item) { do(item); },
changed: function(oldItem, newItem) { do(newItem); },
});
});
Template.parent.onDestroyed({
this.handle.stop();
});
Template.parent.helpers({
items: function() {
return Template.instance().items;
}
});
child.html:
{{#each items}}
<div>{{title}}</div>
<p>{{description}}</p>
{{/each}}
There's a tool just for this - 3stack:embox-value provides reactive isolation, and value caching.
Using your example, you could isolate changes to title/description like so:
first up, add the packages
meteor add 3stack:embox-value
meteor add ejson
Then, update your code:
Template.child.onRendered(function(){
// creates a reactive data source, that only triggers "changes"
// when the output of the function changes.
var isolatedData = this.emboxValue(function(){
var data = Template.currentData();
return {title: data.title, description: data.description}
}, {equals: EJSON.equals})
this.autorun(function() {
// This autorun will only execute when title or description changes.
var data = isolatedData()
doSomething(data.title,data.description)
});
});
I am currently trying to have 3 separate templates that the user can switch between by clicking on one of 3 buttons. By using a session variable ('currentContent'), 3 buttons and 3 templates I cannot see what's going wrong with my current code.
In my javascript:
Template.priority.helpers({
expensesbtn:function(){
return Session.get('currentContent') ==='expenses'?true:false;
},
custombtn:function(){
return Session.get('currentContent') ==='cexpenses'?true:false;
},
incomebtn:function(){
return Session.get('currentContent') ==='earning'?true:false;
},
});
Template.priority.events({
"click #expensesbtn":function(event, template){
Session.set('currentContent', 'expenses')
},
"click #custombtn":function(event, template){
Session.set('currentContent', 'cexpenses')
},
"click #incomebtn":function(event, template){
Session.set('currentContent', 'earning')
}
});
and then in my html:
{{>priority}}
{{#if cexpenses}}
{{> cexpenses}}
{{/if}}
{{#if expenses}}
{{> expenses}}
{{/if}}
{{#if earning}}
{{> earning}}
{{/if}}
Any help with this would be greatly appreciated. Thanks!
#Sindis is right, your helper names must match what you are calling in your templates. But another problem is that while the conditionals aren't inside a template named priority, your helpers are attached to the priority template, so they wouldn't be recognized even if the names match. You can fix this by putting everything inside the priority template and separating the buttons out into a separate sub-template if that is your intention.
You can also make your code much more elegant and DRY by using only one session variable chosenTemplate and only one helper and avoiding repeating all those conditionals. Then use Meteor's Template.dynamic feature to display the correct template. Here is an example solution below. Make a new template called templateControl and place the buttons inside it. Then place everything inside the priority template.
<template name="priority">
{{> templateControl }}
{{> Template.dynamic template=chosenTemplate }}
</template>
<template name="templateControl">
{{#each buttons}}
<button id="{{ id }}" class="chose-template">{{ label }}</button>
{{/each}}
</template>
Template.templateControl.helpers
buttons: [
{ id: 'incomebtn', label: 'Income' },
{ id: 'expensesbtn', label: 'Expenses' },
{ id: 'custombtn', label: 'Custom' }
]
Template.templateControl.events
'click .chose-template': function(e, t) {
Session.set('chosenTemplate', this.id);
}
Template.priority.helpers
chosenTemplate: function(e, t) {
return Session.get('chosenTemplate');
}
Then be sure to give the three templates you switch between names corresponding to the template ids set in the chosenTemplate Session variable!
Hope this helps.
Your helpers have to be the same when you use them in HTML, so your js should look like:
Template.priority.helpers({
expenses: function(){
return Session.get('currentContent') === 'expenses';
},
cexpenses: function(){
return Session.get('currentContent') === 'cexpenses';
},
earning: function(){
return Session.get('currentContent') === 'earning';
}
});
I've been trying making a new library app based on the code-school ember tutorial (books instead products... not too complicated).
I'm using the latest ember.js stable release, 1.1.10.
using the {{#each}} in my templates,
js:
App.BooksRoute = Ember.Route.extend({
model: function () {
return this.store.findAll('book');
}
});
html:
{{#each}}
<h1>{{title}}</h1>
{{/each}}
the following warning is shown in the console
DEPRECATION: Using the context switching form of {{each}} is deprecated. Please use the keyword form (`{{#each foo in bar}}`)
So I've been trying to use the recommended syntax and I've found this, which is working
html:
{{#each book in model}}
<h1>{{book.title}}</h1>
{{/each}}
But when it comes the time to try the sortProperties in my arrayController, with my {{#each book in model}}
js:
App.BooksRoute = Ember.Route.extend({
model: function () {
return this.store.findAll('book');
}
});
App.BooksController = Ember.ArrayController.extend({
sortProperties: ['title']
});
html:
{{#each book in model}}
<h1>{{book.title}}</h1>
{{/each}}
my books are not sorted...
I've found another workaround, building a property inside my ArrayController:
js:
App.BooksRoute = Ember.Route.extend({
model: function () {
return this.store.findAll('book');
}
});
App.BooksController = Ember.ArrayController.extend({
books: function(){
return this;
}.property(),
sortProperties: ['title']
});
html:
{{#each book in books}}
<h1>{{book.title}}</h1>
{{/each}}
It's sorted!
, but I'm not satisfied...
Is there another cleanest/simplest way to use the each statement as defined in ember 1.1.10 and sort my array ?
Instead of {{#each book in model}}
use {{#each book in arrangedContent}} or {{#each book in this}}
Try using 'arrangedContent' to get your array sorted in ArrayController.
App.BooksController = Ember.ArrayController.extend({
sortProperties: ['title'],
content: function() {
return this.get('arrangedContent'); // this gives sorted array
},
});
Hope this helps
I'm following a Meteor tutorial, following it step by step and I have run into two issues:
1) when I call the {{> message}} between {{#each messages}} and {{/each}}, my "check if it works" doesn't show up at all. When I call the {{> message}} anywhere else, my "check if it works" shows up!
{{messages}}
<template name="messages">
<h3>message list</h3>
{{#each messages}}
{{> message}} <!--echo of message template-->
{{/each}}
</template>
<template name="message">
<h4>check if it works</h4> <!--didn't show up on page-->
<p>{{name}}: {{message}}</p>
</template>
2) Also none of my Javascript works at all.
I type in 'Messages.insert({ name: 'Eunice', message: 'hello world', time: 10})' to the console. and it is supposed to have Eunice: hello world pop up, sorted by time.
Messages = new Meteor.Collection('messages');
if (Meteor.is_client){
Template.messages.messages = function () {
return Messages.find({}, { sort: {time: -1} });
};
}
I'm usually a good de-bugger, so I don't know where I made a mistake. So I probably misunderstood how something works going from console to collections to templates. Thanks!
Your if check is incorrect
if(Meteor.is_client) {
}
Should be
if(Meteor.isClient) {
}