I have two ponents: A panel and a custom text field.
The panel has a viewmodel and I want to bind a value (called testData
) from that viewmodel to a property (called test
) of the custom text field.
That works fine ...basically.
But when the test
property of the text field is changed, the testData
in the viewmodel of the panel does not update accordingly. I mean when the test
property of the child element (the textfield) is modified, the testData
property of the panel's viewmodel should contain the same value that is in test
, just like a normal two-way bind.
I'm not sure what I'm doing wrong, but here is what I've tried to far: ;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 ponent, 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'
}]
})
}
})
I have two ponents: A panel and a custom text field.
The panel has a viewmodel and I want to bind a value (called testData
) from that viewmodel to a property (called test
) of the custom text field.
That works fine ...basically.
But when the test
property of the text field is changed, the testData
in the viewmodel of the panel does not update accordingly. I mean when the test
property of the child element (the textfield) is modified, the testData
property of the panel's viewmodel should contain the same value that is in test
, just like a normal two-way bind.
I'm not sure what I'm doing wrong, but here is what I've tried to far: https://fiddle.sencha./#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 ponent, 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'
}]
})
}
})
Share
Improve this question
edited Jun 6, 2017 at 7:21
Forivin
asked Jun 2, 2017 at 11:17
ForivinForivin
15.6k30 gold badges118 silver badges212 bronze badges
5
-
first of all the
config
is there as a default value and you create your ponent with a parametertest
which will overrule the default value intest
. – Edwin Commented Jun 2, 2017 at 11:47 - 1 It wouldn't really matter if the config value could only be set once from the parent ponent. My main problem is that changing the test value doesn't affect the viewmodel property of the parent ponent. Any ideas how that could be solved? – Forivin Commented Jun 2, 2017 at 11:55
-
1
you don't have any
test
in the parent..only atestData
– Edwin Commented Jun 2, 2017 at 11:58 -
Yes, well, I want to connect the two so that changing
test
in the child ponent changes 'testData' in the parent's viewmodel. – Forivin Commented Jun 2, 2017 at 12:00 - but you didn't formulate the question like that, that's misleading. I will have a look. – Edwin Commented Jun 2, 2017 at 13:07
4 Answers
Reset to default 1 +50Update: (after reading your ments on other answers)
In general, mentioning the property in the config
block and include it in publishes
will make any property two-way bindable.
ExtJS will generate the getter and setter methods for it. The setter method takes care of binding. Now, whenever anyone updates the property value (using the setter), the new value will be passed on to the bound viewModel and in turn to the other ponents.
Accessing the property directly, this.test
or this.viewModel.data.testData
and assigning values to them will not be reflected in the controls bound to this property.
In case you are providing an implementation for the setter function (setTest
) of a published property, ensure that this.callParent(...)
gets called from it.
The usage of field's value
property to display the contents of test
caused the earlier confusion. Here is a fiddle with two-way bindable test
property without any special handling in the MyField
class.
Click on the 'Get test' button, the value should be 'Example Data' (from viewModel).
'Set testData' button will update the value in the viewModel. Use the 'Get test' button again to verify that the value of test
has also been updated.
'Set test' button assigns a new value to the field's test
property and this will be reflected in the panel's title.
Have a look at this forked fiddle.
In your implementation, the setTest
method is directly changing the value of this.test
to value + ' modified!'
. This will not update the value of testData
in viewModel as binding works via the getter and setter functions implemented of the properties specified in the config.
If you want to change title while changing Textfield
then you have to bind value
property because changing textfield's value only changes value property of field.
bind: {
test: '{testData}',
value : '{testData}'
},
If you don't want to bind it with value then on change
event you have to set value of test
property.
listeners : {
change : function(field, newValue, oldValue, eOpts ){
field.setTest(newValue);
}
}
Please refer fiddle.
First of all, you need to make the test
config twoWayBindable.
This object holds a map of config properties that will update their binding as they are modified.
Secondly, you don't need to define getters and setters for the config object, in your case.
Each config item will have its own setter and getter method automatically generated inside the class prototype during class creation time, if the class does not have those methods explicitly defined.
You might to, but it will override the default methods which take care of updating the binding, among other things.
By standardize this mon pattern, the default generated setters provide two extra template methods that you can put your own custom logic into, i.e: an "applyFoo" and "updateFoo" method for a "foo" config item, which are executed before and after the value is actually set, respectively.
The twoWayBindable config relies on the update template method, and when you specify your own setter, the update method will never get called, and the binding won't be updated.
In other words, when leveraging the config feature, you mostly never need to define setter and getter methods explicitly. Instead, "apply" and "update" methods should be implemented where necessary.
So, in your example, here are the steps you need to take:
- Remove the
setTest
andgetTest
method declarations. Add the
twoWayBindable
config containingtest
.twoWayBindable: ['test']`
Hook up any additional logic into the
applyTest
orupdateTest
template methods. For example, updating the field value after the test value gets set.updateTest(testValue) { this.setValue(testValue) }
Here is the working fiddle: https://fiddle.sencha./#fiddle/20rs&view/editor
- In order to be able to bind custom class properties you need to list these in the
twoWayBindable
config. - Don't modify the value to be set in the setter and don't call the setter recursively. It is better to write an
update<Fieldname>()
function. Those are meant to handle updates in your view and they usually don't modify your data structures. - Based on 2.): Override the view update function of the form field to catch changes done to the value.
Here is the plete fiddle: https://fiddle.sencha./#fiddle/218m&view/editor
Some things to note here:
- after 3 seconds, the ViewModel testData value is updated
- after 6 seconds, the setTest() setter of the field is called
- after 9 seconds, the setValue() method from your input field is triggered
- at the end, you could change the input field value to change the panel title
This is to illustrate the various scenarios.