Sumanta Ghosh
Sumanta Ghosh

Reputation: 11

polymer 1.0 dom-repeat render not updating dom

I have an element which renders a array of objects using dom-repeat. There is also a feature to modify a particular object. However, after updating the object, even if the array is updated, the dom does not reflect the change (render is called as well). I am using Polymer provided mutation function (this.slice, have a look in the _commitChange function below). Can someone point out what is wrong here? One thing to note is that individual items in the array are objects rather than primitives /

<dom-module id="em-person-qualifications">
  <template>
    <style include="shared-styles"></style>
    <style>
      :host {
        display: block;
      }
      iron-pages {
        height: 100%;
      }
    </style>
    <iron-pages id="container" selected="0">
      <div id="listContainer">
        <template id="listTemplate" is="dom-repeat" items="[[data]]">
          <paper-item>
            <paper-item-body two-line>
              <div>
                <span>[[item.qualificationLevel.level]]</span>,
                <span>[[item.qualificationLevel.levelCategory]]</span>
              </div>
              <div secondary>
                <span>[[item.fromInstitute.edumateOrgDisplayName]]</span>
                <span>[[item.status]]</span>
              </div>
            </paper-item-body>
            <paper-icon-button icon="more-vert" on-tap="_loadModifyUI"></paper-icon-button>
          </paper-item>
        </template>
      </div>

      <div id="detailContainer">
        <paper-toolbar>
          <div class="title">
            <us-com-i18n key="qualificationDetail"></us-com-i18n>
          </div>
          <paper-icon-button id="button" icon="clear" on-click="_showList"></paper-icon-button>
        </paper-toolbar>
        <div>
          <iron-label for="levelContainer">
            <us-com-i18n key="level"></us-com-i18n>
          </iron-label>
          <div id="levelContainer" class="layout horizontal wrap">
            <us-com-freeorref data="{{currItem.qualificationLevel.level}}"></us-com-freeorref>
            <paper-dropdown-menu label="select">
              <paper-menu class="dropdown-content" attrForSelected="data-value" selected="{{currItem.qualificationLevel.levelCategory}}">
                <paper-item data-value="10">Graduate</paper-item>
                <paper-item data-value="11">Post-graduate</paper-item>
              </paper-menu>
            </paper-dropdown-menu>
          </div>

          <iron-label for="majorSubjectContainer">
            <us-com-i18n key="majors"></us-com-i18n>
          </iron-label>
          <div id="majorSubjectContainer">
            <template is="dom-repeat" items="[[currItem.majorSubjects]]">
              <em-party-subject data="{{item}}"></em-party-subject>
            </template>
          </div>

          <iron-label for="minorSubjectContainer">
            <us-com-i18n key="minors"></us-com-i18n>
          </iron-label>
          <div id="minorSubjectContainer">
            <template is="dom-repeat" items="[[currItem.minorSubjects]]">
              <em-party-subject data="{{item}}"></em-party-subject>
            </template>
          </div>
          <iron-label for="during">
            <us-com-i18n key="during"></us-com-i18n>
          </iron-label>
          <div class="layout horizontal wrap" id="during">
            <span><us-com-i18n key="from"></span>
            <us-com-date data="{{currItem.fromMonthYear}}"></us-com-date>
            <span><us-com-i18n key="to"></span>
            <us-com-date data="{{currItem.toMonthYear}}"></us-com-date>
          </div>
          <paper-input type="text" value="{{currItem.status}}" label="status">
            <us-com-formattedlongtext data="{{currItem.achievmentStatement}}" label="achievements"></us-com-formattedlongtext>
            <div class="buttons">
              <paper-button tabindex="0" raised autofocus on-click="_commitChange">
                <iron-icon icon="check"></iron-icon>Ok
              </paper-button>
            </div>
        </div>
      </div>
    </iron-pages>
  </template>

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

      Polymer({

        is: 'em-person-qualifications',

        properties: {
          data: {
            type: Array,
            value: function() {
              return [{
                'qualificationLevel': {
                  'level': 'Bsc',
                  'levelCategory': 10
                },
                'majorSubjects': [],
                'minorSubjects': [],
                'fromMonthYear': {},
                'toMonthYear': {},
                'fromInstitute': {
                  'edumateOrgDisplayName': 'XYZ College'
                },
                'status': 'ABCD',
                'achievmentStatement': {}
              }, {
                'qualificationLevel': {
                  'level': 'M-Tech',
                  'levelCategory': 11
                },
                'majorSubjects': [],
                'minorSubjects': [],
                'fromMonthYear': {},
                'toMonthYear': {},
                'fromInstitute': {
                  'edumateOrgDisplayName': 'ABC College'
                },
                'status': 'EFGH',
                'achievmentStatement': {}
              }];
            }
          },
          currItem: Object,
          currIndex: Number,
          currChange: String
        },

        behaviors: [app.I18nBehavior],

        _showList: function() {
          this._commitChange();
          //this.$.container.selected = '0';
        },
        _loadAddUI: function() {
          this.currChange = 'A';
          this.currItem = {};
          this.$.container.selected = '1';
        },
        _loadModifyUI: function(e) {
          this.currChange = 'M';
          this.currItem = e.model.item;
          this.currIndex = this.data.indexOf(e.model.item);
          this.$.container.selected = '1';
        },
        _loadDeleteUI: function() {
          this.currChange = 'D';
          //Find out the index from the data-index attribute of the button
          this.currIndex = 0;
        },
        _commitChange: function() {
          //var model = e.model;
          //this.splice('data',)
          if (this.currChange === 'A') {
            this.push('data', this.currItem);
          } else if (this.currChange === 'M') {
            this.splice('data', this.currIndex, 1, this.currItem);
            console.log('data[this.currIndex] = ' + this.data[this.currIndex].status);
          } else if (this.currChange === 'D') {
            this.splice('data', this.currIndex, 1);
          }
          this.$.listTemplate.render();
          this.$.container.selected = '0';
        }

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

Strings as I see in most examples.

Upvotes: 1

Views: 340

Answers (1)

Rickard Elim&#228;&#228;
Rickard Elim&#228;&#228;

Reputation: 7591

I'm on a huge Polymer 1.9 project, and is currently switching to Polymer 2.0, and I can tell that things like updating a dom-repeat is handled in a better way in Polymer 2.


Updating subproperties in a dom-repeat is a nightmare in 1.0, and the simplest solution is to override dirty checking, where Polymer is checking every single property to see if the DOM needs to update.

var copiedData = JSON.parse( JSON.stringify(data) );
this.set('data', []);
this.set('data', copiedData);

If you're desperate, use this method, but it can create a performance issue on phones or if the list is over about 100 items. You could probably also just do ...

this.set('data', JSON.parse( JSON.stringify(data) ));

... as a totally new array will override dirty checking. Anyways, a dom-repeat wont update with this.splice if the length of the array doesn't change, so I would do something like this.set('data.' + this.currIndex, this.currItem) to update the subproperty directly instead of the splicing that occurs here:

    _commitChange: function() {
      // ...
      } else if (this.currChange === 'M') {
        this.splice('data', this.currIndex, 1, this.currItem);

Also, you don't need this as Polymer should update automatically:

      this.$.listTemplate.render();

Upvotes: 1

Related Questions