6

A polymer element offices-list needs to be created dynamically inside another polymer element's script as so:

<dom-module id="contacts-tag"> 
    <template>
     <iron-ajax ... on-response = "handleResponse"></iron-ajax>
</template> 
 <script>
    Polymer({
        is: "contacts-tag",  

        handleResponse: function(request){
            var response = request.detail.response;
            this.officesRegions = response.officesRegions;  
            this.officesCities = response.officesCities;    

           var dynamicEl = document.createElement("offices-list");
           dynamicEl.setAttribute("regions", this.officesRegions);
           dynamicEl.setAttribute("cities", this.officesCities);
           document.body.appendChild(dynamicEl); 

        }
       });
</script></dom-module>

However as soon as it reaches "document.createElement("offices-list");" the element inside this new tag starts rendering, and it's on ready method is already called, while I was expecting them to happen after I set attributes. How can I do it?

Edit: Seems that problem is of different nature. I'm setting objects to attributes and "offices-list" tag is not recognizing them, hence isn't able to access it or loop through it. Then, my question will change to, "How to bind objects?"

Nazerke
  • 2,098
  • 7
  • 37
  • 57
  • What do you do in the `ready` callback ? if you want to wait with rendering until the element is added then use the `attached` callback – Ümit Jun 29 '15 at 14:51
  • Even if I move everything on ready to on attached, I still have problem of local dom getting rendered immediately. The elements in local dom need attributes in order to render correctly, but because attributes are added after the createElement I can't control it from getting rendered. As I said in the question,the problem is it's not waiting until it is actually appended, but gets rendered just after createElement without waiting for attributes – Nazerke Jun 30 '15 at 02:42

3 Answers3

11

I think the right answer is - it depends on what you are trying to achieve.

If you are looking to imperatively data-bind i.e. you want to dynamically add something like this into the template,

<offices-list offices-regions="{{regions}}"
              offices-cities="{{cities}}">
              </offices-list>

you are out of luck because imperative data-binding is not supported in Polymer 1.0.

If you simply want to pass in parameters (NOT data-bind) into a dynamically-created element, both el.setAttribute() and el.myAttribute = this.myAttribute should work.

Since you are using Polymer, I think you should try to contain DOM manipulations within the framework (inside a Polymer template instance) instead of directly adding to document.body, something like this.

<dom-module id="contacts-tag"> 
  <template>
     <iron-ajax ... on-response="handleResponse"></iron-ajax>
     <div id="insertion_point"></div>
  </template> 
  <script>
    Polymer({
      is: "contacts-tag",
      handleResponse: function(request) {
        ...
        Polymer.dom(this.$.insertion_point).appendChild(dynamicEl);
      }
    });
  </script>
</dom-module>

Lastly, if your intention is to simply display a <contacts-tag> after the ajax request is completed, I think you can achieve this declaratively.

<dom-module id="contacts-tag"> 
  <template>
     <iron-ajax ... on-response="handleResponse"></iron-ajax>

     <template is="dom-if" if="{{_unveilOfficesListWhenReady}}">
       <offices-list offices-regions="{{_regions}}"
                     offices-cities="{{_cities}}">
       </offices-list>
     </template>
  </template> 
  <script>
    Polymer({
      is: "contacts-tag",
      properties: {
        _regions: String,
        _cities: String,
        _unveilOfficesListWhenReady: { type: Boolean, value: false }
      },
      handleResponse: function(request) {
        var response = request.detail.response;
        this._regions = response.officesRegions;  
        this._cities = response.officesCities;
        this._unveilOfficesListWhenReady = true;
      }
    });
  </script>
</dom-module>

No dynamic element needed.

Community
  • 1
  • 1
zerodevx
  • 1,591
  • 10
  • 10
  • Good catch "Polymer.dom(this.$.insertion_point).appendChild(dynamicEl);" I've corrected in my code, forgot to do the same here. Umit's reply worked for me, thanks for elaboration – Nazerke Jun 30 '15 at 10:22
  • Hmm, if that's the case, that means you didn't expose any attributes in the `properties` object inside your `` element, so I'm not sure why you will want to specially create a new web component for that... But whatever works I guess. – zerodevx Jun 30 '15 at 10:37
8

You should not use setAttribute but you should set the corresponding property directly.

var dynamicEl = document.createElement("offices-list");
dynamicEl.regions = this.officesRegions;    
dynamicEl.cities = this.officesCities;
document.body.appendChild(dynamicEl); 
Ümit
  • 17,379
  • 7
  • 55
  • 74
  • 1
    For *attributes* (*non `HTMLElement` properties*) you will need to use `setAttribute`. Example: `dynamicEl.setAttribute('regions', this.officesRegions);` – tomloprod Oct 27 '16 at 16:46
1

You can use dom api provided by polymer team.

Polymer.dom(parent).appendChild(polymerChild)