2013-04-15 5 views
6

У меня есть сетка, используемая для отображения информации о счете. Сетка заполняется с использованием магазина счетов-фактур, в хранилище счетов используется модель счета-фактуры, модель счета-фактуры имеет «имеет одну» связь с моделью InvoiceStatus с первичным ключом «id» и foren-ключом «invoice_status_id».EXT JS 4 использовать ассоциацию модели для отображения значения сетки

Проблема

Я не уверен, как сделать дисплей значение столбца счета-фактуры в «управляющей сетке в радиолампе Статуса» использовать Ассоциированный моделей «имя», вставленное в invoice_status_id. Я знаю, что мне нужно создать средство визуализации для этого, но я все равно получаю нулевое значение. Сводка Invoice и InvoiceStatus заполняется правильными значениями.

Статус Колонка Рендер

renderer: function(value, metaData, record, rowIndex, colIndex, store, view) { 
    return record.getStatus().get('name'); 
}, 

магазин Счет

Ext.define('MyApp.store.Invoice', { 
    extend: 'Ext.data.Store', 

    requires: [ 
     'MyApp.model.InvoiceModel' 
    ], 

    constructor: function(cfg) { 
     var me = this; 
     cfg = cfg || {}; 
     me.callParent([Ext.apply({ 
      autoLoad: true, 
      autoSync: true, 
      model: 'MyApp.model.InvoiceModel', 
      remoteSort: true, 
      storeId: 'StoreInvoce', 
      proxy: { 
       type: 'rest', 
       url: '/api/invoice', 
       reader: { 
        type: 'json', 
        root: 'data' 
       } 
      } 
     }, cfg)]); 
    } 
}); 

InvoiceStatus магазин

Ext.define('MyApp.store.InvoiceStatus', { 
    extend: 'Ext.data.Store', 
    alias: 'store.InvoiceStatus', 

    requires: [ 
     'MyApp.model.InvoiceStatus' 
    ], 

    constructor: function(cfg) { 
     var me = this; 
     cfg = cfg || {}; 
     me.callParent([Ext.apply({ 
      autoLoad: true, 
      autoSync: true, 
      model: 'MyApp.model.InvoiceStatus', 
      remoteSort: true, 
      storeId: 'MyJsonStore1', 
      proxy: { 
       type: 'rest', 
       url: '/api/invoice_status', 
       reader: { 
        type: 'json', 
        root: 'data' 
       } 
      } 
     }, cfg)]); 
    } 
}); 

Счет Модель

Ext.define('MyApp.model.InvoiceModel', { 
    extend: 'Ext.data.Model', 

    uses: [ 
     'MyApp.model.InvoiceStatus' 
    ], 

    fields: [ 
     { 
      mapping: 'id', 
      name: 'id', 
      type: 'int' 
     }, 
     { 
      mapping: 'client_id', 
      name: 'client_id', 
      type: 'int' 
     }, 
     { 
      mapping: 'client_name', 
      name: 'client_name', 
      type: 'string' 
     }, 
     { 
      dateFormat: 'Y-m-d', 
      dateReadFormat: '', 
      mapping: 'issue_date', 
      name: 'issue_date', 
      sortType: 'asDate', 
      type: 'date' 
     }, 
     { 
      dateFormat: 'Y-m-d', 
      mapping: 'due_date', 
      name: 'due_date', 
      sortType: 'asDate', 
      type: 'date' 
     }, 
     { 
      mapping: 'payment_date', 
      name: 'payment_date', 
      sortType: 'asDate', 
      type: 'date', 
      useNull: true 
     }, 
     { 
      name: 'amount' 
     }, 
     { 
      mapping: 'invoice_status_id', 
      name: 'invoice_status_id', 
      sortType: 'asInt', 
      type: 'int' 
     } 
    ], 

    hasOne: { 
     model: 'MyApp.model.InvoiceStatus', 
     foreignKey: 'invoice_status_id', 
     getterName: 'getStatus' 
    } 
}); 

InvoiceStatus Модель

Ext.define('MyApp.model.InvoiceStatus', { 
    extend: 'Ext.data.Model', 

    fields: [ 
     { 
      mapping: 'id', 
      name: 'id', 
      type: 'int' 
     }, 
     { 
      mapping: 'name', 
      name: 'name', 
      type: 'string' 
     } 
    ] 
}); 

Счет Сетка

Ext.define('MyApp.view.ApplicationViewport', { 
    extend: 'Ext.container.Viewport', 

    requires: [ 
     'MyApp.view.ClearTriggerField' 
    ], 

    layout: { 
     type: 'border' 
    }, 

    initComponent: function() { 
     var me = this; 

     Ext.applyIf(me, { 
      items: [ 
       { 
        xtype: 'header', 
        region: 'north', 
        height: 100, 
        items: [ 
         { 
          xtype: 'image', 
          height: 100, 
          width: 250, 
          alt: 'Logo', 
          src: 'images/logo.gif', 
          title: 'Logo' 
         } 
        ] 
       }, 
       { 
        xtype: 'container', 
        region: 'center', 
        layout: { 
         type: 'card' 
        }, 
        items: [ 
         { 
          xtype: 'container', 
          width: 150, 
          layout: { 
           type: 'border' 
          }, 
          items: [ 
           { 
            xtype: 'gridpanel', 
            collapseMode: 'mini', 
            region: 'west', 
            split: true, 
            autoRender: false, 
            maxWidth: 300, 
            width: 250, 
            bodyBorder: false, 
            animCollapse: false, 
            collapsed: false, 
            collapsible: true, 
            hideCollapseTool: true, 
            overlapHeader: false, 
            titleCollapse: true, 
            allowDeselect: true, 
            columnLines: false, 
            forceFit: true, 
            store: 'ClientDataStor', 
            dockedItems: [ 
             { 
              xtype: 'toolbar', 
              dock: 'top', 
              items: [ 
               { 
                xtype: 'cleartrigger' 
               }, 
               { 
                xtype: 'tbfill' 
               }, 
               { 
                xtype: 'button', 
                icon: '/images/settings.png' 
               } 
              ] 
             } 
            ], 
            columns: [ 
             { 
              xtype: 'templatecolumn', 
              tpl: [ 
               '<img class="pull-left client-menu-image" src="/images/{type}.png"><div class="client-menu-name">{name}</div><div class="client-menu-type">{type}</div>' 
              ], 
              dataIndex: 'id', 
              text: 'Client' 
             } 
            ], 
            selModel: Ext.create('Ext.selection.RowModel', { 

            }), 
            plugins: [ 
             Ext.create('Ext.grid.plugin.BufferedRenderer', { 

             }) 
            ] 
           }, 
           { 
            xtype: 'gridpanel', 
            region: 'center', 
            title: 'Invoices', 
            titleCollapse: false, 
            forceFit: true, 
            store: 'Invoice', 
            columns: [ 
             { 
              xtype: 'numbercolumn', 
              maxWidth: 120, 
              minWidth: 50, 
              dataIndex: 'id', 
              groupable: false, 
              lockable: true, 
              text: 'ID', 
              tooltip: 'Invoice ID', 
              format: '0' 
             }, 
             { 
              xtype: 'numbercolumn', 
              hidden: true, 
              maxWidth: 120, 
              minWidth: 50, 
              dataIndex: 'client_id', 
              groupable: true, 
              text: 'Client ID', 
              format: '0' 
             }, 
             { 
              xtype: 'gridcolumn', 
              renderer: function(value, metaData, record, rowIndex, colIndex, store, view) { 
               return record.getStatus().get('name'); 
              }, 
              maxWidth: 200, 
              minWidth: 100, 
              dataIndex: 'invoice_status_id', 
              text: 'Status' 
             }, 
             { 
              xtype: 'datecolumn', 
              maxWidth: 200, 
              minWidth: 100, 
              dataIndex: 'issue_date', 
              text: 'Issue Date', 
              format: 'd M Y' 
             }, 
             { 
              xtype: 'datecolumn', 
              maxWidth: 200, 
              minWidth: 100, 
              dataIndex: 'due_date', 
              text: 'Due Date', 
              format: 'd M Y' 
             }, 
             { 
              xtype: 'datecolumn', 
              maxWidth: 200, 
              minWidth: 100, 
              dataIndex: 'payment_date', 
              text: 'Payment Date', 
              format: 'd M Y' 
             }, 
             { 
              xtype: 'templatecolumn', 
              summaryType: 'sum', 
              maxWidth: 150, 
              minWidth: 50, 
              tpl: [ 
               '${amount}' 
              ], 
              defaultWidth: 80, 
              dataIndex: 'amount', 
              groupable: true, 
              text: 'Amount' 
             } 
            ], 
            features: [ 
             { 
              ftype: 'grouping' 
             } 
            ] 
           } 
          ] 
         } 
        ] 
       } 
      ] 
     }); 

     me.callParent(arguments); 
    } 

}); 
+0

Я также пробовал это в моем рендерере столбца store.getAt (rowIndex) .getStatus(). Get ('name'); –

ответ

10

Мне удалось найти работу по взаимодействию, используя функцию обратного вызова, но оказалось, что намного проще просто выполнить поиск из магазина.

Шаг первый

Я переехал прокси из магазина InvoiceStatus и на модели InvoiceStatus и сделал магазин автозагрузку InvoiceStatus.

Шаг второго

Я изменил метод визуализации столбца состояния для запроса отображаемого имени из магазина InvoiceStatus как так.

renderer: function(value, metaData, record, rowIndex, colIndex, store, view) { 
    var store = Ext.data.StoreManager.lookup('InvoiceStatus'); 
    return store.getById(value).get('name'); 
}, 

Это оказалось гораздо более симпатичным решением.

+0

хороший обходной путь! Благодарю. Obs: не забудьте проверить нули, чтобы избежать ошибок, например: if (value && value> 0) {/*...*/} –

3

Похоже, что вам нужно установить belongsTo ассоциацию на InvoiceStatus чи ld. Вы могли бы подумать, что определение ассоциации в одном направлении автоматически создало бы ассоциацию в другом направлении, но, по-видимому, это не так, и вы должны определить связь как с родителями, так и с детьми. См. Здесь, чтобы получить более подробное объяснение: Why isn't my ExtJS Store Association Working

+0

Спасибо, Джеймс, это было частью ответа. Реальная проблема заключалась в том, что мой связанный магазин был json-магазином, и ему нужно было загрузить, прежде чем стоимость может быть одета из него. Это потребовало метода обратного вызова в качестве части функции рендеринга, что было сделано для процесса беспорядочной загрузки, и я основал поиск более простого метода визуализации значений поиска. См. Мой ответ. –

3

Ваш hasOne должен быть таким:

hasOne: { 
    name:   'status', 
    instanceName: 'status', 
    associationKey: 'status', 
    model:   'MyApp.model.InvoiceStatus', 
    foreignKey:  'invoice_status_id', 
    getterName:  'getStatus', 
    setterName:  'setStatus' 
} 

Следующий патч для ExtJS 4.2.2 позволит вам установить dataIndex: 'status.name' без каких-либо дополнительных рендеров. Сетка отобразит все в порядке, но сортировка не будет работать.

Это решение не работает с асинхронной (ленивой) загрузкой состояния.

Ext.view.Table.prototype.renderCell = function(column, record, recordIndex, rowIndex, columnIndex, out) { 
    var me = this, 
     selModel = me.selModel, 
     cellValues = me.cellValues, 
     classes = cellValues.classes, 
     // fieldValue = record.data[column.dataIndex]; // patched 
     fieldValue = null, 
     cellTpl = me.cellTpl, 
     fullIndex, value, clsInsertPoint; 

    // Patch start 
    if (column.dataIndex && column.dataIndex.indexOf('.') > 0) { 
     var associationParts = column.dataIndex.split('.'), 
      v = record; 

     for (var i = 0; i < associationParts.length-1; i++) { 
      v = v['get' + associationParts[i].charAt(0).toUpperCase() + associationParts[i].slice(1)](); 
     } 
     fieldValue = v.get(associationParts[associationParts.length-1]); 
    } 
    else { 
     fieldValue = record.data[column.dataIndex]; 
    } 
    // Patch end 

    cellValues.record = record; 
    cellValues.column = column; 
    cellValues.recordIndex = recordIndex; 
    cellValues.rowIndex = rowIndex; 
    cellValues.columnIndex = columnIndex; 
    cellValues.cellIndex = columnIndex; 
    cellValues.align = column.align; 
    cellValues.tdCls = column.tdCls; 
    cellValues.innerCls = column.innerCls; 
    cellValues.style = cellValues.tdAttr = ""; 
    cellValues.unselectableAttr = me.enableTextSelection ? '' : 'unselectable="on"'; 

    if (column.renderer && column.renderer.call) { 
     fullIndex = me.ownerCt.columnManager.getHeaderIndex(column); 
     value = column.renderer.call(column.scope || me.ownerCt, fieldValue, cellValues, record, recordIndex, fullIndex, me.dataSource, me); 
     if (cellValues.css) { 
      // This warning attribute is used by the compat layer 
      // TODO: remove when compat layer becomes deprecated 
      record.cssWarning = true; 
      cellValues.tdCls += ' ' + cellValues.css; 
      delete cellValues.css; 
     } 
    } else { 
     value = fieldValue; 
    } 
    cellValues.value = (value == null || value === '') ? '&#160;' : value; 

    // Calculate classes to add to cell 
    classes[1] = column.getCellId(); 

    // On IE8, array[len] = 'foo' is twice as fast as array.push('foo') 
    // So keep an insertion point and use assignment to help IE! 
    clsInsertPoint = 2; 

    if (column.tdCls) { 
     classes[clsInsertPoint++] = column.tdCls; 
    } 
    if (me.markDirty && record.isModified(column.dataIndex)) { 
     classes[clsInsertPoint++] = me.dirtyCls; 
    } 
    if (column.isFirstVisible) { 
     classes[clsInsertPoint++] = me.firstCls; 
    } 
    if (column.isLastVisible) { 
     classes[clsInsertPoint++] = me.lastCls; 
    } 
    if (!me.enableTextSelection) { 
     classes[clsInsertPoint++] = me.unselectableCls; 
    } 
    if (cellValues.tdCls) { 
     classes[clsInsertPoint++] = cellValues.tdCls; 
    } 
    if (selModel && selModel.isCellModel && selModel.isCellSelected(me, recordIndex, columnIndex)) { 
     classes[clsInsertPoint++] = (me.selectedCellCls); 
    } 

    // Chop back array to only what we've set 
    classes.length = clsInsertPoint; 

    cellValues.tdCls = classes.join(' '); 

    cellTpl.applyOut(cellValues, out); 

    // Dereference objects since cellValues is a persistent var in the XTemplate's scope chain 
     cellValues.column = null; 
}; 
Смежные вопросы