Skip to content
This repository has been archived by the owner on Feb 22, 2018. It is now read-only.

feat(ng-model-options) Added ng-model-options #974

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion benchmark/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion example/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ packages:
barback:
description: barback
source: hosted
version: "0.13.0"
version: "0.12.0"
browser:
description: browser
source: hosted
Expand Down
2 changes: 1 addition & 1 deletion example/web/hello_world.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<body hello-world-controller>

<h3>Hello {{ctrl.name}}!</h3>
name: <input type="text" ng-model="ctrl.name">
name: <input type="text" ng-model="ctrl.name" ng-model-options="{ debounce: {'default': 500, 'blur': 0} }">

<script type="application/dart" src="hello_world.dart"></script>
<script src="packages/browser/dart.js"></script>
Expand Down
4 changes: 4 additions & 0 deletions lib/directive/module.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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());
Expand Down
150 changes: 66 additions & 84 deletions lib/directive/ng_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

{ on new line

_expression = attrs["ng-model"];
print("model: " + _expression);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

debug

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry will remove that.

watchCollection = false;

//Since the user will never be editing the value of a select element then
Expand Down Expand Up @@ -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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it would be better to separate "real" changes from formatting only changes.

Please make formatting changes only where required and keep in mind that line length should be limited to 100 chars

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will remove formatting changes

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you want me to remove all formatting changes?

}, collection: true);
} else if (_expression != null) {
_watch = _scope.watch(_expression, onChange);
}
Expand Down Expand Up @@ -196,6 +192,7 @@ class NgModel extends NgControl implements AttachAware {

get viewValue => _viewValue;
void set viewValue(value) {
//delay set
_viewValue = value;
modelValue = value;
}
Expand All @@ -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;
Expand Down Expand Up @@ -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) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

long line

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(() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing ws around =>

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dosent need it?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be (_) => ngModelOptions.executeChangeFuncaccording to Dart CC, see https://www.dartlang.org/articles/style-guide/

ngModel.viewValue = inputElement.checked ? ngTrueValue.value : ngFalseValue.value;
}))
..onBlur.listen((_)=>ngModelOptions.executeBlurFunc(() {
ngModel.markAsTouched();
});
}));
}
}




/**
* Usage:
*
Expand All @@ -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)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

revert

typedValue = value;
}
});
};

print("text type");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

debug

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will fix all of these


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}");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

debug

var value = typedValue;

if (value != ngModel.viewValue) ngModel.viewValue = value;

ngModel.validate();
}
}
Expand All @@ -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;


Expand All @@ -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() {
Expand All @@ -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';
Expand All @@ -473,19 +468,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";
Copy link
Contributor

Choose a reason for hiding this comment

The 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;
}
}

Expand Down Expand Up @@ -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)));
Copy link
Contributor

Choose a reason for hiding this comment

The 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) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

too long

if (inputElement.type == 'datetime-local') {
ngBindType.idlAttrKind = NgBindTypeForDateLike.NUMBER;
}
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}

Expand Down Expand Up @@ -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)
Copy link
Contributor

Choose a reason for hiding this comment

The 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) {
Copy link
Contributor

Choose a reason for hiding this comment

The 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) {
Expand Down Expand Up @@ -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;
Expand Down
Loading