Reputation: 255
While rendering with Polymer an array of objects, it keeps launching me an exception.
Here's the data model retrieved from server:
{
"lastUpdate":"yyyy-MM-ddTHH:mm:ss.mmm",
"info": [
{
"title": "Some nice title"
},
...
]
}
Here's my Polymer component template:
<dom-module is="items-list">
<template>
<dl>
<dt>last update:</dt>
<dd>[[$response.lastUpdate]]</dd>
<dt>total items:</dt>
<dd>[[$response.info.length]]</dd>
</dl>
<template is="dom-repeat" items="{{$response.info}}">
{{index}}: {{item.title}}
</template>
</template>
<script src="controller.js"></script>
</dom-module>
And here's the controller:
'use strict';
Polymer(
{
properties: {
info: {
type: Array
},
$response: {
type: Object,
observer: '_gotResponse'
}
},
_gotResponse: function(response)
{
console.log(response);
if (response.info.length)
{
try
{
//here I try to set info value
}
catch(e)
{
console.error(e);
}
}
},
ready: function()
{
//set some default value for info
},
attached: function()
{
//here I request the service for the info
}
}
);
If tried to set info value as:
this.info = response.info;
this.set('info', response.info);
this.push('info', response.info[i]); //inside a loop
But the result breaks after rendering the first item, the exception launched is: "Uncaught TypeError: Cannot read property 'value' of null"
Upvotes: 0
Views: 207
Reputation: 1643
If info === $response.info
then why not just use items={{info}}
in the repeat?
edit: Try to modify your code in the following way.
'use strict';
Polymer({
properties: {
$response: {
type: Object
}
},
_gotResponse: function(response)
{
console.log(response);
...
this.$response = response
...
},
attached: function()
{
//here I request the service for the info
someAjaxFn(someParam, res => this._gotResponse(res));
}
});
You don't need an observer in this case. You only use an explicit observer when the implicit ones don't/won't work. I.e. fullName:{type:String, observer:_getFirstLastName}
or
value:{type:String, observer:_storeOldVar}
...
_storeOldVar(newValue, oldValue) {
this.oldValue = oldValue;
}
if you are updating the entire array, ie this.info
, then you simple use this.info = whatever
once within your function. If you don't want to update the entire array, just some element within it, then you will want to use polymer's native array mutation methods as JS array method doesn't trigger the observer.
Again, since your template doesn't use info, then you don't need the property info
. If you want to keep info, then don't store info within $response
. In fact, $ has special meaning in polymer so try not to name properties with it. you can simply use the property info
and lastUpdate
for your polymer.
Last note, beware of variable scoping when you invoke functions from polymer. Since functions within polymer instances often use this
to refer to itself, it may cause
Uncaught TypeError: Cannot read property 'value' ..."
as this
no longer refers to the polymer instance at the time of resolve.
For example, suppose your host html is
...
<items-list id='iList'></items-list>
<script>
iList._gotResponse(json); // this will work.
setTimeout(() => iList.gotResponse(json),0); //this will also work.
function wrap (fn) {fn(json)}
wrap (iList._gotResponse); //TypeError: Cannot read property '$response' of undefined.
function wrap2(that, fn) {fn.bind(that)(json)}
wrap2 (iList,iList._gotResponse); // OK!
wrap (p=>iList._gotResponse(p)) //OK too!!
wrap (function (p) {iList._gotResponse(p)}) //OK, I think you got the idea.
</script>
Upvotes: 0