I am building a simple table component with Polymer. I am passing the list of items (an array of objects), and also the list of properties I'd like to display.
So, for example, I want to tell the component: only display the "name" and "number" properties of each object I'll pass to you.
this is how I the component is called:
<cool-table
items="[[projects]]"
columns='[
{"heading": "Project name", "property": "name"},
{"heading": "Project number", "property": "number"}]'>
</cool-table>
So basically it will create a table with two columns, with headings "Project name" and "Project number", and then each row will show project.name and project.number
Here is the component:
<dom-module id="cool-table">
<template>
<div class="table-header">
<template is="dom-repeat" items="{{columns}}" as="column">
<div class="cell">
[[column.heading]]
</div>
</template>
</div>
<div class="table-content">
<template is="dom-repeat" items="{{columns}}" as="column">
<div class="cell">
<!--
here is where I am getting stuck:
I want to to display [[ item.[[column.property]] ]]
So I need to dynamically generate
the name of the property I'll put in the data binding
-->
item.[[column.property]]
</div>
</template>
</div>
</template>
<script>
Polymer({
is: 'cool-table',
properties: {
items: {type: Array},
columns: {type: Array}
}
});
</script>
</dom-module>
In PHP I would do something like eval("\$item.$column.property")
Any idea how this can be achieved with Polymer?
Update:
I am rephrasing the question since I realized I made a mistake in describing the component. I'm using another example where I've simplified everything.
Basically I need to create a component that displays an array of objects. Each object will be on a row, and each object's key will be in a column.
Like this:
object1.name | object1.number | object1.type
object2.name | object2.number | object2.type
object3.name | object3.number | object3.type
So far, so good, that's easy.
Now what I'd like to do is to tell the component which keys need to be displayed, as I don't want to display all of them.
So, I need to tell the component: display only "name" and "number". Then we'll have:
object1.name | object1.number
object2.name | object2.number
object3.name | object3.number
To do that I'm passing the name of the keys I want to display:
<cool-table item="[[items]]" keys="['name', 'number']"></cool-table>
In cool-table.html I would have this:
<!-- loop through all items -->
<template is="dom-repeat" items="{{items}}" as="item">
<div class="row">
<!-- now loop through the keys we want to display -->
<template is="dom-repeat" items="{{keys}}" as="key">
<div class="cell">
<!--
Here I want to display the item's value for that key
for example if key is "name" I want to display item.name
that's what I can't figure out how to do
-->
</div>
</template>
</div>
</template>
Hopefully this now makes more sense. Thanks for hanging there with me!
Ah, I found the solution. I needed to use a computed binding:
<!-- loop through all items -->
<template is="dom-repeat" items="{{items}}" as="item">
<div class="row">
<!-- now loop through the keys we want to display -->
<template is="dom-repeat" items="{{keys}}" as="key">
<div class="cell">
[[getValueFromKey(item, column.key)]]
</div>
</template>
</div>
</template>
<script>
getValueFromKey: function(item, key) {
return item[key];
}
</script>
If I'm understanding your question correctly, you want an inner loop inside the columns array loop, where you iterate through the various keys of your column object?
If so, perhaps this question / answer would help?
Hi Hubert, again, not sure if I understand your question properly now, as I don't see a name property in your data. But I added one, and maybe this is what you are looking for?
Your component would look like this:
<div class="table-header">
<template is="dom-repeat" items="{{columns}}" as="column">
<div class="cell">
[[column.heading]]
</div>
</template>
</div>
<div class="table-content">
<template is="dom-repeat" items="{{columns}}" as="column" filter="{{isPropertyEqName('name')}}">
<div class="cell">
<!--
here is where I am getting stuck:
I want to to display [[ item.[[column.property]] ]]
So I need to dynamically generate
the name of the property I'll put in the data binding
-->
[[column.name]]
</div>
</template>
</div>
</template>
<script>
Polymer({
is: 'cool-table',
properties: {
items: {type: Array},
columns: {type: Array}
},
isPropertyEqName: function(search){
return function(item){
return item.property === 'name';
}
}
});
</dom-module>
and your use of the component would look as follows, where I addded the name property
<cool-table
items="[[projects]]"
columns='[
{"heading": "Project name", "property": "name", "name": "hello"},
{"heading": "Project number", "property": "number", "name": "world"}]'>
</cool-table>
Related
am trying to list 9 items each time and i found alethes:pages that can help accomplish it.
i didn't understand how exactly it should be implemented.
My collection is created with
Products = new Mongo.Collection("products");
so i created the Pages inside /lib folder
Pages = new Meteor.Pagination(Products, {
perPage: 9,
sort: {
createdAt: -1
}
});
Am confused on how to use the Pages to list the items? below is my template to list the items. Am calling the template inside another template to list the items.
This is the template
<template name="list_products">
{{#each applications}}
<div class="col-sm-4 col-lg-4 col-md-4">
<div class="thumbnail">
<img src="{{previewImage}}" alt="">
</div>
</div>
{{/each}}
</template>
How do i apply Pages to list_products template?
sorry for my english
This how you have to define your template and item template for pages.
Pages = new Meteor.Pagination(Products, {
perPage: 9,
sort: {
createdAt: -1
}
templateName: "list_products",
itemTemplate: "list_products_item",
});
Then your list_products have the following templates {{> pages}} and {{> pagesNav}} like this :
<template name="list_products">
{{> pages}}
{{> pagesNav}}
</template>
And here how you have to create your each item template which will show your item and you don't have to use any #each for that. Basically it will render each time based of your item per page value:
<template name="list_products_item">
<div class="col-sm-4 col-lg-4 col-md-4">
<div class="thumbnail">
<img src="{{previewImage}}" alt="">
</div>
</div>
</template>
I have an embedded document in a MongoDB collection "Author" as such:
{"Name": "John Doe",
"Country": "U.S.A",
"Books": [
{"BName": "Book1", "Year": "1950"},
{"BName": "Book2", "Year": "1960"}
]
}
I want to access the Books data, loop through it and display each Book in a table.
This is what my JS file looks like
Template.Author.helpers({
author: function() {
//_id of the Author is passed via the URL
return Author.find({"_id": FlowRouter.getParam('_id')})
}
});
This is the HTML for my report
<template name="Author">
<body>
<div class="row">
<div class="col-md-2">
Book Name
</div>
<div class="col-md-2">
Year
</div>
</div>
{{#each author}}
{{> bookdetails}}
{{/each}}
</body>
</template>
<template name="bookdetails">
<div class="row">
<div class="col-md-2">
{{Books.BName}}
</div>
<div class="col-md-2">
{{Books.Year}}
</div>
</div>
</template>
This works when I have only one record in the embedded Books document but not when I have more than one record - which makes sense since 'Books.BName' is ambiguous at that point.
I need to loop through 'Books' and output each BName and Year. This answer is the closest I found to doing this but I get the error:
TypeError: _.value is not a function
This may be because I have an embedded document as opposed to an array.
Your naming is confusing. You've got Book helper that returns an author, and that's what you're passing to the bookdetails template. You should rename the helper to author to reduce confusion. Then you can loop through the actual array of books with {{#each author.Books}}.
Furthermore, in the bookdetails template access the book parameters directly, e.g. {{BName}} instead of {{Books.BName}}.
I have a list template (#each) in a package that I plan to use across many different collections. Since the template is in a package they are not easily customizable. So I figured this was a great example to use Template.dynamic. Everything works except passing data.
.. I pull the data into the routed page and manipulate the data to match the dynamic template.
Template.usersIndex.helpers({
items: function() {
var users = Meteor.users.find({}).fetch();
var items = users.filter(function(user) {
return user;
}).map(function(user){
return {
name: user.profile.name,
description: user.emails[0].address,
tidbit: "hello"
};
});
return items
}
});
... the data passes perfectly to the usersIndex template.
<template name="usersIndex">
<div id="gc-users-index-navbar">
<h2>Title</h2>
</div>
<div id="gc-users-index" class="inner-content">
{{> Template.dynamic template="strataIndexItem" data="items" }}
</div>
</template>
... But no dice, the dynamic template is rendered but no data.
<template name="themeIndex">
<div class="list-group">
{{#each items }}
<div class="list-group-item">
<div class="row-content">
<div class="least-content">{{tidbit}}</div>
<h4 class="list-group-item-heading">{{name}}</h4>
<p class="list-group-item-text">{{description}}</p>
</div>
</div>
<div class="list-group-separator"></div>
{{/each}}
</div>
</template>
You pass data as string?
{{> Template.dynamic template="strataIndexItem" data="items" }}
You should pass data as variable, without ""
{{> Template.dynamic template="strataIndexItem" data=items }}
Also check if your strataIndexItem template is named strataIndexItem:
<template name="strataIndexItem">
...
</template>
I have been working with meteor.js and have been practicing using examples from getting started with meteor.js Javascript framework. The book is 2 years old and I have been running across some snags. For instance the book tells you to use var to define a variable, but after searching on stack I read that you didn't have to use it and now it works. I'm new so I write programs, run them, debug them and start from scratch to help me learn. For some reason this program that I have done 4 times before today is not running and I cant figure out why.
I keep getting this message :
While building the application:
LendLib.html:37: Expected "template" end tag
...  </div>
after inputting the following code:
<head>
<title>LendLib</title>
</head>
<body>
{{> hello}}
<div id="categories-container">
{{> categories}}
</div>
</body>
<template name="hello">
<h1>Lending Library</h1>{{greeting}}
<input type="button" value="Click" />
<template name="categories">
<div class="title">my stuff</div>
<div id="categories">{{#each lists}}
<div class="category">{{Category}}</div>{{/each}} </div>
</template>
</template>
any advice will be appreciated
dont define templates inside another template.
try like this.
<template name="hello">
<h1>Lending Library</h1>
{{greeting}}
<input type="button" value="Click" />
</template>
<template name="categories">
<div class="title">my stuff</div>
<div id="categories">
{{#each lists}}
<div class="category">
{{Category}}
</div>
{{/each}} 
</div>
</template>
Like pahan said, you cannot define a template within another template. They each have to be separate and un-nested. You CAN, however, call a template from within another template.
<template name="myOtherTemplate">
<h1> Lalalala </h1>
</template>
<template name="myTemplate">
{{> myOtherTemplate}} //injects the contents of myOtherTemplate
</template>
On another note, you also cannot nest Template instances within other Template instances.
Say that you want to register a helper function only after a certain template has been rendered.
Template.myTemplate.rendered = function({
Template.myTemplate.helpers({
key: "value",
anotherKey: "anotherValue"
});
});
^^ This also won't work.
So I want to render a template that will hold an image when the value of the score in my Players collection equals 500, it right now doesn't render at all even when a player score equals 500, do I need an if statement in my handlebars or something else?
Relevant code I made so far
client
foo.html
<body>
<div class="container">
{{> header}}
<div class="row-fluid">
<div class="span8">
{{> leaderboard}}
</div>
<div class="span4">
{{> champion}}
</div>
</div>
</div>
</body>
<template name="champion">
{{#each winners}}
{{> winner}}
{{/each}}
</template>
<template name="winner">
<img src="gold.jpg" alt="winner">
</template>
foo.js
Template.champion.winners = function () {
return Players.find({score: 500});
};
You marked the Template code as being on the server in your question, but the code with Template.winner.winners should be on the client, not the server. This is most likely the problem. Also, you have two templates named winner, although Meteor should throw an error on the command line if you have duplicate template names.
Finally, this isn't what you asked, but it may come handy for debugging too. You can detect whether the cursor is empty in your templates using Handlebars {{else}}:
{{#each winners}}
{{> winner}}
{{else}}
no winners!
{{/each}}