From fcfc2486edd35763dbf9a270097accc8da07fd1e Mon Sep 17 00:00:00 2001 From: jrote1 Date: Mon, 28 Apr 2014 22:36:27 +0100 Subject: [PATCH 1/6] Added ng-model-options support Add support for the debounce part of ng-model-options --- benchmark/pubspec.lock | 2 +- example/pubspec.lock | 2 +- example/web/hello_world.html | 2 +- lib/directive/module.dart | 4 + lib/directive/ng_model.dart | 150 ++++++++++++---------------- lib/directive/ng_model_options.dart | 55 ++++++++++ pubspec.lock | 2 +- test/directive/ng_model_spec.dart | 32 ++++-- 8 files changed, 150 insertions(+), 99 deletions(-) create mode 100644 lib/directive/ng_model_options.dart diff --git a/benchmark/pubspec.lock b/benchmark/pubspec.lock index 23eec1cc4..5b25f0a42 100644 --- a/benchmark/pubspec.lock +++ b/benchmark/pubspec.lock @@ -18,7 +18,7 @@ packages: barback: description: barback source: hosted - version: "0.13.0" + version: "0.12.0" benchmark_harness: description: benchmark_harness source: hosted diff --git a/example/pubspec.lock b/example/pubspec.lock index f2692c5e6..8991b5523 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -18,7 +18,7 @@ packages: barback: description: barback source: hosted - version: "0.13.0" + version: "0.12.0" browser: description: browser source: hosted diff --git a/example/web/hello_world.html b/example/web/hello_world.html index 1b4c681d9..705607d48 100644 --- a/example/web/hello_world.html +++ b/example/web/hello_world.html @@ -6,7 +6,7 @@

Hello {{ctrl.name}}!

-name: +name: diff --git a/lib/directive/module.dart b/lib/directive/module.dart index a3eb93703..8840844d1 100644 --- a/lib/directive/module.dart +++ b/lib/directive/module.dart @@ -19,6 +19,8 @@ library angular.directive; import 'package:di/di.dart'; import 'dart:html' as dom; +import 'dart:convert' as convert; +import 'dart:async' as async; import 'package:intl/intl.dart'; import 'package:angular/core/annotation.dart'; import 'package:angular/core/module_internal.dart'; @@ -51,6 +53,7 @@ part 'ng_non_bindable.dart'; part 'ng_model_select.dart'; part 'ng_form.dart'; part 'ng_model_validators.dart'; +part 'ng_model_options.dart'; class DecoratorFormatter extends Module { DecoratorFormatter() { @@ -82,6 +85,7 @@ class DecoratorFormatter extends Module { value(ContentEditable, null); value(NgBindTypeForDateLike, null); value(NgModel, null); + value(NgModelOptions, null); value(NgValue, null); value(NgTrueValue, new NgTrueValue()); value(NgFalseValue, new NgFalseValue()); diff --git a/lib/directive/ng_model.dart b/lib/directive/ng_model.dart index b71273c31..44f53b7be 100644 --- a/lib/directive/ng_model.dart +++ b/lib/directive/ng_model.dart @@ -43,11 +43,10 @@ class NgModel extends NgControl implements AttachAware { Watch _watch; bool _watchCollection; - NgModel(this._scope, NgElement element, Injector injector, NodeAttrs attrs, - Animate animate) - : super(element, injector, animate) - { + NgModel(this._scope, NgElement element, Injector injector, NodeAttrs attrs, Animate animate) + : super(element, injector, animate) { _expression = attrs["ng-model"]; + print("model: " + _expression); watchCollection = false; //Since the user will never be editing the value of a select element then @@ -142,14 +141,11 @@ class NgModel extends NgControl implements AttachAware { }; _watchCollection = value; - if (_watch!=null) _watch.remove(); + 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 +192,7 @@ class NgModel extends NgControl implements AttachAware { get viewValue => _viewValue; void set viewValue(value) { + //delay set _viewValue = value; modelValue = value; } @@ -204,7 +201,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 +291,28 @@ 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) { + InputCheckbox(dom.Element this.inputElement, this.ngModel, 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(() { + ngModel.viewValue = inputElement.checked ? ngTrueValue.value : ngFalseValue.value; + })) + ..onBlur.listen((_)=>ngModelOptions.executeBlurFunc(() { ngModel.markAsTouched(); - }); + })); } } + + + /** * Usage: * @@ -327,46 +326,48 @@ class InputCheckbox { * as well as the other way around (when the scope property is updated). * */ -@Decorator(selector: 'textarea[ng-model]') -@Decorator(selector: 'input[type=text][ng-model]') -@Decorator(selector: 'input[type=password][ng-model]') -@Decorator(selector: 'input[type=url][ng-model]') -@Decorator(selector: 'input[type=email][ng-model]') -@Decorator(selector: 'input[type=search][ng-model]') +@Decorator(selector: 'textarea[ng-model]')@Decorator(selector: 'input[type=text][ng-model]')@Decorator(selector: 'input[type=password][ng-model]')@Decorator(selector: 'input[type=url][ng-model]')@Decorator(selector: 'input[type=email][ng-model]')@Decorator(selector: 'input[type=search][ng-model]') 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)) { + typedValue = value; } }); }; + + print("text type"); + 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([_]) { + print("processed viewValue ${ngModel.viewValue} typeValue ${typedValue}"); var value = typedValue; + if (value != ngModel.viewValue) ngModel.viewValue = value; + ngModel.validate(); } } @@ -388,11 +389,11 @@ class InputTextLike { * Setting the model to [double.NAN] will have no effect (input will be left * unchanged). */ -@Decorator(selector: 'input[type=number][ng-model]') -@Decorator(selector: 'input[type=range][ng-model]') +@Decorator(selector: 'input[type=number][ng-model]')@Decorator(selector: 'input[type=range][ng-model]') class InputNumberLike { final dom.InputElement inputElement; final NgModel ngModel; + final NgModelOptions ngModelOptions; final Scope scope; @@ -413,21 +414,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() { @@ -452,12 +452,7 @@ class InputNumberLike { * kind would be appropriate) or, for browsers that fail to conform to the * HTML5 standard in their processing of date-like inputs. */ -@Decorator(selector: 'input[type=date][ng-model][ng-bind-type]') -@Decorator(selector: 'input[type=time][ng-model][ng-bind-type]') -@Decorator(selector: 'input[type=datetime][ng-model][ng-bind-type]') -@Decorator(selector: 'input[type=datetime-local][ng-model][ng-bind-type]') -@Decorator(selector: 'input[type=month][ng-model][ng-bind-type]') -@Decorator(selector: 'input[type=week][ng-model][ng-bind-type]') +@Decorator(selector: 'input[type=date][ng-model][ng-bind-type]')@Decorator(selector: 'input[type=time][ng-model][ng-bind-type]')@Decorator(selector: 'input[type=datetime][ng-model][ng-bind-type]')@Decorator(selector: 'input[type=datetime-local][ng-model][ng-bind-type]')@Decorator(selector: 'input[type=month][ng-model][ng-bind-type]')@Decorator(selector: 'input[type=week][ng-model][ng-bind-type]') class NgBindTypeForDateLike { static const DATE = 'date'; static const NUMBER = 'number'; @@ -473,9 +468,7 @@ 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"; _idlAttrKind = kind; } @@ -483,9 +476,12 @@ class NgBindTypeForDateLike { 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 +564,16 @@ 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))); 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) { if (inputElement.type == 'datetime-local') { ngBindType.idlAttrKind = NgBindTypeForDateLike.NUMBER; } @@ -599,11 +583,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; @@ -667,8 +651,7 @@ final _uidCounter = new _UidCounter(); * selected. Note that `expr` can be not any type; i.e., it is not restricted * to [String]. */ -@Decorator(selector: 'input[type=radio][ng-model][ng-value]') -@Decorator(selector: 'option[ng-value]') +@Decorator(selector: 'input[type=radio][ng-model][ng-value]')@Decorator(selector: 'option[ng-value]') class NgValue { static Module _module = new Module()..type(NgValue); static Module moduleFactory() => _module; @@ -679,7 +662,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 +726,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) 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) { // 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 +766,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; diff --git a/lib/directive/ng_model_options.dart b/lib/directive/ng_model_options.dart new file mode 100644 index 000000000..c472d40d1 --- /dev/null +++ b/lib/directive/ng_model_options.dart @@ -0,0 +1,55 @@ +part of angular.directive; + +@Decorator(selector: 'input[ng-model-options]') +class NgModelOptions { + int _debounceDefaultValue = 0; + int _debounceBlurValue = null; + int _debounceChangeValue = null; + int _debounceInputValue = null; + + static const String _debounceDefaultKey = "default"; + static const String _debounceBlurKey = "blur"; + static const String _debounceChangeKey = "change"; + static const String _debounceInputKey = "input"; + + NgModelOptions(NodeAttrs attrs) { + print("options: " + attrs["ng-model-options"].replaceFirst("debounce", "'debounce'").replaceAll("'", "\"")); + Map options = convert.JSON.decode(attrs["ng-model-options"].replaceFirst("debounce", "'debounce'").replaceAll("'", "\"")); + + if (options["debounce"].containsKey(_debounceDefaultKey)) _debounceDefaultValue = options["debounce"][_debounceDefaultKey]; + if (options["debounce"].containsKey(_debounceBlurKey)) _debounceBlurValue = options["debounce"][_debounceBlurKey]; + if (options["debounce"].containsKey(_debounceChangeKey)) _debounceChangeValue = options["debounce"][_debounceChangeKey]; + if (options["debounce"].containsKey(_debounceInputKey)) _debounceInputValue = options["debounce"][_debounceInputKey]; + } + + async.Timer _blurTimer; + void executeBlurFunc(func()) { + if (_blurTimer != null && !_blurTimer.isActive) _blurTimer.cancel(); + + var delay = _debounceBlurValue == null ? _debounceDefaultValue : _debounceBlurValue; + _runFuncDebounced(delay, func, (timer)=>_blurTimer = timer); + } + + async.Timer _changeTimer; + void executeChangeFunc(func()) { + if (_changeTimer != null && !_changeTimer.isActive) _changeTimer.cancel(); + + var delay = _debounceChangeValue == null ? _debounceDefaultValue : _debounceChangeValue; + _runFuncDebounced(delay, func, (timer)=>_changeTimer = timer); + } + + async.Timer _inputTimer; + void executeInputFunc(func()) { + if (_inputTimer != null && _inputTimer.isActive) _inputTimer.cancel(); + + var delay = _debounceInputValue == null ? _debounceDefaultValue : _debounceInputValue; + _runFuncDebounced(delay, func, (timer) => _inputTimer = timer); + } + + void _runFuncDebounced(int delay, func(), setTimer(async.Timer timer)){ + if(delay == 0) + func(); + else + setTimer(new async.Timer(new Duration(milliseconds: delay), func)); + } +} diff --git a/pubspec.lock b/pubspec.lock index 119c9bbf2..3846055f9 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -12,7 +12,7 @@ packages: barback: description: barback source: hosted - version: "0.13.0" + version: "0.12.0" benchmark_harness: description: benchmark_harness source: hosted diff --git a/test/directive/ng_model_spec.dart b/test/directive/ng_model_spec.dart index 0fd41441e..6739cfe26 100644 --- a/test/directive/ng_model_spec.dart +++ b/test/directive/ng_model_spec.dart @@ -86,16 +86,18 @@ void main() { it('should write to input only if the value is different', (Injector i, Animate animate) { + NodeAttrs nodeAttrs = new NodeAttrs(new DivElement()); + var scope = _.rootScope; var element = new dom.InputElement(); var ngElement = new NgElement(element, scope, animate); - - NodeAttrs nodeAttrs = new NodeAttrs(new DivElement()); + var ngModelOptions = new NgModelOptions(nodeAttrs); + nodeAttrs['ng-model'] = 'model'; var model = new NgModel(scope, ngElement, i.createChild([new Module()]), nodeAttrs, new Animate()); dom.querySelector('body').append(element); - var input = new InputTextLike(element, model, scope); + var input = new InputTextLike(element, model, scope, ngModelOptions); element ..value = 'abc' @@ -364,16 +366,18 @@ void main() { it('should write to input only if value is different', (Injector i, Animate animate) { + NodeAttrs nodeAttrs = new NodeAttrs(new DivElement()); + var scope = _.rootScope; var element = new dom.InputElement(); var ngElement = new NgElement(element, scope, animate); + var ngModelOptions = new NgModelOptions(nodeAttrs); - NodeAttrs nodeAttrs = new NodeAttrs(new DivElement()); nodeAttrs['ng-model'] = 'model'; var model = new NgModel(scope, ngElement, i.createChild([new Module()]), nodeAttrs, new Animate()); dom.querySelector('body').append(element); - var input = new InputTextLike(element, model, scope); + var input = new InputTextLike(element, model, scope, ngModelOptions); element ..value = 'abc' @@ -454,16 +458,18 @@ void main() { it('should write to input only if value is different', (Injector i, Animate animate) { + NodeAttrs nodeAttrs = new NodeAttrs(new DivElement()); + var scope = _.rootScope; var element = new dom.InputElement(); var ngElement = new NgElement(element, scope, animate); + var ngModelOptions = new NgModelOptions(nodeAttrs); - NodeAttrs nodeAttrs = new NodeAttrs(new DivElement()); nodeAttrs['ng-model'] = 'model'; var model = new NgModel(scope, ngElement, i.createChild([new Module()]), nodeAttrs, new Animate()); dom.querySelector('body').append(element); - var input = new InputTextLike(element, model, scope); + var input = new InputTextLike(element, model, scope, ngModelOptions); element ..value = 'abc' @@ -552,16 +558,18 @@ void main() { it('should write to input only if value is different', (Injector i, Animate animate) { + NodeAttrs nodeAttrs = new NodeAttrs(new DivElement()); + var scope = _.rootScope; var element = new dom.InputElement(); var ngElement = new NgElement(element, scope, animate); + var ngModelOptions = new NgModelOptions(nodeAttrs); - NodeAttrs nodeAttrs = new NodeAttrs(new DivElement()); nodeAttrs['ng-model'] = 'model'; var model = new NgModel(scope, ngElement, i.createChild([new Module()]), nodeAttrs, new Animate()); dom.querySelector('body').append(element); - var input = new InputTextLike(element, model, scope); + var input = new InputTextLike(element, model, scope, ngModelOptions); element ..value = 'abc' @@ -761,16 +769,18 @@ void main() { xit('should write to input only if value is different', (Injector i, Animate animate) { + NodeAttrs nodeAttrs = new NodeAttrs(new DivElement()); + var scope = _.rootScope; var element = new dom.TextAreaElement(); var ngElement = new NgElement(element, scope, animate); + var ngModelOptions = new NgModelOptions(nodeAttrs); - NodeAttrs nodeAttrs = new NodeAttrs(new DivElement()); nodeAttrs['ng-model'] = 'model'; var model = new NgModel(scope, ngElement, i.createChild([new Module()]), nodeAttrs, new Animate()); dom.querySelector('body').append(element); - var input = new InputTextLike(element, model, scope); + var input = new InputTextLike(element, model, scope, ngModelOptions); element ..value = 'abc' From c1a2cc479676c41dae6a4d7bc1c932e630ad136f Mon Sep 17 00:00:00 2001 From: jrote1 Date: Mon, 28 Apr 2014 23:02:23 +0100 Subject: [PATCH 2/6] feat(ng-model-options) Added ng-model-options Added support for the debounce part of ng-model-options closes #969 --- lib/directive/ng_model.dart | 40 ++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/lib/directive/ng_model.dart b/lib/directive/ng_model.dart index 44f53b7be..7a1837e26 100644 --- a/lib/directive/ng_model.dart +++ b/lib/directive/ng_model.dart @@ -43,10 +43,10 @@ class NgModel extends NgControl implements AttachAware { Watch _watch; bool _watchCollection; - NgModel(this._scope, NgElement element, Injector injector, NodeAttrs attrs, Animate animate) + NgModel(this._scope, NgElement element, Injector injector, NodeAttrs attrs, + Animate animate) : super(element, injector, animate) { _expression = attrs["ng-model"]; - print("model: " + _expression); watchCollection = false; //Since the user will never be editing the value of a select element then @@ -141,10 +141,12 @@ class NgModel extends NgControl implements AttachAware { }; _watchCollection = value; - if (_watch != null) _watch.remove(); + if (_watch!=null) _watch.remove(); if (_watchCollection) { _watch = _scope.watch(_expression, (changeRecord, _) { - onChange(changeRecord is CollectionChangeRecord ? changeRecord.iterable : changeRecord); + onChange(changeRecord is CollectionChangeRecord + ? changeRecord.iterable + : changeRecord); }, collection: true); } else if (_expression != null) { _watch = _scope.watch(_expression, onChange); @@ -326,7 +328,12 @@ class InputCheckbox { * as well as the other way around (when the scope property is updated). * */ -@Decorator(selector: 'textarea[ng-model]')@Decorator(selector: 'input[type=text][ng-model]')@Decorator(selector: 'input[type=password][ng-model]')@Decorator(selector: 'input[type=url][ng-model]')@Decorator(selector: 'input[type=email][ng-model]')@Decorator(selector: 'input[type=search][ng-model]') +@Decorator(selector: 'textarea[ng-model]') +@Decorator(selector: 'input[type=text][ng-model]') +@Decorator(selector: 'input[type=password][ng-model]') +@Decorator(selector: 'input[type=url][ng-model]') +@Decorator(selector: 'input[type=email][ng-model]') +@Decorator(selector: 'input[type=search][ng-model]') class InputTextLike { final dom.Element inputElement; final NgModel ngModel; @@ -352,8 +359,6 @@ class InputTextLike { }); }; - print("text type"); - inputElement ..onChange.listen((event) => ngModelOptions.executeChangeFunc(() => processValue(event))) ..onInput.listen((event) => ngModelOptions.executeInputFunc(() => processValue(event))) @@ -363,7 +368,6 @@ class InputTextLike { } void processValue([_]) { - print("processed viewValue ${ngModel.viewValue} typeValue ${typedValue}"); var value = typedValue; if (value != ngModel.viewValue) ngModel.viewValue = value; @@ -389,7 +393,8 @@ class InputTextLike { * Setting the model to [double.NAN] will have no effect (input will be left * unchanged). */ -@Decorator(selector: 'input[type=number][ng-model]')@Decorator(selector: 'input[type=range][ng-model]') +@Decorator(selector: 'input[type=number][ng-model]') +@Decorator(selector: 'input[type=range][ng-model]') class InputNumberLike { final dom.InputElement inputElement; final NgModel ngModel; @@ -452,7 +457,12 @@ class InputNumberLike { * kind would be appropriate) or, for browsers that fail to conform to the * HTML5 standard in their processing of date-like inputs. */ -@Decorator(selector: 'input[type=date][ng-model][ng-bind-type]')@Decorator(selector: 'input[type=time][ng-model][ng-bind-type]')@Decorator(selector: 'input[type=datetime][ng-model][ng-bind-type]')@Decorator(selector: 'input[type=datetime-local][ng-model][ng-bind-type]')@Decorator(selector: 'input[type=month][ng-model][ng-bind-type]')@Decorator(selector: 'input[type=week][ng-model][ng-bind-type]') +@Decorator(selector: 'input[type=date][ng-model][ng-bind-type]') +@Decorator(selector: 'input[type=time][ng-model][ng-bind-type]') +@Decorator(selector: 'input[type=datetime][ng-model][ng-bind-type]') +@Decorator(selector: 'input[type=datetime-local][ng-model][ng-bind-type]') +@Decorator(selector: 'input[type=month][ng-model][ng-bind-type]') +@Decorator(selector: 'input[type=week][ng-model][ng-bind-type]') class NgBindTypeForDateLike { static const DATE = 'date'; static const NUMBER = 'number'; @@ -564,7 +574,12 @@ 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))); final dom.InputElement inputElement; @@ -651,7 +666,8 @@ final _uidCounter = new _UidCounter(); * selected. Note that `expr` can be not any type; i.e., it is not restricted * to [String]. */ -@Decorator(selector: 'input[type=radio][ng-model][ng-value]')@Decorator(selector: 'option[ng-value]') +@Decorator(selector: 'input[type=radio][ng-model][ng-value]') +@Decorator(selector: 'option[ng-value]') class NgValue { static Module _module = new Module()..type(NgValue); static Module moduleFactory() => _module; From 82dd42d061a6d370a3bc458fd2697203696396fc Mon Sep 17 00:00:00 2001 From: jrote1 Date: Mon, 28 Apr 2014 23:34:40 +0100 Subject: [PATCH 3/6] Fixed some more issues --- lib/directive/ng_model.dart | 8 +++--- lib/directive/ng_model_options.dart | 39 +++++++++++++---------------- 2 files changed, 23 insertions(+), 24 deletions(-) diff --git a/lib/directive/ng_model.dart b/lib/directive/ng_model.dart index 7a1837e26..8315bb15f 100644 --- a/lib/directive/ng_model.dart +++ b/lib/directive/ng_model.dart @@ -43,9 +43,10 @@ class NgModel extends NgControl implements AttachAware { Watch _watch; bool _watchCollection; - NgModel(this._scope, NgElement element, Injector injector, NodeAttrs attrs, + 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; @@ -296,7 +297,8 @@ class InputCheckbox { final NgModelOptions ngModelOptions; final Scope scope; - InputCheckbox(dom.Element this.inputElement, this.ngModel, this.scope, this.ngTrueValue, this.ngFalseValue, this.ngModelOptions) { + InputCheckbox(dom.Element this.inputElement, this.ngModel, + this.scope, this.ngTrueValue, this.ngFalseValue, this.ngModelOptions) { ngModel.render = (value) { scope.rootScope.domWrite(() { inputElement.checked = ngTrueValue.isValue(value); diff --git a/lib/directive/ng_model_options.dart b/lib/directive/ng_model_options.dart index c472d40d1..860c04ef5 100644 --- a/lib/directive/ng_model_options.dart +++ b/lib/directive/ng_model_options.dart @@ -7,49 +7,46 @@ class NgModelOptions { int _debounceChangeValue = null; int _debounceInputValue = null; - static const String _debounceDefaultKey = "default"; - static const String _debounceBlurKey = "blur"; - static const String _debounceChangeKey = "change"; - static const String _debounceInputKey = "input"; + static const String DEBOUNCE_DEFAULT_KEY = "default"; + static const String DEBOUNCE_BLUR_KEY = "blur"; + static const String DEBOUNCE_CHANGE_KEY = "change"; + static const String DEBOUNCE_INPUT_KEY = "input"; NgModelOptions(NodeAttrs attrs) { - print("options: " + attrs["ng-model-options"].replaceFirst("debounce", "'debounce'").replaceAll("'", "\"")); Map options = convert.JSON.decode(attrs["ng-model-options"].replaceFirst("debounce", "'debounce'").replaceAll("'", "\"")); - if (options["debounce"].containsKey(_debounceDefaultKey)) _debounceDefaultValue = options["debounce"][_debounceDefaultKey]; - if (options["debounce"].containsKey(_debounceBlurKey)) _debounceBlurValue = options["debounce"][_debounceBlurKey]; - if (options["debounce"].containsKey(_debounceChangeKey)) _debounceChangeValue = options["debounce"][_debounceChangeKey]; - if (options["debounce"].containsKey(_debounceInputKey)) _debounceInputValue = options["debounce"][_debounceInputKey]; + if (options["debounce"].containsKey(DEBOUNCE_DEFAULT_KEY)) _debounceDefaultValue = options["debounce"][DEBOUNCE_DEFAULT_KEY]; + _debounceBlurValue = options["debounce"][DEBOUNCE_BLUR_KEY]; + _debounceChangeValue = options["debounce"][DEBOUNCE_CHANGE_KEY]; + _debounceInputValue = options["debounce"][DEBOUNCE_INPUT_KEY]; } async.Timer _blurTimer; void executeBlurFunc(func()) { - if (_blurTimer != null && !_blurTimer.isActive) _blurTimer.cancel(); - var delay = _debounceBlurValue == null ? _debounceDefaultValue : _debounceBlurValue; - _runFuncDebounced(delay, func, (timer)=>_blurTimer = timer); + _runFuncDebounced(delay, func, (timer)=>_blurTimer = timer,_blurTimer); } async.Timer _changeTimer; void executeChangeFunc(func()) { - if (_changeTimer != null && !_changeTimer.isActive) _changeTimer.cancel(); - var delay = _debounceChangeValue == null ? _debounceDefaultValue : _debounceChangeValue; - _runFuncDebounced(delay, func, (timer)=>_changeTimer = timer); + _runFuncDebounced(delay, func, (timer)=>_changeTimer = timer, _changeTimer); } async.Timer _inputTimer; void executeInputFunc(func()) { - if (_inputTimer != null && _inputTimer.isActive) _inputTimer.cancel(); - var delay = _debounceInputValue == null ? _debounceDefaultValue : _debounceInputValue; - _runFuncDebounced(delay, func, (timer) => _inputTimer = timer); + _runFuncDebounced(delay, func, (timer) => _inputTimer = timer, _inputTimer); } - void _runFuncDebounced(int delay, func(), setTimer(async.Timer timer)){ - if(delay == 0) + void _runFuncDebounced(int delay, func(), setTimer(async.Timer timer), async.Timer timer){ + if (timer != null && timer.isActive) timer.cancel(); + + if(delay == 0){ func(); - else + } + else{ setTimer(new async.Timer(new Duration(milliseconds: delay), func)); + } } } From 68e21a6712819401ec5f682aef579107646fe2f0 Mon Sep 17 00:00:00 2001 From: jrote1 Date: Tue, 29 Apr 2014 00:00:55 +0100 Subject: [PATCH 4/6] Fixed some more issues --- lib/directive/ng_model.dart | 22 +++++++++++++------- lib/directive/ng_model_options.dart | 32 +++++++++++++++-------------- 2 files changed, 32 insertions(+), 22 deletions(-) diff --git a/lib/directive/ng_model.dart b/lib/directive/ng_model.dart index 8315bb15f..2d81c44f0 100644 --- a/lib/directive/ng_model.dart +++ b/lib/directive/ng_model.dart @@ -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; @@ -355,7 +355,8 @@ class InputTextLike { if (value == null) value = ''; var currentValue = typedValue; - if (value != currentValue && !(value is num && currentValue is num && value.isNaN && currentValue.isNaN)) { + if (value != currentValue && !(value is num && currentValue is num && + value.isNaN && currentValue.isNaN)) { typedValue = value; } }); @@ -480,7 +481,9 @@ 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"; _idlAttrKind = kind; } @@ -583,14 +586,16 @@ class NgBindTypeForDateLike { @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))); 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, this.ngModelOptions) { + InputDateLike(dom.Element this.inputElement, this.ngModel, this.scope, + this.ngBindType, this.ngModelOptions) { if (inputElement.type == 'datetime-local') { ngBindType.idlAttrKind = NgBindTypeForDateLike.NUMBER; } @@ -744,14 +749,17 @@ 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) 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) { // 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) { diff --git a/lib/directive/ng_model_options.dart b/lib/directive/ng_model_options.dart index 860c04ef5..2b25f7d69 100644 --- a/lib/directive/ng_model_options.dart +++ b/lib/directive/ng_model_options.dart @@ -7,46 +7,48 @@ class NgModelOptions { int _debounceChangeValue = null; int _debounceInputValue = null; - static const String DEBOUNCE_DEFAULT_KEY = "default"; - static const String DEBOUNCE_BLUR_KEY = "blur"; - static const String DEBOUNCE_CHANGE_KEY = "change"; - static const String DEBOUNCE_INPUT_KEY = "input"; + static const String _DEBOUNCE_DEFAULT_KEY = "default"; + 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("'", "\"")); - if (options["debounce"].containsKey(DEBOUNCE_DEFAULT_KEY)) _debounceDefaultValue = options["debounce"][DEBOUNCE_DEFAULT_KEY]; - _debounceBlurValue = options["debounce"][DEBOUNCE_BLUR_KEY]; - _debounceChangeValue = options["debounce"][DEBOUNCE_CHANGE_KEY]; - _debounceInputValue = options["debounce"][DEBOUNCE_INPUT_KEY]; + if (options["debounce"].containsKey(_DEBOUNCE_DEFAULT_KEY)){ + _debounceDefaultValue = options["debounce"][_DEBOUNCE_DEFAULT_KEY]; + } + _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); + _blurTimer = _runFuncDebounced(delay, func,_blurTimer); } async.Timer _changeTimer; void executeChangeFunc(func()) { var delay = _debounceChangeValue == null ? _debounceDefaultValue : _debounceChangeValue; - _runFuncDebounced(delay, func, (timer)=>_changeTimer = timer, _changeTimer); + _changeTimer = _runFuncDebounced(delay, func, _changeTimer); } async.Timer _inputTimer; void executeInputFunc(func()) { var delay = _debounceInputValue == null ? _debounceDefaultValue : _debounceInputValue; - _runFuncDebounced(delay, func, (timer) => _inputTimer = timer, _inputTimer); + _inputTimer = _runFuncDebounced(delay, func, _inputTimer); } - void _runFuncDebounced(int delay, func(), setTimer(async.Timer timer), async.Timer timer){ + async.Timer _runFuncDebounced(int delay, func(), async.Timer timer){ if (timer != null && timer.isActive) timer.cancel(); if(delay == 0){ func(); - } - else{ - setTimer(new async.Timer(new Duration(milliseconds: delay), func)); + return null; + } else { + return new async.Timer(new Duration(milliseconds: delay), func); } } } From 308d8dcf5120dc014abd581b4a1997089ca3cdc9 Mon Sep 17 00:00:00 2001 From: jrote1 Date: Tue, 29 Apr 2014 00:09:14 +0100 Subject: [PATCH 5/6] Fixed some formatting --- lib/directive/ng_model.dart | 35 ++++++++++++++++------------- lib/directive/ng_model_options.dart | 6 ++--- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/lib/directive/ng_model.dart b/lib/directive/ng_model.dart index 2d81c44f0..f85691556 100644 --- a/lib/directive/ng_model.dart +++ b/lib/directive/ng_model.dart @@ -145,9 +145,9 @@ 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); + onChange(changeRecord is CollectionChangeRecord + ? changeRecord.iterable + : changeRecord); }, collection: true); } else if (_expression != null) { _watch = _scope.watch(_expression, onChange); @@ -195,8 +195,7 @@ class NgModel extends NgControl implements AttachAware { get viewValue => _viewValue; void set viewValue(value) { - //delay set - _viewValue = value; + _viewValue = value; modelValue = value; } @@ -204,7 +203,7 @@ class NgModel extends NgControl implements AttachAware { void set modelValue(value) { try { value = converter.parse(value); - } catch (e) { + } catch(e) { value = null; } _modelValue = value; @@ -305,10 +304,10 @@ class InputCheckbox { }); }; inputElement - ..onChange.listen((_)=>ngModelOptions.executeChangeFunc(() { + ..onChange.listen((_) => ngModelOptions.executeChangeFunc(() { ngModel.viewValue = inputElement.checked ? ngTrueValue.value : ngFalseValue.value; })) - ..onBlur.listen((_)=>ngModelOptions.executeBlurFunc(() { + ..onBlur.listen((_) => ngModelOptions.executeBlurFunc(() { ngModel.markAsTouched(); })); } @@ -579,12 +578,18 @@ 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))); @@ -607,7 +612,7 @@ class InputDateLike { inputElement ..onChange.listen((event) => ngModelOptions.executeChangeFunc(() => processValue())) ..onInput.listen((event) => ngModelOptions.executeInputFunc(() => processValue())) - ..onBlur.listen((_)=> ngModelOptions.executeBlurFunc(() => () { + ..onBlur.listen((_) => ngModelOptions.executeBlurFunc(() => () { ngModel.markAsTouched(); })); } diff --git a/lib/directive/ng_model_options.dart b/lib/directive/ng_model_options.dart index 2b25f7d69..cb2ba9708 100644 --- a/lib/directive/ng_model_options.dart +++ b/lib/directive/ng_model_options.dart @@ -3,9 +3,9 @@ part of angular.directive; @Decorator(selector: 'input[ng-model-options]') class NgModelOptions { int _debounceDefaultValue = 0; - int _debounceBlurValue = null; - int _debounceChangeValue = null; - int _debounceInputValue = null; + int _debounceBlurValue; + int _debounceChangeValue; + int _debounceInputValue; static const String _DEBOUNCE_DEFAULT_KEY = "default"; static const String _DEBOUNCE_BLUR_KEY = "blur"; From e706b9346ad27e78ee632d01c7b3e996fd4af3c7 Mon Sep 17 00:00:00 2001 From: jrote1 Date: Tue, 29 Apr 2014 00:25:15 +0100 Subject: [PATCH 6/6] Fixed some formatting --- lib/directive/ng_model.dart | 2 +- lib/directive/ng_model_options.dart | 28 ++++++++++++++++++---------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/lib/directive/ng_model.dart b/lib/directive/ng_model.dart index f85691556..ef0bebedf 100644 --- a/lib/directive/ng_model.dart +++ b/lib/directive/ng_model.dart @@ -195,7 +195,7 @@ class NgModel extends NgControl implements AttachAware { get viewValue => _viewValue; void set viewValue(value) { - _viewValue = value; + _viewValue = value; modelValue = value; } diff --git a/lib/directive/ng_model_options.dart b/lib/directive/ng_model_options.dart index cb2ba9708..15f136ccd 100644 --- a/lib/directive/ng_model_options.dart +++ b/lib/directive/ng_model_options.dart @@ -7,35 +7,43 @@ class NgModelOptions { int _debounceChangeValue; int _debounceInputValue; + async.Timer _blurTimer; + async.Timer _changeTimer; + async.Timer _inputTimer; + static const String _DEBOUNCE_DEFAULT_KEY = "default"; 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("'", "\"")); + var jsonFormattedOptions = attrs["ng-model-options"].replaceFirst("debounce", "'debounce'") + .replaceAll("'", "\""); + Map options = convert.JSON.decode(jsonFormattedOptions); - if (options["debounce"].containsKey(_DEBOUNCE_DEFAULT_KEY)){ - _debounceDefaultValue = options["debounce"][_DEBOUNCE_DEFAULT_KEY]; + if(options["debounce"] is int){ + _debounceDefaultValue = options["debounce"]; + }else{ + if (options["debounce"].containsKey(_DEBOUNCE_DEFAULT_KEY)){ + _debounceDefaultValue = options["debounce"][_DEBOUNCE_DEFAULT_KEY]; + } + _debounceBlurValue = options["debounce"][_DEBOUNCE_BLUR_KEY]; + _debounceChangeValue = options["debounce"][_DEBOUNCE_CHANGE_KEY]; + _debounceInputValue = options["debounce"][_DEBOUNCE_INPUT_KEY]; } - _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; - _blurTimer = _runFuncDebounced(delay, func,_blurTimer); + _blurTimer = _runFuncDebounced(delay, func, _blurTimer); } - async.Timer _changeTimer; void executeChangeFunc(func()) { var delay = _debounceChangeValue == null ? _debounceDefaultValue : _debounceChangeValue; _changeTimer = _runFuncDebounced(delay, func, _changeTimer); } - async.Timer _inputTimer; void executeInputFunc(func()) { var delay = _debounceInputValue == null ? _debounceDefaultValue : _debounceInputValue; _inputTimer = _runFuncDebounced(delay, func, _inputTimer);