问题
I want to write a new component that extends Ember Input as number input. When users of this class binds their values to value
property of number-input-component, they should only get a number (or NaN for invalid values). In Ember Input, value has an attribute binding.
I've defined a computed property named "value" on number-input-component as following:
value:Ember.computed({
get:function(key){
let htmlValue = this.get('htmlvalue');
return this.sanitize(htmlValue);
},
set:function (key, htmlvalue){
this.set('htmlvalue', htmlvalue);
if(this.get('onUpdate')) {
this.get('onUpdate')(this.sanitize(htmlvalue));
}
return this.sanitize(htmlvalue);
}
}),
It works as expected but it's not working in two-way binding. (Actually it is ok for DDAU. But it should work in two-way bindings.)
Note: I know that I can supply another property such as "numericValue" (shown as here) so that users can bind their values to "numericValue". But I don't want to confuse users with both value and numericValue.
UPDATE:
While typing to the field, any typo shouldn't reset the value. For example while user is trying to write "123456789" and accidentally press "12345678p" should not cause the input reset. Neither displaying an error message nor reseting the value is not a responsibility of the component when value is invalid.
There is a fiddle you can see: Ember-Twiddle
回答1:
Another way would be to overwrite the _elementValueDidChange()
method. You can get the current DOM value by this.readDOMAttr('value')
, do your sanitizing and finally call this.set('value', sanitizedValue)
. This is how Ember internally changes the value
property.
回答2:
You can write an observer of the value
property and when it is changed, replace it with the sanitized version:
valueWatcher() {
this.set('value' this.sanitize(this.get('value')));
}.observes('value')
Ember will prevent the race condition when an observer modifies the property it watches.
回答3:
I've found a solution using _elementDidChange
suggested in @jcbvm's solution. Also override attributeBindings to manage the screen value.
Here it is:
import Ember from 'ember';
export default Ember.TextField.extend({
type:'text',//hey! this is text!
init(){
this._super(...arguments);
let arr = this.get('attributeBindings');
arr.removeObject('value');
arr.pushObject('val:value');
},
val: Ember.computed('domValue', 'value', function() {
let value = this.get('value');
//detect whether the update is trigger by dom or by users of this class:
if(!Number.isNaN(value) && this.sanitize(this.get('domValue')) !== value){
return value;
}
return this.get('domValue');
}),
_elementValueDidChange(){
let domValue = this.readDOMAttr('value');
let value = this.sanitize(domValue);
if(this.sanitize(this.get('domValue')) !== value){
this.set('domValue', domValue);
}
this.set('value', value);
},
sanitize:function(value){
if(value === ''){
return Number.NaN;
}
return Number(value);
}
});
The reason of using type=text
is html5 number inputs' sanitization algorithm. input type=number
component returns empty string for invalid values on Chrome, Firefox and Edge (not IE).Reference for sanitization from W3C.
Cons of this solution:
- Overrides
_elementDidChange
- Modifies attributeBindings. (Maybe parent classes depends on this value.)
来源:https://stackoverflow.com/questions/36941190/how-to-override-a-parent-property-in-ember-js-specifically-number-inputs-beha