Polymerfire dom-repeat with Firebase objects - firebase

I want to be able to show a list of all the FirstName and ZipCodes. My data looks as follows:
/user
|
|__INAxzxWKQrSAfA7tapV0c08YvfJ3
| |____FirstName:"James"
| |____ZipCode:"90210"
|
|__ANAczxWKQrEAfA7tapV0c08YvfX6
|____FirstName:"Simon"
|____ZipCode:"40213"
and Polymerfire's firebase document looks like this
<firebase-document
app-name="contacts"
path="/user"
data="{{allUsers}}">
</firebase-document>
And my dom repeat is like
<template is="dom-repeat" items="{{_makeArray(allUsers)}}">
<div class="profile card">
{{item.FirstName}}
</div>
</template>
I added the function
_makeArray: function(items) {
return Object.keys(items).map(function (key) {items[key]});
}
There are no errors but I also get nothing to the DOM

just use firebase-query instead of firebase-document. you'll get an array back.
<firebase-query
app-name="contacts"
path="/user"
data="{{allUsers}}">
</firebase-query>
<template is="dom-repeat" items="{{allUsers)}}">
<div class="profile card">
{{item.FirstName}}
</div>
</template>

dom-repeat takes an array as the items property. You can do something like this:
<template is="dom-repeat" items="[[makeArray(allUsers)]]">
...
makeArray: function(items) {
return Object.keys(items).map(function (key) {items[key]});
}

You forgot the return:
_makeArray: function(items) {
return Object.keys(items).map(function (key) { return items[key]; });
}
Its works fine with me data are displayed just fine.

Better implementation (also includes the name of the key if required) can be found here:
How to use dom-repeat with objects instead of arrays in Polymer 1.0?
Also an implementation for two way binding:
Two way binding for Firebase arrays in dom-repeat
Hope this gets implemented in Polymer 2.0, as Firebase is being advertised but then there are problems with using best practice Polymer and best practice Firebase together.

Use firebase-query to return an array of object that you can pass to dom-repeate.
<firebase-query
path="/user"
data="{{allUsers}}"
</firebase-query>
The dom-repeat
add attribute as="data"
add property data.$key
<template is="dom-repeat" items="{{_makeArray(allUsers)}}" as="data">
<div class="profile card">
{{data.$key}}
{{data.FirstName}}
</div>
</template>

Related

Handlebars If Statement not behaving as expected

I have the following json object -
{
"type": "typeOne",
"Children": [
{
"ChildType": "ChildTypeOne",
"Settings": {
"IsChildTypeOne": true
}
},
{
"ChildType": "ChildTypeTwo",
"Settings": {
"IsChildTypeTwo": true
}
}
]
}
My handlebars template contains the following snippet -
{{#each Children}}
{{#if Settings.IsChildTypeOne}}
ChildTypeOne!!
{{else}}
ChildTypeTwo!!
{{/if}}
{{/each}}
If I run this data through the template, the only thing that ever renders is ChildTypeTwo!!. So it seems that the if statement isn't properly evaluating IsChildTypeOne. The strange part is that if I put a statement in to display the value of IsChildTypeOne in the else clause, the value is displayed as true for the first ChildType.
Does anyone have any thoughts as to why this is not working as expected?
NOTE - the json posted above is a trimmed down version of my actual object. The real object has nested Children arrays that reuse the same object structure. So for instance, in my example, ChildTypeOne can also have a Childrens array with other objects within it.
EDIT****
So in stepping through the code, I found that if I had my type defined as follows -
...
"Settings" : {
"IsChildTypeOne": 'true'
}
...
it appears to work. Removing the single quoted causes the value to be read as undefined when stepping through.
Given charrs answer didn't seem to help, and the fact that your JSON is more complex than what you've posted, maybe your actual template isn't referencing a parent context correctly? For instance, if you wanted to access the type field in #each children block, it would look like this:
{{#each Children}}
{{#if Settings.IsChildTypeOne}}
{{../type}}
{{/if}}
{{/each}}
This ended up being related to the process being used to serialize the json string into an object. Please see the issue here for an explanation.
Can you try changing the handlebar template code as below:
{{#Children}}
{{#if Settings.IsChildTypeOne}}
ChildTypeOne!!!
{{else}}
ChildTypeTwo!!!
{{/if}}
{{/Children}}
This would iterate your array of Children and would give you result as
ChildTypeOne!!!
ChildTypeTwo!!!
Since your json has two elements one which has ChildTypeOne true and other not.
Sample handelbar:
<div class="entry">
<h1>{{title}}</h1>
<div class="body">
{{body}}
{{#Children}}
{{#if Settings.IsChildTypeOne}}
ChildTypeOne!!!
{{else}}
ChildTypeTwo!!!
{{/if}}
{{/Children}}
</div>
</div>
The html Output for above template :
<div class="entry">
<h1>My New Post</h1>
<div class="body">
This is my first post!
ChildTypeOne!!!
ChildTypeTwo!!!
</div>
</div>
You can see ChildTypeOne!!! for first element is coming.

Meteor example for newbie

Following an example from a book, I have in my .js file
lists = new Mongo.Collection("Lists");
if (Meteor.isClient) {
Template.categories.helpers ({
'Category': function(){
return lists.find({}, {sort: {Category: 1}});
}})
and in my html file:
<body>
<div id="categories-container">
{{> categories}}
</div>
</body>
<template name="categories">
<div class="title">my stuff</div>
{{#each lists}}
<div>
{{Category}}
</div>
{{/each}}
</template>
I have input data this data into lists which uses Category for a field using the console:
> 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"}});
but it doesn't output the data.
I think the issue lies in the context of your {{#each}}, you seem to be attempting to access the mongo collection itself rather specific fields through a helper function.
Check out this tutorial on spacebars, it’s a pretty good read http://meteorcapture.com/spacebars/ and also the Meteor Docs section http://docs.meteor.com/#/full/livehtmltemplates. I'm fairly new to Meteor myself but hope that helps.
In your example, you use name Category for 2 different things.
It is the name of template helper function that return an array of list items.
and it is the name of a field item inside your list.
Do the {{#each Category}} to run on the array returned by the helper
Inside the each, you should access the {{Category}} or {{item}} list items
You just need to call your helper lists instead of Category and your code will work:
Template.categories.helpers({
lists: function () {
return lists.find({}, {sort: {Category: 1}});
}
});
{{#each lists}} means: Iterate over a collection cursor (the result of a find) or an array which we get by calling the helper lists. The naming here is somewhat confusing because lists also happens to be the name of the collection your are iterating over.
Inside of the each, the context is a lists document. Each document contains a Category field, which you are outputting inside of a div.
Recommended reading:
A Guide to Meteor Templates & Data Contexts
check to run command : meteor list
it is given to you list of packages which is you used
if autopublish package not in the list you want to publish and subscribe your data here's simple example:
//in server
Meteor.publish('lists',function(){
return lists.find({}, {sort: {Category: 1}});
})
//in client
Meteor.subscribe('lists');
For More Deatails : publish subscription
First: The function in your 'categories' helper shouldn't be between quotes (not sure if that may couse problems).
Second: You are using the {{#each}} loop wrong.
You are calling the 'Lists' collection, but you should call the 'Categories' helper.
<template name="categories">
<div class="title">my stuff</div>
{{#each Category}}
<div>
{{Category}}
</div>
{{/each}}
</template>
Its very confusing your helper has the same name as the field you are calling in the #each loop.

Data available ("this") from a template event handler

projects.html
{{#if projects}}
{{#each projects}}
<div class="project-item">
<div class="project-name">
{{name}}
</div>
<div class="project-settings">
<span class="rename">Rename</span>
<span class="edit">Edit</span>
<span class="delete">
<!-- Here -->
</span>
</div>
</div>
{{/each}}
{{/if}}
projects.js
Template.Projects.events({
"click .project-item .delete": function (e, template) {
e.preventDefault();
debugger
// "this" refers to the specific project
}
});
In an event handler, I noticed "this" conveniently refers to a specific object inside the template where the event is related to. For example, in this case, the delete button is inside each projects block, and the handler for the delete button has this = some project. This is convenient, but I'd like to know the scopes and rules more completely. Can someone explain in briefly and point me to the right document?
This is a data context sensitive feature. Basically, there is a lexical scope in spacebars helpers. Have a look at this: http://devblog.me/no-data-context.html
The original pull request is here: https://github.com/meteor/meteor/pull/3560

In Meteor How to copy data between templates?

I'm new to both meteor and JS.
I created a meteor app like this:
cd /tmp/
meteor create hello
cd hello
In hello.html I wrote this
<body>
<h1>Welcome to Meteor!</h1>
{{> t1}}
{{> t2}}
</body>
Then I added these templates:
<template name='t1'>
<span id='t1'>hello</span>
</template>
<template name='t2'>
<span id='t2'>world</span>
</template>
Then I wrote syntax inside of hello.js to get text from the DOM:
Template.t1.onRendered( function() {
mytext = $('span#t1').html() });
According to the debugger-console in my browser,
the above syntax works okay.
The debugger tells me that mytext == 'hello'
Question: How to share the mytext value with other parts of my Meteor app?
As written, mytext is stuck inside my anonymous function.
For example how would I make this call work:
$('span#t2').html(mytext)
??
You'll want to reactively watch your variable. An easy out-of-the-box solution for this is to use the Session variable. You can do it pretty easily like so:
Template.t1.onRendered( function() {
Session.set('mytext', $('span#t1').html());
});
Then in your second template, define and reference helper that returns that variable:
<!--html-->
<template name='t2'>
<span id='t2'>{{getMyText}}</span>
</template>
//js
Template.t2.helpers({
getMyText: function() { return Session.get('mytext'); }
});
The Session variable is reactive, so when the first template renders and sets the value of Session.mytext, the helper's result will be invalidated and the second template will update.

how to insert a string containing a link with a helper in meteor blaze

I would like to insert a string that contains a link with a helper (or is there any better option to achieve this?) in meteor blaze.
So far blaze just gives back the link as normal text with the '' tags.
Does anyone have a good solution or workaround for this?
Here is a simple example to get you started :
<template name="parent">
{{> linkTemplate linkData}}
{{#each links}}
{{> linkTemplate}}
{{/each}}
</template>
<template name="linkTemplate">
{{title}}
</template>
Links=new Meteor.Collection(null);
Links.insert({
url:"https://www.google.com",
title:"Google"
});
Template.parent.helpers({
linkData:function(){
return {
url:"https://www.google.com",
title:"Google"
};
},
links:function(){
return Links.find();
}
});
If you want to render a string in a template that happens to contain a link, you would have to provide the HTML string as in
var string="A link to Google.";
Then you can use the triple bracket syntax {{{helperReturningHTMLString}}} and it will work as expected, but I don't think it's good practice unless you're working with something like a WYSIWYG editor.

Resources