【问题标题】:Bind custom component store config to ViewModel store将自定义组件存储配置绑定到 ViewModel 存储
【发布时间】:2016-11-26 12:36:27
【问题描述】:

我正在用 Ext JS 编写一个自定义组件,它需要一个存储作为其配置的一部分。我想把这个 store 保存在组件的 ViewModel 中,并且我也希望它是可绑定的。目前我有这样的代码:

Ext.define('CustomComponent', {
    extend: 'Ext.container.Container',
    xtype: 'customcomponent',
    viewModel: {
        type: 'customcomponent'
    },
    config: {
        store: 'ext-empty-store'
    },
    initComponent: function() {
        var store = Ext.getStore(this.getConfig('store'));
        this.lookupViewModel().set('myStore', store);
        this.callParent(arguments);
    }
});

Ext.define('CustomComponentViewModel', {
    extend: 'Ext.app.ViewModel',
    alias: 'viewmodel.customcomponent',
    data: {
        myStore: null
    }
});

由于多种原因,这并不理想:

  • store 配置选项不可绑定。
  • 商店包含在 ViewModel 的 data 中,而不是 stores 中。这意味着它不能通过 ViewModel 的 getStore 方法访问。

为了使商店可绑定,我可以编写如下代码:

Ext.define('CustomComponent', {
    extend: 'Ext.container.Container',
    xtype: 'customcomponent',
    viewModel: {
        type: 'customcomponent'
    },
    config: {
        store: 'ext-empty-store'
    },
    publishes: 'store'
});

Ext.define('CustomComponentViewModel', {
    extend: 'Ext.app.ViewModel',
    alias: 'viewmodel.customcomponent',
    data: {
        store: null
    },
    formulas: {
        myStore: function(get) {
            return Ext.getStore(get('store'));
        }
    }
});

不过,这也不理想:

  • ViewModel 被store 配置污染,不一定是Ext.data.Store。它可以是商店的 ID 或配置对象。从本质上讲,它是一个实现细节,我希望将它保留在 ViewModel 之外,它会被每个子组件继承。
  • 商店仍然不是 ViewModel 商店配置的一部分,因此仍然无法通过getStore 访问。

基本上,我正在寻找一种方法来设置我的 View 和 ViewModel(以及 ViewController,如果有帮助的话),这样我就可以满足这三个条件:

  • 视图上的store 配置是可绑定的。
  • store 配置选项未保留在 ViewModel 中,或者以某种方式防止污染组件子级的 ViewModel。
  • 可通过getStore 访问 ViewModel 中的商店。

是否有可能同时满足所有这三个条件?如果不是,将可绑定存储配置转换为 ViewModel 存储的最规范方法是什么? Ext JS 源码没有使用 View-ViewModel 架构来定义组件,所以我不能只看他们做了什么。

【问题讨论】:

    标签: javascript extjs data-binding extjs6


    【解决方案1】:

    我相信您可以像这样使用商店。

    Ext.define('CustomComponentViewModel', {
        extend: 'Ext.app.ViewModel',
        alias: 'viewmodel.customcomponent',
        formulas: {
            myStore: function(get) {
                return Ext.getStore(get('store'));
            }
        },
        stores: {
            myStore: {
                fields: [
                    {
                        name: 'id'
                    },
                    {
                        name: 'name'
                    },
                    {
                        name: 'description'
                    }
                ]
            }},
    
    });    
    
    
    Ext.define('CustomComponent', {
        extend: 'Ext.container.Container',
        xtype: 'customcomponent',
        viewModel: {
            type: 'customcomponent'
        },
        config: {
            bind: {
                store: '{myStore}'
            }
        }
    });
    

    【讨论】:

    • 我对你的建议有点困惑。这将如何让商店由组件设置?
    • 我想我可能对您需要什么感到困惑。很高兴你明白了!
    【解决方案2】:

    在更彻底地阅读了 Ext JS 6.0.2 源代码之后,我得出的结论是,如果不覆盖或继承 Ext.app.ViewModel,就不可能满足我想要的所有三个条件。我将逐一介绍标准,然后讨论我认为当前的最佳做法。

    标准

    store 配置必须是可绑定的

    这实际上是默认完成的;所有配置选项都是可绑定的。当我说商店必须是可绑定的时,我的意思是“绑定到store 配置将更新我的 ViewModel 中的商店”。如果publishes 选项设置得当,store 配置的值将被发送到 ViewModel,即publishes: 'store'。这会将store 配置的原始值作为store 发送回ViewModel,但这不是我们想要的。我认为解决此问题的最简洁方法是通过为每个配置选项提供的apply<em>ConfigName</em> 模板方法。这是一个例子:

    Ext.define('CustomComponent', {
        extend: 'Ext.container.Container',
        xtype: 'customcomponent',
        viewModel: {
            type: 'customcomponent'
        },
        config: {
            store: 'ext-empty-store'
        },
        publishes: 'store',
        applyStore: function(store) {
            return Ext.getStore(store);
        }
    });
    

    applyStore 函数将在设置之前应用于store 的值,将其从存储 ID 或配置对象转换为实际存储。这就引出了第二个标准:

    store 配置选项未保留在 ViewModel 中

    通过使用applyStore 模板方法,我们可以将商店配置选项排除在我们的视图模型之外。 (实际上,它甚至将它排除在我们的视图之外!)相反,发布到我们的 ViewModel 的 store 的值是它定义的实际存储。然而不幸的是,发布配置值会将它们添加到 ViewModel 的数据对象中,而不是存储对象中。这将我们带到了最终标准:

    ViewModel 中的存储可通过getStore 访问

    目前无法满足此标准。原因有两个:

    getStore 仅检索通过 stores 配置选项添加的商店

    在 Ext JS 6.0.2 中,getStore 通过在 Ext.app.ViewModel 的 storeInfo 私有属性中查找存储来检索它们。 storeInfo 属性本身是通过 setupStore 私有方法设置的,该方法仅在 stores 配置的每个成员上调用。

    stores 配置选项只允许配置对象

    与Ext.grid.Panel 的store config 不同,Ext.app.ViewModel 的stores config 选项只允许每个store 的值是config 对象;不允许使用商店 ID 和实际商店。直接将值设置为绑定似乎可行,例如:

    Ext.define('CustomComponentViewModel', {
        extend: 'Ext.app.ViewModel',
        alias: 'viewmodel.customcomponent',
        data: {
            dataStore: null
        },
        stores: {
            storeStore: '{dataStore}'
        }
    });
    

    但实际上,storeStore 是一个新的Ext.data.ChainedStore,它配置了source: dataStore。这意味着在storeStore 上设置过滤器和排序器不会影响dataStore,这可能不是我们想要的。

    这两个限制的组合意味着不可能在 ViewModel 中设置可以使用getStore 检索的存储。

    那我该怎么办?

    我认为在可用选项的情况下,最好的做法是放弃使用getStore 检索商店的能力。虽然这是一个令人讨厌的不一致,但它不太可能像允许隐式 ChainedStore 那样导致细微的错误。这给了我们最终的代码:

    Ext.define('CustomComponent', {
        extend: 'Ext.container.Container',
        xtype: 'customcomponent',
        viewModel: {
            type: 'customcomponent'
        },
        config: {
            store: 'ext-empty-store'
        },
        publishes: 'store',
        applyStore: function(store) {
            return Ext.getStore(store);
        }
    });
    
    Ext.define('CustomComponentViewModel', {
        extend: 'Ext.app.ViewModel',
        alias: 'viewmodel.customcomponent',
        data: {
            store: null
        }
    });
    

    【讨论】:

      猜你喜欢
      • 2011-03-17
      • 1970-01-01
      • 1970-01-01
      • 2021-04-14
      • 2014-11-15
      • 1970-01-01
      • 2011-03-23
      • 1970-01-01
      • 2017-10-24
      相关资源
      最近更新 更多