Chris Russi
Chris Russi

Reputation: 35

Polymer + Meteor, in blaze #each loop, unable to pass object to Polymer web component

In Polymer, alone, without combining with Meteor, you can pass an object to a polymer web component by simply passing it to an attribute. I've been successful at doing this. Here we're passing "state" from the iteration directly into the custom polymer web component called state-card.

<template repeat="{{state in states}}">
	<state-card class="state-card" stateObj={{state}}></state-card>
</template>

However, in my project, I am combining Polymer and Meteor.
Polymer's templates and Meteor's blaze templates can't be mixed ... so, this is blaze with just a custom Polymer web component. I could not pass the "state" object in Meteor with blaze #each loop in a meteor template. As a work-a-round I found I could only pass the individual properties as text strings like so ...

<template name="inbox">
    <div class="content" flex>
        {{#each states}}
            <state-card class="state-card" name={{name}} status={{status}} displayType={{displaytype}}></state-card>
        {{/each}}
    </div>
</template>

to accomplish the above, here is a snippet from the custom Polymer web component with an attribute like so ...

<polymer-element name="state-card" attributes="name status displayType" on-click="cardClicked">
    <template>
    ...
    </template>
</polymer-element>

What I "really" want to do is just pass in the object directly to the polymer web component like so ... but, sadly this just won't work

<template name="inbox">
    <div class="content" flex>
        {{#each states}}
            <state-card class="state-card" stateObj={{this}}></state-card>
        {{/each}}
    </div>
</template>

Ideally, I should be able to accept the object with an attribute like so ...

<polymer-element name="state-card" attributes="stateObj" on-click="cardClicked">
    <template>
    ...
	</template>
</polymer-element>

This SO question/answer is "very" similar to my issue, but, the answer didn't work because I have the Meteor blaze template complication ...

Similar SO question/answer

I "really" don't want to stick with my work-a-round ... even though it works.

I've read elsewhere on SO that in a blaze #each iteration you can access the object literal like so ...

{{#each humans}}
  {{this}}
{{/each}}

But, I couldn't make this work. I would be very appreciative of any help and guidance. I understand what I'm trying to do, combine Polymer and Meteor is somewhat problematic, but, I've seen it done and I've made a lot of progress. I'm just stumbling at this point. Thanks!!!

Upvotes: 3

Views: 449

Answers (1)

Greg Neiheisel
Greg Neiheisel

Reputation: 590

When setting an attribute on a custom polymer element, polymer attempts to detect the type and and cast the property as such when setting the values on your elements prototype - so numbers are numbers and strings are strings, etc. Things become a little more difficult when you are not setting this attribute from within another polymer element - like trying to set it using blaze (and any other non-polymer engine, I'd imagine).

Polymer ends up running .toString() on your object literal which produces "[object Object]" which is of little use. Luckily, polymer lets you pass objects in as double quoted JSON strings from the outside world, like the result of JSON.stringify(something).

The most straightforward, but not as elegant approach is to create a stringify helper and use it to set the attribute.

Template.registerHelper('stringify', function(obj) {
  return JSON.stringify(obj);
});

{{#each things}}
  <my-component something={{stringify this}}></my-component>
{{/each}}

OR

Template.registerHelper('stringThis', function() {
  return JSON.stringify(this);
});

{{#each things}}
  <my-component something={{stringThis}}></my-component>
{{/each}}

Another option could be to override the toString method at some level in your application. Using meteor's document transforms or the collection-helpers package you could add a toString method that just returns JSON.stringify(this) - if you are iterating over cursors.

It's tough to just override Object.prototype.toString and do the same though. You'll get circular reference errors, but it looks like there are a couple libraries and methods to decycle objects before passing it (this) to JSON.stringify. I haven't tried this, but seems like it would work.

Either way, if the attribute is set to JSON, it will be available as an actual object within your polymer element. You can even setup observers on nested properties within that object!

Bottom line - there doesn't seem to be a perfect way yet, so stringify objects for now. Hope that helps!

Upvotes: 4

Related Questions