-
Notifications
You must be signed in to change notification settings - Fork 248
feat(ng-model-options) Added ng-model-options #974
Changes from 3 commits
fcfc248
c1a2cc4
82dd42d
68e21a6
308d8dc
e706b93
ac37d3e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -45,7 +45,7 @@ class NgModel extends NgControl implements AttachAware { | |
|
||
NgModel(this._scope, NgElement element, Injector injector, NodeAttrs attrs, | ||
Animate animate) | ||
: super(element, injector, animate) | ||
: super(element, injector, animate) | ||
{ | ||
_expression = attrs["ng-model"]; | ||
watchCollection = false; | ||
|
@@ -145,11 +145,10 @@ class NgModel extends NgControl implements AttachAware { | |
if (_watch!=null) _watch.remove(); | ||
if (_watchCollection) { | ||
_watch = _scope.watch(_expression, (changeRecord, _) { | ||
onChange(changeRecord is CollectionChangeRecord | ||
? changeRecord.iterable | ||
: changeRecord); | ||
}, | ||
collection: true); | ||
onChange(changeRecord is CollectionChangeRecord | ||
? changeRecord.iterable | ||
: changeRecord); | ||
}, collection: true); | ||
} else if (_expression != null) { | ||
_watch = _scope.watch(_expression, onChange); | ||
} | ||
|
@@ -196,6 +195,7 @@ class NgModel extends NgControl implements AttachAware { | |
|
||
get viewValue => _viewValue; | ||
void set viewValue(value) { | ||
//delay set | ||
_viewValue = value; | ||
modelValue = value; | ||
} | ||
|
@@ -204,7 +204,7 @@ class NgModel extends NgControl implements AttachAware { | |
void set modelValue(value) { | ||
try { | ||
value = converter.parse(value); | ||
} catch(e) { | ||
} catch (e) { | ||
value = null; | ||
} | ||
_modelValue = value; | ||
|
@@ -294,26 +294,29 @@ class InputCheckbox { | |
final NgModel ngModel; | ||
final NgTrueValue ngTrueValue; | ||
final NgFalseValue ngFalseValue; | ||
final NgModelOptions ngModelOptions; | ||
final Scope scope; | ||
|
||
InputCheckbox(dom.Element this.inputElement, this.ngModel, | ||
this.scope, this.ngTrueValue, this.ngFalseValue) { | ||
this.scope, this.ngTrueValue, this.ngFalseValue, this.ngModelOptions) { | ||
ngModel.render = (value) { | ||
scope.rootScope.domWrite(() { | ||
inputElement.checked = ngTrueValue.isValue(value); | ||
}); | ||
}; | ||
inputElement | ||
..onChange.listen((_) { | ||
ngModel.viewValue = inputElement.checked | ||
? ngTrueValue.value : ngFalseValue.value; | ||
}) | ||
..onBlur.listen((e) { | ||
..onChange.listen((_)=>ngModelOptions.executeChangeFunc(() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. missing ws around => There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. dosent need it? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should be |
||
ngModel.viewValue = inputElement.checked ? ngTrueValue.value : ngFalseValue.value; | ||
})) | ||
..onBlur.listen((_)=>ngModelOptions.executeBlurFunc(() { | ||
ngModel.markAsTouched(); | ||
}); | ||
})); | ||
} | ||
} | ||
|
||
|
||
|
||
|
||
/** | ||
* Usage: | ||
* | ||
|
@@ -336,37 +339,41 @@ class InputCheckbox { | |
class InputTextLike { | ||
final dom.Element inputElement; | ||
final NgModel ngModel; | ||
final NgModelOptions ngModelOptions; | ||
final Scope scope; | ||
String _inputType; | ||
|
||
|
||
get typedValue => (inputElement as dynamic).value; | ||
void set typedValue(value) { | ||
(inputElement as dynamic).value = (value == null) ? '' : value.toString(); | ||
} | ||
|
||
InputTextLike(this.inputElement, this.ngModel, this.scope) { | ||
InputTextLike(this.inputElement, this.ngModel, this.scope, this.ngModelOptions) { | ||
ngModel.render = (value) { | ||
scope.rootScope.domWrite(() { | ||
if (value == null) value = ''; | ||
|
||
var currentValue = typedValue; | ||
if (value != currentValue && !(value is num && currentValue is num && | ||
value.isNaN && currentValue.isNaN)) { | ||
typedValue = value; | ||
if (value != currentValue && !(value is num && currentValue is num && value.isNaN && currentValue.isNaN)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. revert |
||
typedValue = value; | ||
} | ||
}); | ||
}; | ||
|
||
inputElement | ||
..onChange.listen(processValue) | ||
..onInput.listen(processValue) | ||
..onBlur.listen((e) { | ||
..onChange.listen((event) => ngModelOptions.executeChangeFunc(() => processValue(event))) | ||
..onInput.listen((event) => ngModelOptions.executeInputFunc(() => processValue(event))) | ||
..onBlur.listen((_) => ngModelOptions.executeBlurFunc(() => () { | ||
ngModel.markAsTouched(); | ||
}); | ||
})); | ||
} | ||
|
||
void processValue([_]) { | ||
var value = typedValue; | ||
|
||
if (value != ngModel.viewValue) ngModel.viewValue = value; | ||
|
||
ngModel.validate(); | ||
} | ||
} | ||
|
@@ -393,6 +400,7 @@ class InputTextLike { | |
class InputNumberLike { | ||
final dom.InputElement inputElement; | ||
final NgModel ngModel; | ||
final NgModelOptions ngModelOptions; | ||
final Scope scope; | ||
|
||
|
||
|
@@ -413,21 +421,20 @@ class InputNumberLike { | |
} | ||
} | ||
|
||
InputNumberLike(dom.Element this.inputElement, this.ngModel, this.scope) { | ||
InputNumberLike(dom.Element this.inputElement, this.ngModel, this.scope, this.ngModelOptions) { | ||
ngModel.render = (value) { | ||
scope.rootScope.domWrite(() { | ||
if (value != typedValue | ||
&& (value == null || value is num && !value.isNaN)) { | ||
if (value != typedValue && (value == null || value is num && !value.isNaN)) { | ||
typedValue = value; | ||
} | ||
}); | ||
}; | ||
inputElement | ||
..onChange.listen(relaxFnArgs(processValue)) | ||
..onInput.listen(relaxFnArgs(processValue)) | ||
..onBlur.listen((e) { | ||
..onChange.listen((event) => ngModelOptions.executeChangeFunc(() => processValue())) | ||
..onInput.listen((event) => ngModelOptions.executeInputFunc(() => processValue())) | ||
..onBlur.listen((event) => ngModelOptions.executeBlurFunc(() => () { | ||
ngModel.markAsTouched(); | ||
}); | ||
})); | ||
} | ||
|
||
void processValue() { | ||
|
@@ -473,19 +480,20 @@ class NgBindTypeForDateLike { | |
@NgAttr('ng-bind-type') | ||
void set idlAttrKind(final String _kind) { | ||
String kind = _kind == null ? DEFAULT : _kind.toLowerCase(); | ||
if (!VALID_VALUES.contains(kind)) | ||
throw "Unsupported ng-bind-type attribute value '$_kind'; " | ||
"it should be one of $VALID_VALUES"; | ||
if (!VALID_VALUES.contains(kind)) throw "Unsupported ng-bind-type attribute value '$_kind'; " "it should be one of $VALID_VALUES"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. revert |
||
_idlAttrKind = kind; | ||
} | ||
|
||
String get idlAttrKind => _idlAttrKind; | ||
|
||
dynamic get inputTypedValue { | ||
switch (idlAttrKind) { | ||
case DATE: return inputValueAsDate; | ||
case NUMBER: return inputElement.valueAsNumber; | ||
default: return inputElement.value; | ||
case DATE: | ||
return inputValueAsDate; | ||
case NUMBER: | ||
return inputElement.valueAsNumber; | ||
default: | ||
return inputElement.value; | ||
} | ||
} | ||
|
||
|
@@ -568,28 +576,21 @@ class NgBindTypeForDateLike { | |
* dropped. | ||
*/ | ||
|
||
@Decorator(selector: 'input[type=date][ng-model]', | ||
module: InputDateLike.moduleFactory) | ||
@Decorator(selector: 'input[type=time][ng-model]', | ||
module: InputDateLike.moduleFactory) | ||
@Decorator(selector: 'input[type=datetime][ng-model]', | ||
module: InputDateLike.moduleFactory) | ||
@Decorator(selector: 'input[type=datetime-local][ng-model]', | ||
module: InputDateLike.moduleFactory) | ||
@Decorator(selector: 'input[type=month][ng-model]', | ||
module: InputDateLike.moduleFactory) | ||
@Decorator(selector: 'input[type=week][ng-model]', | ||
module: InputDateLike.moduleFactory) | ||
@Decorator(selector: 'input[type=date][ng-model]', module: InputDateLike.moduleFactory) | ||
@Decorator(selector: 'input[type=time][ng-model]', module: InputDateLike.moduleFactory) | ||
@Decorator(selector: 'input[type=datetime][ng-model]', module: InputDateLike.moduleFactory) | ||
@Decorator(selector: 'input[type=datetime-local][ng-model]', module: InputDateLike.moduleFactory) | ||
@Decorator(selector: 'input[type=month][ng-model]', module: InputDateLike.moduleFactory) | ||
@Decorator(selector: 'input[type=week][ng-model]', module: InputDateLike.moduleFactory) | ||
class InputDateLike { | ||
static Module moduleFactory() => new Module()..factory(NgBindTypeForDateLike, | ||
(Injector i) => new NgBindTypeForDateLike(i.get(dom.Element))); | ||
static Module moduleFactory() => new Module()..factory(NgBindTypeForDateLike, (Injector i) => new NgBindTypeForDateLike(i.get(dom.Element))); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. revert |
||
final dom.InputElement inputElement; | ||
final NgModel ngModel; | ||
final NgModelOptions ngModelOptions; | ||
final Scope scope; | ||
NgBindTypeForDateLike ngBindType; | ||
|
||
InputDateLike(dom.Element this.inputElement, this.ngModel, this.scope, | ||
this.ngBindType) { | ||
InputDateLike(dom.Element this.inputElement, this.ngModel, this.scope, this.ngBindType, this.ngModelOptions) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. too long |
||
if (inputElement.type == 'datetime-local') { | ||
ngBindType.idlAttrKind = NgBindTypeForDateLike.NUMBER; | ||
} | ||
|
@@ -599,11 +600,11 @@ class InputDateLike { | |
}); | ||
}; | ||
inputElement | ||
..onChange.listen(relaxFnArgs(processValue)) | ||
..onInput.listen(relaxFnArgs(processValue)) | ||
..onBlur.listen((e) { | ||
..onChange.listen((event) => ngModelOptions.executeChangeFunc(() => processValue())) | ||
..onInput.listen((event) => ngModelOptions.executeInputFunc(() => processValue())) | ||
..onBlur.listen((_)=> ngModelOptions.executeBlurFunc(() => () { | ||
ngModel.markAsTouched(); | ||
}); | ||
})); | ||
} | ||
|
||
dynamic get typedValue => ngBindType.inputTypedValue; | ||
|
@@ -679,7 +680,9 @@ class NgValue { | |
NgValue(this.element); | ||
|
||
@NgOneWay('ng-value') | ||
void set value(val) { this._value = val; } | ||
void set value(val) { | ||
this._value = val; | ||
} | ||
dynamic get value => _value == null ? (element as dynamic).value : _value; | ||
} | ||
|
||
|
@@ -741,17 +744,14 @@ class NgFalseValue { | |
* `009`, `00A`, `00Z`, `010`, and so on using more than 3 characters for the | ||
* name when the counter overflows. | ||
*/ | ||
@Decorator( | ||
selector: 'input[type=radio][ng-model]', | ||
module: NgValue.moduleFactory) | ||
@Decorator(selector: 'input[type=radio][ng-model]', module: NgValue.moduleFactory) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. revert |
||
class InputRadio { | ||
final dom.RadioButtonInputElement radioButtonElement; | ||
final NgModel ngModel; | ||
final NgValue ngValue; | ||
final Scope scope; | ||
|
||
InputRadio(dom.Element this.radioButtonElement, this.ngModel, | ||
this.scope, this.ngValue, NodeAttrs attrs) { | ||
InputRadio(dom.Element this.radioButtonElement, this.ngModel, this.scope, this.ngValue, NodeAttrs attrs) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. too long |
||
// If there's no "name" set, we'll set a unique name. This ensures | ||
// less surprising behavior about which radio buttons are grouped together. | ||
if (attrs['name'] == '' || attrs['name'] == null) { | ||
|
@@ -784,8 +784,8 @@ class InputRadio { | |
*/ | ||
@Decorator(selector: '[contenteditable][ng-model]') | ||
class ContentEditable extends InputTextLike { | ||
ContentEditable(dom.Element inputElement, NgModel ngModel, Scope scope) | ||
: super(inputElement, ngModel, scope); | ||
ContentEditable(dom.Element inputElement, NgModel ngModel, Scope scope, NgModelOptions modelOptions) | ||
: super(inputElement, ngModel, scope, modelOptions); | ||
|
||
// The implementation is identical to InputTextLike but use innerHtml instead of value | ||
String get typedValue => (inputElement as dynamic).innerHtml; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
part of angular.directive; | ||
|
||
@Decorator(selector: 'input[ng-model-options]') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Some doc about the purpose of this class would be great! |
||
class NgModelOptions { | ||
int _debounceDefaultValue = 0; | ||
int _debounceBlurValue = null; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is int default value not 0? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you don't have to be sorry for asking question ;) in Dart everything default to null (Types are only informative and not taken into account in production code) |
||
int _debounceChangeValue = null; | ||
int _debounceInputValue = null; | ||
|
||
static const String DEBOUNCE_DEFAULT_KEY = "default"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you can keep the leading "_" -> package private |
||
static const String DEBOUNCE_BLUR_KEY = "blur"; | ||
static const String DEBOUNCE_CHANGE_KEY = "change"; | ||
static const String DEBOUNCE_INPUT_KEY = "input"; | ||
|
||
NgModelOptions(NodeAttrs attrs) { | ||
Map options = convert.JSON.decode(attrs["ng-model-options"].replaceFirst("debounce", "'debounce'").replaceAll("'", "\"")); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. shouldn't we just have valid JSON as input ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. only thing i was trying to achieve to match the angularjs spec There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. actually you should check how this is done in ng_pluralize.dart IMO There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the comment has been removed: please check ng-pluralize There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what should i check ng-pluralize for? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Some attributes have a JSON format On 04/29/2014 01:21 AM, jrote1 wrote:
|
||
|
||
if (options["debounce"].containsKey(DEBOUNCE_DEFAULT_KEY)) _debounceDefaultValue = options["debounce"][DEBOUNCE_DEFAULT_KEY]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
you can omit {} when:
|
||
_debounceBlurValue = options["debounce"][DEBOUNCE_BLUR_KEY]; | ||
_debounceChangeValue = options["debounce"][DEBOUNCE_CHANGE_KEY]; | ||
_debounceInputValue = options["debounce"][DEBOUNCE_INPUT_KEY]; | ||
} | ||
|
||
async.Timer _blurTimer; | ||
void executeBlurFunc(func()) { | ||
var delay = _debounceBlurValue == null ? _debounceDefaultValue : _debounceBlurValue; | ||
_runFuncDebounced(delay, func, (timer)=>_blurTimer = timer,_blurTimer); | ||
} | ||
|
||
async.Timer _changeTimer; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. pls move properties at the top of the class, before methods |
||
void executeChangeFunc(func()) { | ||
var delay = _debounceChangeValue == null ? _debounceDefaultValue : _debounceChangeValue; | ||
_runFuncDebounced(delay, func, (timer)=>_changeTimer = timer, _changeTimer); | ||
} | ||
|
||
async.Timer _inputTimer; | ||
void executeInputFunc(func()) { | ||
var delay = _debounceInputValue == null ? _debounceDefaultValue : _debounceInputValue; | ||
_runFuncDebounced(delay, func, (timer) => _inputTimer = timer, _inputTimer); | ||
} | ||
|
||
void _runFuncDebounced(int delay, func(), setTimer(async.Timer timer), async.Timer timer){ | ||
if (timer != null && timer.isActive) timer.cancel(); | ||
|
||
if(delay == 0){ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
notice ws & formatting |
||
func(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. add missing {} |
||
} | ||
else{ | ||
setTimer(new async.Timer(new Duration(milliseconds: delay), func)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what about dropping the 3rd args & returning the timer |
||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you should configure your editor to remove trailing ws