Using itemsAfterInsert event for a virtual list

Is there a way to get information on the items that were inserted in a similar way to itemBeforeInsert?
I was hoping fragment was going to be an array of items but I’m not really sure how to use this?

on: {
  itemsAfterInsert: function (virtualList, fragment) {
    console.log(fragment);
  }
}

It contains DocumentFragment, you can traverse it as with usual dom node to find its children https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment

Thank you.
Another virtual list related question… Any idea why this wouldn’t work?:

renderItem: function(item) {
  var src = item.image;
  ImgCache.isCached(src, function(path, success) {
    if (success) {                
      ImgCache.getCachedFile(path, function(src, file) {
        var image = file.nativeURL;
        var obj = app.utils.extend(item, {image: image});
        var template = '<li><img src="{{image}}" /></li>';
        return Template7.compile(tmp)(obj);
      });
    } else {
      ImgCache.cacheFile(src, function () {
        var obj = app.utils.extend(item);
        var template = '<li><img src="{{image}}" /></li>';
        return Template7.compile(tmp)(obj);
      });
    }
  });
}

I am able to log the file.nativeURL to the console and it works in terms of local caching but the troubles I’m having are with the virtual list.
I suspect the problem lies with there being a delay in the return of render template.

Because your render function doesn’t return anything. It must have synchronous return statement

I return stuff from inside the nested callbacks, I guess this isn’t synchronous so essentially does nothing.

Exactly this is async call in your case

Going back to my original question again, does this look right to you? I know for a fact the over thirty elements are being inserted into the virtual list but this doesn’t seem to be getting reflected in the fragment.

on: {
  itemsAfterInsert: function (virtualList, fragment) {
    console.log($$(fragment));
  }
}

Essentially what I want to do is access the src for an image in each element that was inserted to the list after they were inserted. How can I traverse it?

<template>
  <div class="page">
    <div class="navbar">
      <div class="navbar-inner sliding">
        <div class="title">Virtual List</div>
      </div>
    </div>
    <div class="page-content">
      <div class="list virtual-list media-list"></div>
    </div>
  </div>
</template>
<script>
  return {
    data:function(){
      var media={
        before:'https://picsum.photos/200?image=1074',
        after:'https://picsum.photos/200?image=1069'
      };
      var items=[];
      for (var i=1;i<=10000;i++){
        items.push({title:'Item '+i,img:media.before});
      }
      return {items:items,media:media,count:-1};
    },
    methods:{
      onItemsAfterInsert:function(obj){
        var self=this;
        //simulate async
        setTimeout(function(){
          for (var k in obj){
            if(Number(k)<=self.count) continue;
            Dom7(obj[k]).find('img').attr('src',self.media.after);
          }
          self.count=k;
        },2000);
      }
    },
    on:{
      pageBeforeRemove:function(){
        this.virtualList.destroy();
      },
      pageInit:function(){
        var self=this;
        self.virtualList=self.$app.virtualList.create({
          el:self.$el.find('.virtual-list'),
          items:self.items,
          itemTemplate:
            '<li><a href="#" class="item-link item-content">\
                <div class="item-media"><img src="{{img}}" width="80"></div>\
                <div class="item-inner">\
                  <div class="item-title-row">\
                    <div class="item-title">{{title}}</div>\
                  </div>\
                </div>\
              </a></li>',
          height:self.$theme.ios?63:73,
          on:{
            itemsAfterInsert:function(l,f){
              self.onItemsAfterInsert(l.domCache);
            }
          }
        });
      }
    }
  }
</script>
1 Like

Hmm, yeah it is happening because this callback called afterInsert so items are moved away from fragment to current DOM. But you can use itemsBeforeInsert for same purpose, checked and it works

@plpl. Thanks! it seemed that virtualList.domCache was what I needed.

itemsAfterInsert: function (virtualList, fragment) {
  console.log(virtualList.domCache);
}

Now to figure out how to force cache these images in localStorage.

@nolimits4web Thanks, I wanted to run the image caching loop after the items were inserted so to minimise the lagging effect for the end user. So using @plpl’s suggestion of virtualList.domCache will hopefully be what I need.

Ah. Actually wait, this won’t work for me.
The object you get back from virtualList.domCache gets incrementally larger as you scroll down through the virtual list; so by the time you get to the bottom it returns the entire list.
I need just the items that were inserted at that phase because I’m adding those images to the image caching and don’t want to waste performance going over images that were already added.

Use itemsBeforeInserted they have same DOM elements as you expect in itemsAfterInserted

I’m actually just trying to do this but I’m seeing the same results as with itemsAfterInsert
From what you’re saying, I’d expect the childElementCount to be 31 each time this event is fired for my list; but there’s nothing.

itemsBeforeInsert: function (virtualList, fragment) {
  debug($$(fragment));
},

I’m using v2.2.0

This is how console.log works. It doesn’t do a snapshow. Try instead:

console.log($$(fragment).children())
1 Like
for (var k in obj){
  // if key is smaller or eq to self.count, than continue;
  // continue means: go to the next key
  if(Number(k)<=self.count) continue;
  // else => change the img-src only to the new inserted items
  Dom7(obj[k]).find('img').attr('src',self.media.after);
}
// increase by the last key
self.count=k;
var count=-1;
var obj={
  0:'1',
  1:'2',
  2:'3',
  3:'4'
};
for(var k in obj){
  if(k<=count) continue;
  console.log(k,obj[k]);
}
count=k;
console.log('done!');


var obj2={
  4:'5',
  5:'6',
  6:'7',
  7:'8'
};
var obj={...obj,...obj2}
for(var k in obj){
  if(k<=count) continue;
  console.log(k,obj[k]);
}
console.log('done!');

@plpl … But this still returns list items starting from index zero that don’t need attention because they were referenced in previous itemsAfterInsert event.

@nolimits4web is there any chance you might be able to fix the fragment return for itemsAfterInsert in the next update.? The reason I really want to hook into this event is because it would handle much smoother for image caching.