Search code examples
extjs4

ExtJS: dataview itemSelector pointing to child element


I want to use dataview to render the following hierarchy data:

[{
  id: 1,
  name: 'Parent #1',
  children: [ { id: 11, name: 'Child 1.1' }, { id: 12, name: 'Child 1.2' }]
 },
 {
  id: 1,
  name: 'Parent #1',
  children: [ { id: 21, name: 'Child 2.1' }, { id: 22, name: 'Child 2.2' }]
}]

in the form of:

Parent #1    <- div with class = x-title
 Child 1.1  <- div with class = x-list-item
 Child 1.2 
Parent #2
 Child 2.1
 Child 2.2

My dataview tpl configured like this:

  ...
  trackOver: true,
  tpl: new Ext.XTemplate( 
    '<tpl for=".">',
'<div class="x-title">{name}</div>',
    '<tpl for="children">',
    '<div class="x-list-item">{name}</div>',
    '</tpl>',
'</tpl>'
  ),
  ...

Here is the problem:

  1. itemSelector: 'x-list-item' not working Cannot read property 'internalId' of undefined
  2. itemSelector: 'x-title' work!

I wonder if it possible at all to support itemSelector which point to children element instead of root level?


Solution

  • It is possible after extending DataView a bit.

    Example code:

    Ext.create('Ext.Panel', {
        id: 'images-view',
        frame: true,
        collapsible: true,
        width: 535,
        renderTo: 'dataview-example',
        title: 'Simple DataView (0 items selected)',
        items: Ext.create('Ext.view.View', {
            store: store,
            tpl: new Ext.XTemplate( 
                '<tpl for=".">',
                    '<div class="x-item x-title">{name}</div>',
                    '<tpl for="children">',
                        '<div class="x-item x-item-child">{name}</div>',
                    '</tpl>',
                '</tpl>'
            ),
            multiSelect: true,
            height: 310,
            trackOver: true,
            overItemCls: 'x-item-over',
            itemSelector: '.x-item',
            emptyText: 'No images to display',
    
            onItemSelect: function(record) {
                var node = this._selectedNode; //this.getNode(record);
    
                if (node) {
                    Ext.fly(node).addCls(this.selectedItemCls);
                }
            },
    
            onItemDeselect: function(record) {
                var node = this._deselectedNode; //this.getNode(record);
    
                if (node) {
                    Ext.fly(node).removeCls(this.selectedItemCls);
                }
            },
    
            processItemEvent: function(record, item, index, e) {
                if (e.type == "mousedown" && e.button == 0) {
                    this._deselectedNode = this._selectedNode;
                    this._selectedNode = item;
                    console.log(item.innerHTML);
                }
            },
    
            updateIndexes : function(startIndex, endIndex) {
                var ns = this.all.elements,
                    records = this.store.getRange(),
                    i, j;
    
                startIndex = startIndex || 0;
                endIndex = endIndex || ((endIndex === 0) ? 0 : (ns.length - 1));
                for(i = startIndex, j = startIndex - 1; i <= endIndex; i++){
                    if (!Ext.fly(ns[i]).is('.x-item-child')) {
                        j++;
                    }
    
                    ns[i].viewIndex = i;
    
                    ns[i].viewRecordId = records[j].internalId;
                    if (!ns[i].boundView) {
                        ns[i].boundView = this.id;
                    }
                }
            }
        })
    });
    

    Working sample: http://jsfiddle.net/fU9De/

    But it's easy to achieve without modifying DataView by only changing data layout in that way children are separated records. For example:

    [
        {
            id: 1,
            name: 'Parent #1',
            children: [ 11, 12 ]
        },
        { id: 11, name: 'Child 1.1', parentId: 1 }, 
        { id: 12, name: 'Child 1.2', parentId: 1 },
        {
            id: 2,
            name: 'Parent #2',
            children: [ 21, 22 ]
        },
        { id: 21, name: 'Child 2.1', parentId: 2 }, 
        { id: 22, name: 'Child 2.2', parentId: 2 }
    ]
    

    Then you can change template to:

    new Ext.XTemplate( 
        '<tpl for=".">',
            '<div class="x-item x-title {[!!values.parentId ? "x-item-child" : "x-item-parent"]}">{name}</div>',
        '</tpl>'
    ),
    

    and you'll have working selection out-of-box.