【问题标题】:Seems like ViewModel persists after its View is destroyed in extjs似乎 ViewModel 在其 View 在 extjs 中被销毁后仍然存在
【发布时间】:2015-10-13 12:31:51
【问题描述】:

我确定我在这里遗漏了一些东西,我只是看不到它是什么。

我有我正在用 extjs 6 构建的演示项目。其中我有一个库存项目网格。

Ext.define("InventoryDemo.view.inventory.list.Inventory",{
    extend: "Ext.container.Container",
    xtype: 'inventory',

    requires: [
        "InventoryDemo.view.inventory.list.InventoryController",
        "InventoryDemo.view.inventory.list.InventoryModel"
    ],

    controller: "inventory-inventory",
    viewModel: {
        type: "inventory-inventory"
    },
    closable: true,

    listeners:{
        refreshList: 'onRefreshList'
    },


    layout:{
        type: 'hbox',
        align: 'stretch'
    },
    items:[
        {
            xtype: 'grid',
            flex: 1,

            tbar:[
                {xtype: 'button', text: 'New Item', handler: 'newInventoryItem'}
            ],

            bind:{
                store: '{inventory}'
            },

            listeners:{
                itemclick: 'showDetails'
            },

            columns:[
                { text: 'Name', dataIndex: 'name', flex: 1 },
                { text: 'Price', dataIndex: 'price' },
                { text: 'Active', dataIndex: 'active' },
            ]
        }
    ]
});

当您单击一行时,会创建一个新的详细信息面板,并且选定的记录会链接到它的视图模型,并且它会添加到包含网格的容器视图中。我还想在创建新库存记录时使用相同的详细信息面板,因此我提取了用于创建和编辑的共享逻辑,以便可以在控制器中重用它。

这是列表的控制器:

Ext.define('InventoryDemo.view.inventory.list.InventoryController', {
    extend: 'Ext.app.ViewController',
    alias: 'controller.inventory-inventory',

    config:{
        // holds the newly created detail panel
        detailsPanel: null
    },

    showDetails: function (grid, record, item, index, e, eOpts){
        this.createDetailsPanel();
        this.addTitleToDetailsPanel(record.get('name'));

        // This creates the link in the new detail panel's viewmodel for the
        // selected record. We specifically do NOT do this in the
        // `newInventoryItem`.
        details.getViewModel().linkTo('inventoryitem', record);

        this.addDetailsPanelToView();
    },

    newInventoryItem: function (button, e){
        this.createDetailsPanel();
        this.addTitleToDetailsPanel('New Item');

        // I thought that because the previous panel was destroyed during the
        // `createDetailsPanel` method any previously linked record would not
        // be linked to the new detail panel created and that not linking here
        // would give me an empty detail panel.
        this.addDetailsPanelToView();
    },


    createDetailsPanel: function (){
        if(this.getDetailsPanel() !== null){
            // I'm destroying any previous view here which, as I understand, 
            // would also destroy the the associated ViewController and ViewModel
            // which would also kill any links to the viewmodel
            this.getDetailsPanel().destroy();
        }

        details = Ext.create('InventoryDemo.view.inventory.details.Inventory',{
            session: true,
            listeners:{
                refreshList: 'onRefreshList'
            }
        });
        this.setDetailsPanel(details);
    },

    addDetailsPanelToView: function (){
        this.getView().add(this.getDetailsPanel());
    },

    addTitleToDetailsPanel: function (title){
        this.getDetailsPanel().setTitle("<h3>" + title + "</h3>");
    },

    onRefreshList: function (){
        this.getViewModel().get('inventory').load();
    }
});

正在创建的详细信息面板如下所示:

Ext.define("InventoryDemo.view.inventory.details.Inventory",{
    extend: "Ext.form.Panel",

    requires: [
        "InventoryDemo.view.inventory.details.InventoryController",
        "InventoryDemo.view.inventory.details.InventoryModel"
    ],

    controller: "inventory-details-inventory",
    viewModel: {
        type: "inventory-details-inventory"
    },

    flex: 1,
    closable: true,
    bodyPadding: 10,
    reference: 'inventorydetails',
    defaults:{
        layout: 'anchor',
        anchor: '50%'
    },
    dockedItems:[
        {
            xtype: 'toolbar',
            dock: 'bottom',
            ui: 'footer',
            items:[
                {xtype: 'button', text: 'Update', handler: 'updateRecord'},
                {xtype: 'button', text: 'Delete', handler: 'deleteRecord'}
            ]
        }
    ],

    items:[
        {
            xtype: 'hiddenfield',
            name: '_method',
            value: 'PUT'
        },
        {
            xtype: 'fieldset',
            title: 'IDs',
            collapsible: true,
            defaults:{
                xtype: 'textfield'
            },
            items:[
                {
                    name: 'id',
                    fieldLabel: 'ID',
                    readOnly: true,
                    bind: '{inventoryitem.id}'
                },
                {
                    name: 'brand_id',
                    fieldLabel: 'Brand ID',
                    readOnly: true,
                    bind: '{inventoryitem.brand_id}'
                }
            ]
        },
        {
            xtype: 'fieldset',
            title: 'Details',
            defaults:{
                xtype: 'textfield'
            },
            items:[
                {
                    name: 'name',
                    fieldLabel: 'Name',
                    bind: '{inventoryitem.name}'
                },
                {
                    name: 'price',
                    fieldLabel: 'Price',
                    bind: '{inventoryitem.price}'
                }
            ]
        }
    ]

});

我遇到的问题是,如果我单击一行以查看其详细信息(有效),然后单击 New Item 按钮,则在之前的详细信息面板上加载的记录仍然加载新的细节面板。

如果我首先单击New Item 按钮,我会得到我想要的空白表单,并且如果我选择不同的项目行,则所选行中的每条记录都会正确加载到详细信息面板中(这不是第一行的记录在详细信息面板中“卡住”了),但是一旦我选择了一行,New Item 按钮只会给我以前加载的记录的表单。

在销毁和创建两个单独的视图/视图模型/视图控制器之间,是否有任何东西可以使指向视图模型的链接持续存在(或者我的控制器逻辑中是否存在我没​​有看到的缺陷)?

【问题讨论】:

    标签: extjs mvvm extjs6


    【解决方案1】:

    如果您在详细信息的 viewModel 中唯一需要的是您尝试链接到的这个单一属性,请考虑完全不要为详细信息使用独立的 viewModel。

    当您的详细信息面板位于 inventory 视图的项目中时,它实际上可以自然地访问视图的 viewModel(detailPanel.lookupViewModel() 将返回组件树层次结构中最接近的单个 viewModel)。绑定也应该可以工作。

    但是,如果您需要一个单独的视图模型用于详细信息面板,您可以使用临时 viewModel 配置创建详细信息视图,该配置在实例化时合并到详细信息的视图模型中。

    观点:

    Ext.define('APP.view.TheView',{
        extend: "Ext.container.Container",
        alias: 'widget.theView',
    
        controller: 'theView',
        viewModel: { type: 'theView' },
    
        config: {
            detailConfig: { xtype: 'theDetail', reference: 'detail' }
        },
    
        items: ...
    };
    

    视图的viewController:

    Ext.define('APP.controller.TheView',{
        extend: "Ext.app.ViewController",
        alias: 'controller.theView',
    
        onOpenDetail: function(){
    
            var detail = this.lookupReference('detail');
    
            if(!detail){
    
                var view = this.getView(),
                    detailConfig = view.getDetailConfig(),
                    theProperty = this.getViewModel().get('theProperty');
    
                detailConfig = Ext.apply({
                    viewModel: {
                        // This actually gets correctly merged with whatever there is
                        // in the viewModel configuration of the detail
                        data: { theProperty: theProperty }
                    }
                }, detailConfig));
    
                detail = view.add(detailConfig);
            }
    
            // Do something with the detail instance
        }
    };
    

    还有细节:

    Ext.define('APP.view.TheDetail',{
        extend: "Ext.panel.Panel",
        alias: 'widget.theDetail',
    
        controller: 'theDetail',
        viewModel: { type: 'theDetail' },
    
        items: ...
    };
    

    希望这会有所帮助! :-)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-03-06
      • 1970-01-01
      • 2018-09-18
      • 2023-04-05
      • 1970-01-01
      • 1970-01-01
      • 2021-11-21
      相关资源
      最近更新 更多