I want to display an array of object in HTML page, so I did this :
Template.home.helpers({
contents() {
var contentArray = [];
var content1 =
{
'contentName': 'test1',
'contentSize': 'test1',
'contentType': 'test1',
};
var content2 =
{
'contentName': 'test2',
'contentSize': 'test2',
'contentType': 'test2',
};
contentArray.push(content1);
contentArray.push(content2);
return contentArray;
}
});
How can I display the "contents" in the HTML page ?
Have you worked through the meteor tutorial? This is covered in the second step, here.
For you, the following should suffice as a basic model:
<template name="home">
{{#each thing in contents}}
<ul>
<li>Name: {{thing.contentName}}</li>
<li>Size: {{thing.contentSize}}</li>
<li>Type: {{thing.contentType}}</li>
</ul>
{{/each}}
</template>
If this doesn't make sense it would be best to work through the first few steps of the Blaze tutorial first.
You might also want to take a look at the blaze docs, specifically #each ... in ... - http://blazejs.org/guide/spacebars.html#Each-in
Related
I'm trying to implement sort and search to my items, so i started with sort and it works:
Template
<button class="sort">Sort</button>
{{#each cvs}}
{{> Interviu}}
{{/each}}
JS:
Template.Interviuri.onCreated(function () {
var self = this
self.autorun(function () {
self.sortOrder = new ReactiveVar(-1)
})
Template.Interviuri.helpers({
cvs() {
const instance = Template.instance()
return Cvs.find({}, { sort: { createdAt: instance.sortOrder.get() } })
},
})
Template.Interviuri.events({
'click .sort'(event, instance) {
instance.sortOrder.set(instance.sortOrder.get() * -1)
Next i wanted to implement Search on the same page. So the best way i could found was EasySearch.
But using EasySearch, it means i must change the way my items are being displayed. And then the sort doesn't work anymore.
Template
<div class="searchBox pull-right">
{{> EasySearch.Input index=cvsIndex attributes=searchAttributes }}
</div>
{{#EasySearch.Each index=cvsIndex }}
{{> Interviu}}
{{/EasySearch.Each}}
Collection
CvsIndex = new EasySearch.Index({
collection: Cvs,
fields: ['name'],
engine: new EasySearch.Minimongo()
})
JS
cvsIndex: () => CvsIndex,
How can i have both search and sort working at the same time?
With EasySearch you can use two methods on your index, namely getComponentDict() and getComponentMethods().
With getComponentDict() you can access search definition and options:
index.getComponentDict().get('searchDefinition');
index.getComponentDict().get('searchOptions');
You also have the corresponding setters to change the search definition/option.
getComponentMethods has mehods like
index.getComponentMethods().loadMore(integer);
index.getComponentMethods().hasMoreDocuments();
index.getComponentMethods().addProps(prop, value);
index.getComponentMethods().removeProps([prop])
From that you can set your prop, say index.getComponentMethods().addProp('sort', -1) and then on the index definition, in your MongoDB engine, set the sort from that prop:
index = new EasySearch.index({
// other parameters
engine: new EasySearch.MongoDB({
sort: function(searchObject, options) {
if(options.search.props.sort) {
return parseInt(options.search.props.sort);
}
return 1;
}
})
});
See EasySearch Engines for more info.
I am new to meteor, and have a basic understanding of what is going on, but I am stuck with this example (the problem has been simplified as much as possible):
I have a template, and a child template:
<template name="test">
{{#each items}}
{{> testItem}}
{{/each}}
{{#each items}}
{{> testItem}}
{{/each}}
</template>
<template name="testItem">
<div {{ b "click: toggle"}}>{{value}}</div>
</template>
Template.test.viewmodel({
items: [],
onCreated: function() {
this.items().push({ value: 'test' });
}
})
Template.testItem.viewmodel({
toggle: function() {
this.value("changed");
}
});
The thing here is we have a single array of items in the viewmodel, and we render it through a child template multiple times.
When we toggle the item, it only toggles the single item template, not the other representation of it. It is behaving like it is copying the value, or some sort of scoping is taking place.
My expectation would be the second item to also change, but this is not the case - what am I missing, or misunderstanding here?
EDIT - Additional Investigation
If I change the item through the parent, and notify it has changed, the changes propogate throughout the child templates
Template.testItem.viewmodel({
toggle: function () {
this.parent().items()[0].value = "changed";
this.parent().items().changed();
}
});
Thanks!
You're right, when you do this.value("changed"); you're changing the value of the testItem view model, not the parent array. If you're going to modify the properties of objects in an array I highly recommend you use a client side Mongo collection instead. It will save you a lot of headaches.
Items = new Mongo.Collection(null);
Template.test.viewmodel({
items: function() {
return Items.find();
},
onCreated: function() {
Items.insert({ _id: "1", value: 'test' });
}
})
Template.testItem.viewmodel({
toggle: function() {
Items.update({ _id: this._id() }, { value: 'changed' });
}
});
btw, I rarely check SO. You will get quicker responses on viewmodelboard.meteor.com
I want to know how to bind/set template-passed-parameter-value to click event of an item in the template in Meteor.
I'm using Meteor 0.7.0.1 with Blaze UI package. My main idea is to build a re-usable custom components in Meteor with Blaze template engine.
I have the following component which is working fine at the moment but I want this to be more customizable and remove some dependencies.
This is my component template named postLinks
<template name="postLinks">
<div id="link-popover-wrapper" >
<ul class="link-popover">
{{#each linkOptions}}
<li><a tabindex="-1" class="link-action" id="link-{{value}}" href="#">{{label}}</a>
</li>
{{/each}}
</ul>
</div>
</template>
This postLinks component is used in the myPostItem helper.
Template.myPostItem.events({
'click .post-item-link-picker': function (evt, tmpl) {
var tmpPostId = this._id;
var tempData = {linkOptions:[{label:'Favorite', value : 'favorite'},{label:'Wish list', value : 'wishlist'},{label:'Later', value : 'later'}, {label:"Read", value:"read"}]};
var linkContent = Template.postLinks(tempData);
$(".item-link-picker").popover({
content: linkContent, html: true, placement: 'bottom', trigger: "manual",
template: "UI_POPOVER_TEMPLATE"});
$("#item-link-picker-"+tmpPostId).popover('show');
},
'click .link-action': function (evt, tmpl) {
//.... some code here to update link selection in db
}
});
Above code is working fine and I want to improve it to have following
Pass item click event externally to be bind to link-action like
After above two changes it will look like :
Template.myPostItem.events({
'click .post-item-link-picker': function (evt, tmpl) {
var tmpPostId = this._id;
var tempData = { itemClick:function(){}, linkOptions:[{label:'Favorite', value : 'favorite'},...]};
var linkContent = Template.postLinks(tempData);
$(".item-link-picker").popover({
content: linkContent, html: true, placement: 'bottom', trigger: "manual",
template: "UI_POPOVER_TEMPLATE"});
$("#item-link-picker-"+tmpPostId).popover('show');
}
});
I lack knowledge how/where to bind that passed event handling function to link-action elements in template or helper. I really appreciate if anybody could help to find a way to do that.
You go the other way around and use jQuery event triggering system, so
Template.myPostItem.events({
'click .link-action': function (evt, tmpl) {
$(evn.target).trigger('post-link-action', this /* extra data */);
},
});
This event can be easily catched in any parent template:
<template name="someOtherTamplate">
{{> myPostItem}}
</template>
Template.someOtherTemplate.events({
'post-link-action': function (evt, tmpl, extra) {
// the user of your component can define their custom behavior here
},
});
Please note that the event extra parameter will only be supported in the next Meteor release. Currently (0.8.0) it is included in the devel branch.
After Commit 48 (Beta Candidate) i can't get observable array logic anymore. I know it has changed. I've read the changelog and been playing with new commit for some time but couldn't get it working. Helpers just don't update anymore. Any help appreciated.
Here is a simple example. Clicking "add friend" should call friends_names again.. but it doesn't anymore:
<!DOCTYPE html>
<html>
<head>
<script src="http://code.jquery.com/jquery.js"></script>
<script src="http://www.jsviews.com/download/jsviews.js"></script>
</head>
<body>
<div id="people"></div>
<script id="peopleTemplate" type="text/x-jsrender">
<button id="add">Add person</button><br />
{^{for people}}
<div>
Name: {{>name}},
Friends: <span data-link="html{:~friends_names(#data.friends)}"></span>
<button class="friend-add">add friend</button>
</div>
{{/for}}
</script>
<script>
var data = {
people: [
{
name: "Adams",
friends: [
{name:'Petere'},
{name:'Steve'}
]
},
{
name: "Eugenia",
friends: [
{name:'Bob'}
]
}
]
};
$.templates({
peopleTmpl: "#peopleTemplate"
});
var friends_names = function(friends){
friends = friends || []
var names = []
for (var i=0, l=friends.length; i<l; i++) {
names.push(friends[i].name);
}
return '<b>' + names.join(', ') + '</b>';
};
$.views.helpers({friends_names:friends_names});
$.templates.peopleTmpl.link("#people", data);
//debug
$.observable(data).observeAll(function (ev, obj) { console.log('change', obj); });
$("#add").on("click", function() {
$.observable(data.people).insert({
name: "Amos",
friends: []
});
})
$('#people').on('click', '.friend-add', function(e){
e.preventDefault();
var name = 'Some anonymous friend' + Math.floor((Math.random()*100)+1);
var friends = $.view(this).data.friends;
$.observable(friends).insert({
name: name
});
});
</script>
</body>
</html>
I know nested template can be used (not sure if it will solve the problem) but in real application there is much more logic in helper, thus nested template won't help.
Yes, this is deliberate: See the commit note:
Data linking to arrays is simplified and more consistent. Now tags DO NOT automatically bind to arrays, and refresh when the array
updates. {^{myTag path.to.array/}} will now update when the to.array
property is update (property change) but not when the to.array
itself changes observably. (array change). A tag should opt in to
arraybinding either by deriving from the "for" tag - as in the
'range' sample: http://www.jsviews.com/#samples/tag-controls/range,
or by following the using onAfterLink and onDispose to add/remove
the onArrayChange handler, as in the {^{myWidget .../}} sample in
the JsViews unit tests. This change relates to
https://github.com/BorisMoore/jsviews/issues/158
Here is a really simple fix. If you include the array.length as a parameter (even if your helper function doesn't use it) then JsViews will respond to changes in the array length (which is a property change, not an array change) and will trigger a refresh for your helper: ~friends_names(friends, friends.length)
{^{for people}}
<div>
Name: {{>name}},
Friends: <span data-link="html{:~friends_names(friends, friends.length)}"></span>
<button class="friend-add">add friend</button>
</div>
{{/for}}
I am doing exercises in the book "Getting Started With Meteor.js Javascript Framework" and
there is a section where a template called categories is created, then a {#each} loop thumbs through a collection.This is done with the intent of printing the results to the screen. This works and the code is below.
<template name ="categories">
<div class ="title">my stuff</div>
<div id='categories'>
{{#each lists}}
<div id="category">
{{Category}}
</div>
{{/each}}
</div>
</template>
My question is this:
In the code below the sort parameter doesn't seem to do anything. I am curious what it is supposed to be doing. I understand that theoretically it's suppose to "sort", but when I play with the parameters nothing changes. I looked it up in the meteor documentation and I couldn't figure it out. I am trying to modify the code so that it so that it sorts in a different order. This way I can see results and get a real understanding of how {sort: works. I tried modifying the {sort: {Category: 1}}) to {sort: {Category: -1}}) as well as {sort: {Category: 2}}) and it's always the same result.
Template.categories.lists = function() {
return lists.find({}, {sort: {Category: 1}}); // Works
/* return lists.find({}); */ // Works just the same
}
The Collections are as follows:
lists.insert({Category:"DVDs", items: [{Name:"Mission Impossible" ,Owner:"me",LentTo:"Alice"}]});
lists.insert({Category:"Tools", items: [{Name:"Linear Compression Wrench",Owner:"me",LentTo: "STEVE"}]});
In your code, you can attempt to change the argument of the sort to be an array instead of an object, like this:
sort: [["Category","asc"],["another argument","desc"],[...]]
so the code :
Template.categories.lists = function() {
return lists.find({}, {
sort: [
["Category", "asc"],
["another argument", "desc"],
[...]
]
});
// return lists.find({}); // Works just the same
}
As per my understanding that is because default is to sort by natural order. More info can be found at this link