Wolfchamane
Wolfchamane

Reputation: 255

Polymer dom-repeat issue

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

Answers (1)

Hin Fan Chan
Hin Fan Chan

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

Related Questions