ExtJs父子组件之间的双向绑定

4
我有两个组件:一个面板和一个自定义文本框。
面板有一个视图模型,我想将该视图模型中的一个值(称为testData)绑定到自定义文本框的属性(称为test)。
基本上这样可以正常工作,但是当文本框的test属性更改时,面板的视图模型中的testData没有相应地更新。我的意思是,当子元素(文本框)的test属性被修改时,面板的视图模型中的testData属性应该包含与test相同的值,就像普通的双向绑定一样。
我不确定我做错了什么,但是这是我迄今为止尝试过的:https://fiddle.sencha.com/#fiddle/20pu&view/editor
Ext.define('MyMain', {
    extend: 'Ext.panel.Panel',
    alias: 'widget.main',

    width: '100%',
    bodyPadding: 10,

    viewModel: {
        data: {
            testData: 'Example Data'
        }
    },

    bind: {
        title: '{testData}'
    },

    items: {
        xtype: 'myField',
        bind: {
            test: '{testData}'
        }
    }
})

Ext.define('MyField', {
    extend: 'Ext.form.field.Text',
    alias: 'widget.myField',
    fieldLabel: 'Data',
    width: '100%',

    config: {
        test: null // when test is changed, it should also affect the {testData} bind of the main component, causing the title to change
    },

    setTest(value) {
        this.test = value + ' modified!' // because of the bind, this /should/ automatically get appied to the viewmodel's `testData` and thus to the panel title
        this.setValue(this.test) // whenever the `test` property is changed, we write the contents to the value of the text field (just to visualize the `test` property).
        // But as you can see, the panel title will still just say `Example Data` and not `Example Data modified!` as it should.
    },
    getTest(){
        return this.test
    }
})

Ext.application({
    name : 'Fiddle',

    launch : function() {
        Ext.create('Ext.container.Viewport', {
            items: [{
                xtype: 'main'
            }]
        })
    }
})

首先,config作为默认值存在,您可以使用参数test创建组件,该参数将覆盖test中的默认值。 - Edwin
1
如果配置值只能从父组件设置一次,那么这并不重要。我的主要问题是更改测试值不会影响父组件的视图模型属性。有什么想法可以解决吗? - Forivin
1
你的父级中没有任何名为 test 的内容,只有一个名为 testData 的内容。 - Edwin
是的,我想连接这两个组件,以便在子组件中更改“test”会更改父视图模型中的“testData”。 - Forivin
但你没有像那样明确表达问题,这是具有误导性的。我会看一下。 - Edwin
4个回答

1
如果您想在更改 Textfield 的同时更改标题,则必须绑定 value 属性,因为更改文本字段的值仅会更改字段的值属性。
 bind: {
            test: '{testData}',
            value : '{testData}'
        },

如果您不想将其绑定到值,则在 change 事件上,您必须设置 test 属性的值。
listeners : {
                change : function(field, newValue, oldValue, eOpts ){
                    field.setTest(newValue);
                }
            }

请参考fiddle

1

更新: (在阅读了您对其他答案的评论后)

通常情况下,在config块中提及属性并将其包含在publishes中,将使任何属性具有双向绑定。

ExtJS会为其生成getter和setter方法。setter方法负责绑定。现在,每当有人使用setter更新属性值时,新值将传递到绑定的viewModel,然后传递到其他组件。

直接访问属性:this.testthis.viewModel.data.testData并对它们赋值将不会反映在绑定到此属性的控件中。

如果您正在为已发布属性的setter函数(setTest)提供实现,请确保从中调用this.callParent(...)

使用字段的value属性来显示test的内容导致了早期的混淆。这里有一个fiddle,其中包含具有双向可绑定test属性的MyField类中没有任何特殊处理的内容。
点击“获取测试”按钮,值应为“Example Data”(来自viewModel)。
“设置测试数据”按钮将更新viewModel中的值。再次使用“获取测试”按钮验证test的值是否已更新。
“设置测试”按钮将向字段的test属性分配新值,并反映在面板的标题中。

请看这个forked fiddle

在你的实现中,setTest方法直接将this.test的值更改为value + ' modified!'。这不会更新viewModel中testData的值,因为绑定是通过实现在配置中指定的属性的getter和setter函数来工作的。


0
首先,您需要使test配置twoWayBindable

此对象保存将更新其绑定的配置属性映射。

其次,在您的情况下,您不需要为config对象定义getter和setter方法。

如果类没有明确定义这些方法,则在类创建期间,每个配置项都将自动在类原型内生成其自己的setter和getter方法。

您可能需要这样做,但它会覆盖负责更新绑定等内容的默认方法。
通过标准化这个常见模式,生成的默认setter提供了两个额外的模板方法,你可以将自己的自定义逻辑放入其中,即:一个“applyFoo”和一个“updateFoo”方法用于“foo”配置项,在实际设置值之前和之后分别执行。 twoWayBindable配置依赖于更新模板方法,当您指定自己的setter时,更新方法将永远不会被调用,绑定也不会被更新。
换句话说,当利用配置特性时,您大多数情况下不需要显式地定义setter和getter方法。相反,应在必要时实现“apply”和“update”方法。
因此,在您的示例中,您需要执行以下步骤:
  1. 删除 setTestgetTest 方法声明。
  2. 添加包含 testtwoWayBindable 配置。

    twoWayBindable: ['test']`
    
  3. 将任何其他逻辑连接到 applyTestupdateTest 模板方法中。例如,在设置测试值后更新字段值。

    updateTest(testValue) {
        this.setValue(testValue)
    }
    

这里是可工作的 fiddle: https://fiddle.sencha.com/#fiddle/20rs&view/editor


似乎不能解决问题。当文本字段更改时,面板的标题应该获得与文本字段相同的值。每当文本属性更改时,面板的标题应简单地与文本字段的测试属性同步。 - Forivin
当文本字段被更改时,它的“value”会改变,而不是“test”配置。我以为你的“test”配置在其他地方被更改了。你为什么需要“test”配置呢?为什么不只是将“testData”绑定到“value”上呢?这里是链接:https://fiddle.sencha.com/#fiddle/20se&view/editor - scebotari66
测试属性是整个重点。我非常清楚值的双向绑定是如何工作的。实际上,我甚至不关心值属性本身,我只是利用它来可视化测试属性的内容。 - Forivin
@Forivin 好的!关于将“test”值反映到面板标题上,我认为我的答案已经涵盖了这一点。当您按下按钮并且“test”值更改时,标题会更新。现在您说“当文本字段更改时,面板的标题应该获得与文本字段相同的值。”但是当字段更改时,它的“value”配置也会更改。您能否请更新您的问题,更详细地解释“test”和“value”之间的关系?“value”是否应该更新“test”? - scebotari66
好的,我更新了问题。希望现在更清楚了。 - Forivin

0
  1. 为了能够绑定自定义类属性,您需要在twoWayBindable配置中列出这些属性。
  2. 不要修改要设置的值,并且不要递归调用setter。最好编写一个update<Fieldname>()函数。它们用于处理视图中的更新,通常不会修改数据结构。
  3. 基于2.):重写表单字段的视图更新函数以捕获对值所做的更改。

这是完整的fiddle: https://fiddle.sencha.com/#fiddle/218m&view/editor

这里有一些需要注意的事项:

  • 3秒后,ViewModel testData的值将被更新
  • 6秒后,将调用字段的setTest() setter
  • 9秒后,将触发您输入字段的setValue()方法
  • 最后,您可以更改输入字段的值以更改面板标题

这是为了说明各种情况。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接