[v2] [SOLVED] virtualList and data- attributes changes

Hi,

I am having some issues with use of virtualList and data attributes.
What I am trying to do is a contact list with “badge” on unread messages.

currently I have:

// Dummy contact list
var contact_items = [{
        uid: '1',
        name: 'Ivan Petrov',
        status: 'offline',
        avatar: 'images/user_placeholder_50x50.jpg',
        favorite: 'no',
        unreadmessages: 0
    },
    {
        uid: '2',
        name: 'John Doe',
        status: 'online',
        avatar: 'images/dummy_user_7.jpg',
        favorite: 'no',
        unreadmessages: 2
    }];

var contactList = app.virtualList.create({
    el: '.virtual-list',
    items: contact_items,
    searchAll: function (query, items) {
        var found = [];
        for (var i = 0; i < items.length; i++) {
            if (items[i].name.toLowerCase().indexOf(query.toLowerCase()) >= 0 || query.trim() === '') found.push(i);
        }
        return found; //return array with mathced indexes
    },
    itemTemplate:
    '<li class="swipeout deleted-callback" data-contact-uid="{{uid}}" data-contact-name="{{name}}" data-contact-status="{{status}}" data-contact-favorite="{{favorite}}" data-contact-avatar="{{avatar}}">' +
    '<div class="item-content swipeout-content">' +
    '<div class="item-media {{#if unreadmessages}}cmbadge{{/if}}" data-badge="{{unreadmessages}}">' +
    '<img src="{{avatar}}" class="userprofile e-contact-msg {{status}}">' +
    '</div>' +
    '<div class="item-inner">' +
    '<div class="item-title e-contact-msg">{{name}}</div>' +
    '<div class="item-after">' +
    '<a href="#" class="button list-button e-contact-video">' +
    '<i class="icon f7-icons ios-only">videocam</i>' +
    '<i class="material-icons md-only">videocam</i>' +
    '</a>' +
    '<a href="#" class="button list-button e-contact-audio">' +
    '<i class="icon f7-icons ios-only">call</i>' +
    '<i class="material-icons md-only">call</i>' +
    '</a>' +
    '</div>' +
    '</div>' +
    '</div>' +
    '<div class="swipeout-actions-right">' +
    '<a href="#" class="set-contact-favorite">Favorite</a>'+
    '<a href="#" data-confirm="Are you sure you want to delete this contact?" class="swipeout-delete">Delete</a>' +
    '</div>' +
    '</li>',
    // Item height
    height: app.theme === 'ios' ? 63 : 73
});

// increase badge by 1, add class "cmbadge"
function badgeIncrease(uid) {
    var selector = $$('li[data-contact-uid="'+uid+'"] .item-media');
    contactList.items.forEach(function (value, index) {
        if ( value.uid === uid ) {
            contactList.items[index].unreadmessages = value.unreadmessages + 1;
        }
    });
    selector.addClass("cmbadge");
    contactList.update();
}

// clear badge - remove class "cmbadge" and set unreadmessages to 0
function badgeClear(uid) {
    var selector = $$('li[data-contact-uid="'+uid+'"] .item-media');
    contactList.items.forEach(function (value, index) {
        if ( value.uid === uid ) {
            contactList.items[index].unreadmessages = 0;
        }
    });
    selector.removeClass('cmbadge');
}

Contact list is rendered correctly, but when I try to increase the “unreadmessages” in contactList.items[index_of_contact].unreadmessages it won’t update the attribute “data-badge”.

But meanwhile I can add or remove class “cmbadge” and that works.

Any ideas?

Thanks

This happens because of VL by default (cache: true parameter) will cache already rendered dom elements. To make it rerendered cached items, you need to clear its cache before calling update, like:

contactList.domCache = {}; // reset to empty object
contactList.update(); // and then update

Or you can just diable caching by passing cache: false VL parameter

when settings cache:false, all events on selectors will stop working when after first rendering of VL I do an action that will trigger re-rendering of VL (for example load another view and go back)

also, funny things is in < li > tag of VL I can manipulate “data-” attributes in runtime without problems

This is because you have mixed logic, move all operations then with attributes and classes to the render template which you already have:

{{#if unreadmessages}}cmbadge{{/if}}

And you can delete dom cache for specific item:

function badgeIncrease(uid) {
    var selector = $$('li[data-contact-uid="'+uid+'"] .item-media');
    contactList.items.forEach(function (value, index) {
        if ( value.uid === uid ) {
            delete contactList.domCache[index];
            contactList.items[index].unreadmessages = value.unreadmessages + 1;
        }
    });
    // no need this selector.addClass("cmbadge");
    contactList.update();
}

// clear badge - remove class "cmbadge" and set unreadmessages to 0
function badgeClear(uid) {
    var selector = $$('li[data-contact-uid="'+uid+'"] .item-media');
    contactList.items.forEach(function (value, index) {
        if ( value.uid === uid ) {
            delete contactList.domCache[index];
            contactList.items[index].unreadmessages = 0;
        }
    });
    contactList.update();
    // no need this selector.removeClass('cmbadge');
}

thanks for this solution, it works but problem now is that all selectors and events on them stopped working after calling either badgeIncrease and badgeClear fn.

for example:

$$('.e-contact-msg').on('click', function (e) {

});

won’t work at all, same goes for F7 swipeout funcionality.

if I remove contactList.update() then at least swipeout works on that particular <li> but only delete works, custom button I added won’t work

You shouldn’t rely on such events because it is a Virtual list. Use delegated events instead like:

$(‘.virtual-list’).on(‘click’, ‘.e-contact-msg’, function () {
...
})
3 Likes

THANKS :slight_smile: it works perfect now

Is there a way to know which item i’m clicking on the virtual-list?. For example I have a JSON with “id”.

For example, in your VL item template you need to pass that ID:

<li class="item-content" data-id="{{id}}">

And then in VL click handler:

$('.virtual-list').on('click', 'li', function () {
  var id = $(this).attr('data-id');
  ...
})
3 Likes

I see. I assigned the data-id="{{id}}" but didn’t know how to get it on the click handler. Thanks a lot.

Thank you, I was struggling with it since 2 days :grimacing: