Why does this polymer element's property resolve to undefined?
Asked Answered
C

3

8

I am trying to dynamically assign an attribute to an iron-ajax template but it resolves to undefined.

<dom-module id="products-service">
  <style>
    :host {
      display: none;
    }
  </style>

  <template>
    <iron-ajax id="productsajax"
      auto
      url="http://localhost:3003/api/taxons/products"
      params='{"token":"my-token"}'
      method='GET'
      on-response='productsLoaded'
      handleAs='json'>
    </iron-ajax>
  </template>
</dom-module>

<script>
(function() {
    Polymer({
        is: 'products-service',

        properties: {
            categoryid: {
                type: String,
                notify: true,
                reflectToAttribute: true
            }
        },

        //here I am trying to add and `id` to the `iron-ajax` `params` attribute.
        ready: function() {
            this.$.productsajax.params.id = this.categoryid;
       }
    });
})();
</script>

The resulting url looks like this:

`http://localhost:3003/api/taxons/products?token=my-token&id=undefined`

The dom-module's categoryid property is not undefined as i can see the correct property value reflected on the attributes which means it something to do with how am assigning it to the attribute. I have also tried this on the created and attached callbacks and still not working.

Edit: The categoryid is passed to the module when instantiating it like this:

<products-service products="{{products}}" categoryid="{{categoryid}}"></products-service>

As seen here the categoryid passed to the service already has a value. (the element names on the image may be slightly different. I shortened them to make the question less verbose.)

enter image description here

The category-products-list where the service is being called looks like this

<dom-module id="category-products-list">
  <template>
    <category-products-service products="{{products}}" categoryid="{{categoryid}}"></category-products-service>
    <div>
      <template is="dom-repeat" items="{{products}}">
       <product-card on-cart-tap="handleCart" product="{{item}}">
         <img width="100" height="100">
         <h3>{{item.name}}</h3>
         <h4>{{item.display_price}}</h4>
       </product-card>
     </template>
  </div>
</template>

</dom-module>

<script>
 (function() {
  Polymer({
  is: 'category-products-list',

  properties: {
    categoryid: {
      type: String,
      notify: true,
      reflectToAttribute: true
    }
  },

ready: function() {
   //this is undefined too
   console.log("categoryid in the list module: "+categoryid)
   }
   });
   })();
</script>
Cestus answered 9/6, 2015 at 19:47 Comment(9)
Where does the categoryid come from? Where is it set? What happens when you add console.log(this.categoryid); in your ready function?Fante
I have edited the question with the information you seek. When i do console.log(this.categoryid);: I get undefinedCestus
the problem is how you are passing the categoryid into the products-service...it is not a problem in the products-service element itself. If you do <products-service categoryid="5"></products-service> it will work. So the next question is, where are you getting the categoryid from? I don't know where you are getting the {{categoryid}} from, but I'm gonna take a wild guess: You could try <products-service products="{{products}}" categoryid$="{{categoryid}}"></products-service>Fante
please check my latest edit to the question. The categoryid passed to the service already has a value.Cestus
could you add your category-products-list element too please. I am assuming the root problem is within that element.Fante
The value passed in through the categoryid attribute should be available at ready, so the console.log should not be returning undefined. Please copy and paste the entire code for the component as-is (minus any security tokens), as I suspect the answer lies in a typo or something.Consider
@ErikHöhmann i have added the list dom-module. The categoryid in that module at ready is also undefined but it is available when it is present when it is passed to the service dom-module.Cestus
Thanks. I still can't see where you are passing in the categoryid. You are probably passing it in one element further up. I have created an answer, which works. Maybe you can use it as a reference. You could also try taking out the categoryid property in the script of the category-products-service, since it looks like you are getting this from the parent element.Fante
The categoryId is passed from routes. page('/categories/:name/:categoryid', function (data) { app.route = 'category-page'; app.params = data.params; });Cestus
C
6

I think you're running into a combination of issues here, and need to slightly rethink your structure.

First, because the categoryid attribute is bound outside of your element its initial value will be undefined. Basically, your element is created and attached, with all lifecycle methods run, and then categoryid gets set. This also means that because you have an iron-ajax with auto set, it will initially try to make a request with the information it is first given.

My recommended changes:

<dom-module id="products-service">
  <style>
    :host {
      display: none;
    }
  </style>

  <template>
    <iron-ajax id="productsajax"
      url="http://localhost:3003/api/taxons/products"
      params='{"token":"my-token"}'
      method='GET'
      on-response='productsLoaded'
      handleAs='json'>
    </iron-ajax>
  </template>
</dom-module>

<script>
(function() {
    Polymer({
        is: 'products-service',

        properties: {
            categoryid: {
                type: String,
                notify: true,
                reflectToAttribute: true
            }
        },

        observers: [
            // Note that this function  will not fire until *all* parameters
            // given have been set to something other than `undefined`
            'attributesReady(categoryid)'
        ],

        attributesReady: function(categoryid) {
            this.$.productsajax.params.id = categoryid;

            // With the removal of `auto` we must initiate the request
            // declaratively, but now we can be assured that all necessary
            // parameters have been set first.
            this.$.productsajax.generateRequest();
        }
    });
})();
</script>
Consider answered 9/6, 2015 at 20:30 Comment(5)
When i do this the id does not reflect in the resulting url, not even with a value of undefined.Cestus
@OptimusPette I suspect the iron-ajax component doesn't realize its params were updated. Try this.$.productsajax.set('params.id', this.categoryid);Consider
same effect, no id set in the params.Cestus
@OptimusPette please have a look at my revised answerConsider
It seems that was the problem all along, Everything works fine now with your recommended changes, It seems i need to revisit the docs on observers.Cestus
G
0

the problem is how you are passing the categoryid into the products-service...it is not a problem in the products-service element itself. If you do <products-service categoryid="5"></products-service> it will work. Clearly there is a lot more complexity to your application, but I created some simple elements which work correctly:

index.html:

<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">

<title>My Test</title>

<!-- Load platform support before any code that touches the DOM. -->
<script src="bower_components/webcomponentsjs/webcomponents-lite.min.js">    </script>

<link rel="import" href="elements/product-list.html">

</head>

<body>
  <product-list categoryid="5"></product-list>
</body>

</html>

product-list.html:

<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="../elements/product-service.html">


<dom-module id="product-list">
<style>

</style>

<template>
<product-service categoryid="{{categoryid}}"></product-service>
</template>
</dom-module>

<script>
Polymer({
    is: 'product-list'
});
</script>

product-service.html:

<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="../bower_components/iron-ajax/iron-ajax.html">


<dom-module id="product-service">
<style>

</style>

<template>
<iron-ajax id="productsajax"
  auto
  url="http://localhost:3003/api/taxons/products"
  params='{"token":"my-token"}'
  method='GET'
  on-response='productsLoaded'
  handleAs='json'>
</iron-ajax>
</template>
</dom-module>

<script>
Polymer({
    is: 'product-service',
    properties: {
      categoryid: {
              type: String,
              notify: true,
              reflectToAttribute: true
              }
},

//here I am trying to add and `id` to the `iron-ajax` `params` attribute.
ready: function() {
console.log(this.categoryid);
this.$.productsajax.params.id = this.categoryid;
},
productsLoaded: function(e) {
console.log('Response');
}

});
</script>
Genous answered 9/6, 2015 at 21:8 Comment(0)
C
0

Zikes diagnosis is correct, the reason this is returning undefined is the page life cycle is completed before the data is loaded onto the page. However, I was unable to get his answer to work for my solution. (Probably an error on my part, somewhere.) My api also uses query strings to pass data, while yours does not do this, I believe this answer will be helpful to anyone who runs into this situation like I did. To solve this issue, I added an observer to my property, I based this answer from https://www.polymer-project.org/1.0/docs/devguide/observers. I used the simple observer. I believe Zikes is using a complex one.

<iron-ajax id="productsajax" url= {{ajaxUrl}} method='GET'
      on-response='productsLoaded' handleAs='json'>
</iron-ajax>

Polymer({
    is: 'product-service',
    properties: {
            categoryid: {
                type: String,
                notify: true,
                reflectToAttribute: true,
                observer: 'catIdReady'
            },
            ajaxUrl: {
                type: String,
                notify: true
            }
    },
    catIdReady: function (catidnew, catidold) {
        this.set('ajaxUrl', this._getAjaxUrl());
        this.$.productsajax.generateRequest();
        console.log("catidReady!" + catidnew);
    },
    _getAjaxUrl: function () {
        console.log(this.categoryid);
        return 'http://localhost:3003/api/taxons/products?categoryId=' + 
        this.categoryid;
    },
Cenis answered 10/5, 2017 at 13:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.