Polymer: [1.0] Data-binding: Is there any way to do this imperatively?

Created on 8 Jun 2015  路  14Comments  路  Source: Polymer/polymer

Hello, considering the below snippet,

  var el = document.createElement("foo-element");
  el.setAttribute("foo", "[[foo]]");
  Polymer.dom(tpl.$.insertion_point).appendChild(el);

Full jsbin: (http://jsbin.com/hiloloqoju/1/edit)

In 0.5, I could simply imperatively import a Polymer element, then insert its markup into the DOM. Could I do something like that in 1.0?

Thanks so much,
J

Most helpful comment

Any updates or plans for updates on this? or any workarounds?

All 14 comments

AFAIK, importHref simply tells Polymer to register/upgrade an element. After registering, how do you imperatively create and place a data-bound node into DOM?

My apologies, I might not have been clear earlier.

Declarative approach:

...
<link rel="import" href="my-foo.html">
...
<dom-module>
  <template>
    <!-- Look, I loaded <my-foo> and did a two-way bind declaratively -->
    <my-foo foo="{{bar}}"></my-foo>
  </template>
  <script>
    Polymer({
      is: "my-element",
      properties: { bar: String },
      ...
    });
  </script>
</template>

Imperatively, how do I do the above?

Were you able to do

    el.setAttribute("foo", "[[foo]]");

and have it correctly execute the binding?

That seems rather strange.

Edit: Now that I think of it, it might have worked because they showed you the {{prop}} syntax in the DOM.

Nope, doesn't work, check out the jsbin: (http://jsbin.com/hiloloqoju/1/edit)

This used to work with 0.5 though.

No, we don't currently support this, outside of dom-bind, which is the only template implementation that late-binds instance children. You can document.createElement('template', 'dom-bind'), then you can dynamically append children with binding annotations to its content, and the bindings will only be evaluated once the dom-bind is attached to the document. See tests here that show this usage of it: https://github.com/Polymer/polymer/blob/master/test/unit/dom-bind.html#L95

Note that dom-bind does not currently allow binding to outer scope, so it has limited use in custom element templates (it's main use case is for binding between elements in the main document), and that's not likely to change short-term.

We are achieving a lot of performance optimization by baking the binding connections into the prototype at _registration_ time for an element (rather than at instance time), and we haven't built up enough of the machinery to easily allow runtime addition/removal of bindings.

@kevinpschaaf

Thanks for the detailed explanation. I suppose I could kind of emulate the data-binding behaviour by:

  1. on parent element, importHref, then document.createElement the child element and append into DOM.
  2. on parent element, define an observer on change and pass in updates to child element.
  3. on child element, fire events on change to notify parent element.

So, if this is no longer available in Polymer, why should I use Polymer with my APP?

Is this still up to date? Or rather, is there no easy way to dynamically import and create a custom element with data-binding properties?
I try to create a webapp with iron-pages that loads it's page-elements dynamically and get stuck because of missing databindings... :disappointed:

Can you take a look at #3456 (and its related PR #3460) and perhaps comment if that would fix your issue.

Any updates or plans for updates on this? or any workarounds?

I have same issue and search too much but finally use write this code to solve my problem.
I don't like this hard-way but I cant do it automatically.
I hope its useful for people search and find this issue.

my-element with ability to load other-element with two way data binding!

<dom-module id="my-element">
  <template>
    <style>
      :host {
        display: block;
      }
    </style>


    <div id="container">
      <button on-tap="changeFoo">Change Foo</button>
      <p>my-element: {{foo}}</p>
      <!-- <other-element foo="{{foo}}"></other-element> -->
    </div>
  </template>

  <script>
    (function () {
      'use strict';

      Polymer({
        is: 'my-element',

        properties: {
          foo: {
            type: String,
            value: 'foo'
          }
        },

        observers: [
          'setVar("foo", foo)'
        ],

        ready: function () {
          this._log('ready');

          if(!this.comp) this.makeComp();
          this.$.container.appendChild(this.comp);
        },

        changeFoo: function (){
          this.foo = Math.floor(Math.random()*1000);
        },

        makeComp: function () {
          this.comp = document.createElement('other-element');
          //this.comp.setAttribute('foo', '{{foo}}'); // not work!
          this.comp.addEventListener('foo-changed', this.getVar('foo'));
        },

        setVar: function (varName, value) {
          if(!this.comp) this.makeComp();
          this.comp[varName] = value;
          // this.comp.set function not defined
        },

        getVar: function (varName) {
          var _this = this;
          return function (evt) {
            var newValue = evt.detail.value;
            if(_this[varName] != newValue) {
              _this[varName] = newValue;
            }
          };
        }


      });

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

Check Demo

You can create dynamic <template id="dom-bind"> with and write any html code but i don't recommend it becouse your codes its not clean anymore and two way binding is very complex if you want make it dynamic like previous demo.
Demo for dynamic template (not recommended for two way binding)

same here ,and how can i get the data

var el = document.createElement("foo-element");
  el.setAttribute("foo", "[[foo]]");
  Polymer.dom(tpl.$.insertion_point).appendChild(el);

@AliMD not event match the problem,I need functions like dom to create doms dymamiclly depending on parsing the json data

use a template :) , but issue is for each parent location of dyanamic component we need separate "myElements" and template definition

<template is="dom-repeat" items="{{myElements}}" >
    <other-element data-index="[[index]]" foo="{{foo}}" on-remove-me="removeChild">
</template>

{

    properties:{
        myElements:{
            type:Array,
            value:[]
        },
        foo:{
            type: String,
            value: ""
        }

    },
    ready:function(e){
        setInterval(()=>{
            this.set("foo", Math.random());
        }, 5000)
    },
    addNewElement:function(){
        this.push("myElements", { })
    },
    removeChild:function(e){
        this.splice("myElements", e.target.dataIndex, 1)
    }
}

Was this page helpful?
0 / 5 - 0 ratings