Search code examples
javascriptpolymerweb-component

Limit array of dom-repeat within iron-list


I'm working on the public messaging part of an app right now. I am iterating over a collection of conversations (arrays) to display, which each contain the actual messages of the conversation as an array, so something like:

   [
       ...
       messages: 
       {
         content :"Yo what's up",
         fromUserId:"X7uFeXpm8NtgocQXJ",
         time:"Sun 26 at 19:41",
       }
       ...
   ]

My html & js look like this:

<iron-list items=[[publicMessages]]>
  <template>

      <paper-card elevation='2'>
        <template is='dom-repeat' items='[[limitMessages(item.messages, item)]]'>
          <paper-item>
            [[item.content]]
          </paper-item>
        </template>
        <paper-button on-tap='loadFullConversation'>Load entire conversation</paper-button>
      </paper-card>

  </template>
</iron-list>


limitMessages: function(messages, item) {
  if (!item.messageLimit) {
    messages = messages.slice(0, 3);
  } else {
    messages = messages.slice(0, item.messageLimit);
  }
  return messages;
},
loadFullConversation: function(e) {
  e.model.set('item.messageLimit', 1000);
},

A jsfiddle can be found here: https://jsfiddle.net/kv1vvvw9/1/

I've tried to bind to a property (which doesn't work though since it's tied to the overall component) and experimenting with the model but I just can't get it to work. If I update the model, how could make sure that limitMessages will re-run?

Note, the original messages collection does not contain item.messageLimit. I've just defined this myself in the view part. I don't think it makes sense putting this in the database inserts.


Solution

  • You could move the item.messageLimit property into item.messages.limit:

    loadFullConversation: function(e) {
      e.model.set('item.messages.limit', 1000);
    }
    

    ...and bind items to a deep sub-property observer on item.messages.*.

    <template is='dom-repeat' items='[[limitMessages(item.messages.*)]]'>
    

    That observer would be notified when loadFullConversation() sets item.message.limit, which would update the items in the template repeater.

    HTMLImports.whenReady(_ => {
      "use strict";
    
      Polymer({
        is: 'x-foo',
        properties: {
          publicMessages: {
            type: Array,
            value: _ => [new Message(), new Message()]
          }
        },
        loadFullConversation: function(e) {
          e.model.set('item.messages.limit', 1000);
    
          // Tell list to resize to fit the expanded card
          this.$.list.notifyResize();
        },
        limitMessages: function(change) {
          const limit = (change.path === 'item.messages.limit') ? change.value : 3;
          return change.base.slice(0, limit);
        }
      });
    
      function randContent() {
        const lorem = ['Lorem ipsum dolor sit amet',
                     'consectetur adipiscing elit',
                     'sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
                     'Ut enim ad minim veniam',
                     'quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.',
                     'Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.',
                     'Excepteur sint occaecat cupidatat non proident',
                     'sunt in culpa qui officia deserunt mollit anim id est laborum.'
                    ];
    
        return lorem[Math.floor(Math.random() * lorem.length)];
      }
    
      function Message() {
        var messages = [];
        for (let i = 0; i < 5; i++) {
          messages.push({ content: randContent() });
        }
        this.messages = messages;
      }
    });
    <head>
      <base href="https://polygit.org/polymer+1.5.0/components/">
      <script src="webcomponentsjs/webcomponents-lite.min.js"></script>
      <link rel="import" href="paper-button/paper-button.html">
      <link rel="import" href="paper-item/paper-item.html">
      <link rel="import" href="paper-card/paper-card.html">
      <link rel="import" href="iron-list/iron-list.html">
    </head>
    <body>
      <x-foo></x-foo>
    
      <dom-module id="x-foo">
        <template>
          <style>
            paper-card {
              border: solid 1px lightgray;
            }
          </style>
          <iron-list id="list" items=[[publicMessages]]>
            <template>
              <paper-card elevation='2'>
                <template is='dom-repeat' items='[[limitMessages(item.messages.*)]]'>
                  <paper-item>
                    [[item.content]]
                  </paper-item>
                </template>
                <paper-button on-tap='loadFullConversation'>Load entire conversation</paper-button>
              </paper-card>
            </template>
          </iron-list>
        </template>
      </dom-module>
    </body>

    codepen