Polymer 1.0 Problems with dom-repeat

3.7k Views Asked by At

I hope someone could help me. I'm really frustrated. :-( I can't figure out how to use the new dom-repeat template with polymer 1.0.

I want to show same items from firebase in a custom-element-list, but if I load the items from firebase, my custom-element-list doesn't fill with the items.

Please see the Code. BIG THANKS in the meantime.

Custom Element: my-uebersicht

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

    #fabTest {
      position: absolute !important;
      right: 10px;
      top: 10px;
    }
  </style>
  <template>
    <h1 class="paper-font-display1"><span>Übersicht</span></h1>
 
    <my-zeiteintrag-list zeiteintraege="{{zeiteintraege}}"></my-zeiteintrag-list>
 
    <paper-fab id="fabTest" mini icon="polymer" on-click="loadUebersicht"></paper-fab>
  </template>
</dom-module>
 
<script>
  (function() {
    Polymer({
      is: 'my-uebersicht',

      routeTo: function(route) {
        document.querySelector('#app').route = route;
      },

      loadUebersicht: function() {
        var id = document.querySelector('#app').getUserId();
        var uname = document.querySelector('#app').getUsername();

        if ((typeof id === 'undefined') || (typeof uname === 'undefined')) {
          this.routeTo('login');
        }

        var that = this;
        var rootRef = new Firebase("https://<FIREBASE.com>/" + id);
        rootRef.on("value", function(snapshot) {

          snapshot.forEach(function(child) {

            var zeintrag = child.val();
            that.zeiteintraege.push(zeintrag);

          });
        });
      },

      ready: function() {
        this.zeiteintraege = [];
      }
    })
  })();
</script>

Custom Element: my-zeiteintrag-list

<dom-module id="my-zeiteintrag-list">
    <style>
      :host {
        display: block;
      }
    </style>
  <template>
 
    <template is="dom-repeat" items="{{zeiteintraege}}">
      <my-zeiteintrag-item zeiteintrag="{{item}}"></my-zeiteintrag-item>
    </template>
 
  </template>
</dom-module>
<script>
  (function () {
    Polymer({
      is: 'my-zeiteintrag-list',

      properties: {
        zeiteintraege: {
          type: Array,
          value: [],
          notify: true,
          reflectToAttribute: true
        }
      },

      ready: function() {
        this.zeiteintraege = this.zeiteintraege || [];
      }
    });
  })();
</script>

Custom Element: my-zeiteintrag-item

<dom-module id="my-zeiteintrag-item">
  <style>
    :host {
      display: block;
    }
  </style>
  <template>
 
    <paper-material elevation="1">
      <ul>
        <li>Projekt: <span class="paper-font-body1">{{zeiteintrag.projekt}}</span></li>
        <li>Vorgang: <span class="paper-font-body1">{{zeiteintrag.vorgang}}</span></li>
        <li>Artikel: <span class="paper-font-body1">{{zeiteintrag.artikel}}</span></li>
        <li>Datum: <span class="paper-font-body1">{{zeiteintrag.datum}}</span></li>
        <li>Dauer: <span class="paper-font-body1">{{zeiteintrag.dauer}}</span></li>
        <li>Bemerkung: <span class="paper-font-body1">{{zeiteintrag.bemerkung}}</span></li>
      </ul>
    </paper-material>
 
  </template>
</dom-module>
 
<script>
  (function () {
    Polymer({
      is: 'my-zeiteintrag-item',

      properties: {
        zeiteintrag: {
          type: Object,
          value: {},
          notify: true,
          reflectToAttribute: true
        }
      },

      ready: function() {
        this.zeiteintrag = this.zeiteintrag || {};
      }
    });
  })();
</script>

[EDIT] - found a solution

After pointing to a Polymer Github Issue about dom-repeat at the Polymer Slack Chat Github Issue and read the Documentation again. You must use the Polymer methods (push, pop, splice, shift, unshift) for Arrays to trigger an update.

Here is the working solution:

Custom Element: my-uebersicht

<script>
  (function() {
    Polymer({
      is: 'my-uebersicht',

      routeTo: function(route) {
        document.querySelector('#app').route = route;
      },

      loadUebersicht: function() {
        var id = document.querySelector('#app').getUserId();
        var uname = document.querySelector('#app').getUsername();

        if ((typeof id === 'undefined') || (typeof uname === 'undefined')) {
          this.routeTo('login');
        }

        var that = this;
        var rootRef = new Firebase('https://<FIREBASE>.com/erfassung/' + id);
        rootRef.on('value', function(snapshot) {

          that.zeiteintraege = [];

          snapshot.forEach(function(child) {
            var zeintrag = child.val();
            that.push('zeiteintraege', zeintrag); //THIS IS ALL!!!
          });
        });
      },

      ready: function() {
        this.zeiteintraege = [];
      }
    });
  })();
</script>

2

There are 2 best solutions below

1
On

Not sure whether you are looking for something similar:

<dom-module id="my-zeiteintrag-list">
  <template>
    <template is="dom-repeat" items="zeiteintraglist">
      <div>
        <span>{{item.name}}</span><br />
        <span>{{item.country}}</span>, <span>{{item.phone}}</span>.<br />
        <span><a href$="{{generateEmailLink(item.email)}}"><span>{{item.email}}</span></a></span>
      </div>
    </template>
  </template>
</dom-module>

<!--Script section starts -->
<script>
  (function () {
          Polymer({
              // define element prototype here
              is: 'my-zeiteintrag-list',
              generateEmailLink: function(value)  {
                //Computed property, since 1.0 does not allow string concatenation
                return "mailto:" + value;
              },
              ready: function () {
                  this.zeiteintraglist = [
                    { "name": "John Doe", "country": "USA", "phone": "1 202 303 4567", "email": "[email protected]"},
                    { "name": "Sara O'coner", "country": "USA", "phone": "1 202 303 4567", "email": "[email protected]"}
                  ];
              }
          });
      })();
</script>

0
On

I'm glad to see you found the solution. I'd like to touch base on the why a little bit. Polymer data binding is built on events for efficiency. When a value is mutated or replaced, Polymer sends events to components that are bound to that data, and they update. Mutating the array directly does not fire these events, because arrays aren't aware of polymer. Hence, polymer provides it's own version of push, pop, shift, unshift, and splice, because these versions fire the correct event before updating the array.

It's important to keep this in mind with data binding in polymer in general. If you have an object, and you modify properties on that object outside of polymer (so not using things like this.set), you will have to manually notify Polymer of the path that updated so that templates rendered off of that object can know to update.