当需要父视图模型时,Extjs 使用子视图模型数据
Extjs uses child-viewmodel data when parent-viewmodel is desired
考虑这样的片段(可以是 运行 在 https://fiddle.sencha.com/,并在右上角的组合框中选择经典而不是现代):
Ext.define('ReusableComponent', {
xtype: 'reusable',
extend: 'Ext.Container',
config: {
foo: 'Foo'
},
updateFoo: function(foo) {
this.getViewModel().set('foo', foo);
},
viewModel: {
data: {
foo: 'Foo'
}
},
items: [{
bind: {
html: 'foo = {foo}'
}
}]
});
Ext.define('ConcreteComponent', {
extend: 'Ext.panel.Panel',
viewModel: {
data: {
foo: 'Bar'
}
},
layout: 'fit',
items: [{
xtype: 'reusable',
bind: {
foo: '{foo}'
}
}]
});
Ext.application({
name : 'Fiddle',
launch : function() {
Ext.create('ConcreteComponent', {
renderTo: Ext.getBody(),
title: 'ConcreteComponent',
width: 200,
height: 200
});
}
});
梦想是有一个可重用的组件,它有一个定义的外部接口,知道它就足够了。使用该组件的人不必了解其内部结构。在这个例子中,外部接口是普通配置,它继承自 Ext.Container(如 width/height/etc)和 foo
config.
所以说我然后尝试在 ConcreteComponent 中使用它。我知道可重用组件具有配置 foo,因此我应该能够将它绑定到我自己的视图模型,这就是我所做的。然而,这不起作用,它显示 foo = Foo
,而不是(预期的)foo = Bar
。原因似乎很清楚——我 不知不觉地 使用了子视图模型中已经存在的名称,而 extjs 选择了它而不是我在 ConcreteComponent 中定义的名称。如何解决这个问题也很清楚(例如,在 ConcreteComponent 中,将视图模型数据 属性 从 foo
重命名为 foo2
)。 但这迫使我们了解该可重用组件的内部结构,而不仅仅是它的 public 接口 。无论如何要解决这个问题?或者无论如何都应该将子视图模型始终视为其 public 界面的一部分?
看起来解决方案是简单地在私有 属性 下手动创建视图模型(这打破了视图模型的子父链 extjs 在组件的视图模型及其容器的视图模型 https://docs.sencha.com/extjs/6.2.0/classic/Ext.Component.html#cfg-viewModel), and pass it to reusable component's children explicitly via viewModel config. Using defaults
seems to work fine. I saw the solution when stumbling upon color picker's source code https://docs.sencha.com/extjs/6.2.0/classic/src/Selector.js.html 之间创建。这里是问题的固定码
Ext.define('ReusableComponent', {
xtype: 'reusable',
extend: 'Ext.Container',
config: {
foo: 'Foo'
},
updateFoo: function(foo) {
this.childViewModel.set('foo', foo);
},
constructor: function() {
this.childViewModel = Ext.create('Ext.app.ViewModel', {
data: {
foo: 'Foo'
}
});
this.defaults = {
viewModel: this.childViewModel
};
this.callParent(arguments);
},
items: [{
bind: {
html: 'foo = {foo}'
}
}]
});
Ext.define('ConcreteComponent', {
extend: 'Ext.panel.Panel',
viewModel: {
data: {
foo: 'Bar'
}
},
layout: 'fit',
items: [{
xtype: 'reusable',
bind: {
foo: '{foo}'
}
}]
});
Ext.application({
name : 'Fiddle',
launch : function() {
Ext.create('ConcreteComponent', {
renderTo: Ext.getBody(),
title: 'ConcreteComponent',
width: 200,
height: 200
});
}
});
考虑这样的片段(可以是 运行 在 https://fiddle.sencha.com/,并在右上角的组合框中选择经典而不是现代):
Ext.define('ReusableComponent', {
xtype: 'reusable',
extend: 'Ext.Container',
config: {
foo: 'Foo'
},
updateFoo: function(foo) {
this.getViewModel().set('foo', foo);
},
viewModel: {
data: {
foo: 'Foo'
}
},
items: [{
bind: {
html: 'foo = {foo}'
}
}]
});
Ext.define('ConcreteComponent', {
extend: 'Ext.panel.Panel',
viewModel: {
data: {
foo: 'Bar'
}
},
layout: 'fit',
items: [{
xtype: 'reusable',
bind: {
foo: '{foo}'
}
}]
});
Ext.application({
name : 'Fiddle',
launch : function() {
Ext.create('ConcreteComponent', {
renderTo: Ext.getBody(),
title: 'ConcreteComponent',
width: 200,
height: 200
});
}
});
梦想是有一个可重用的组件,它有一个定义的外部接口,知道它就足够了。使用该组件的人不必了解其内部结构。在这个例子中,外部接口是普通配置,它继承自 Ext.Container(如 width/height/etc)和 foo
config.
所以说我然后尝试在 ConcreteComponent 中使用它。我知道可重用组件具有配置 foo,因此我应该能够将它绑定到我自己的视图模型,这就是我所做的。然而,这不起作用,它显示 foo = Foo
,而不是(预期的)foo = Bar
。原因似乎很清楚——我 不知不觉地 使用了子视图模型中已经存在的名称,而 extjs 选择了它而不是我在 ConcreteComponent 中定义的名称。如何解决这个问题也很清楚(例如,在 ConcreteComponent 中,将视图模型数据 属性 从 foo
重命名为 foo2
)。 但这迫使我们了解该可重用组件的内部结构,而不仅仅是它的 public 接口 。无论如何要解决这个问题?或者无论如何都应该将子视图模型始终视为其 public 界面的一部分?
看起来解决方案是简单地在私有 属性 下手动创建视图模型(这打破了视图模型的子父链 extjs 在组件的视图模型及其容器的视图模型 https://docs.sencha.com/extjs/6.2.0/classic/Ext.Component.html#cfg-viewModel), and pass it to reusable component's children explicitly via viewModel config. Using defaults
seems to work fine. I saw the solution when stumbling upon color picker's source code https://docs.sencha.com/extjs/6.2.0/classic/src/Selector.js.html 之间创建。这里是问题的固定码
Ext.define('ReusableComponent', {
xtype: 'reusable',
extend: 'Ext.Container',
config: {
foo: 'Foo'
},
updateFoo: function(foo) {
this.childViewModel.set('foo', foo);
},
constructor: function() {
this.childViewModel = Ext.create('Ext.app.ViewModel', {
data: {
foo: 'Foo'
}
});
this.defaults = {
viewModel: this.childViewModel
};
this.callParent(arguments);
},
items: [{
bind: {
html: 'foo = {foo}'
}
}]
});
Ext.define('ConcreteComponent', {
extend: 'Ext.panel.Panel',
viewModel: {
data: {
foo: 'Bar'
}
},
layout: 'fit',
items: [{
xtype: 'reusable',
bind: {
foo: '{foo}'
}
}]
});
Ext.application({
name : 'Fiddle',
launch : function() {
Ext.create('ConcreteComponent', {
renderTo: Ext.getBody(),
title: 'ConcreteComponent',
width: 200,
height: 200
});
}
});