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 3 commits
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
126 changes: 63 additions & 63 deletions lib/directive/ng_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Copy link
Contributor

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

{
_expression = attrs["ng-model"];
watchCollection = false;
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -196,6 +195,7 @@ class NgModel extends NgControl implements AttachAware {

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

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();
}
}
Expand All @@ -393,6 +400,7 @@ class InputTextLike {
class InputNumberLike {
final dom.InputElement inputElement;
final NgModel ngModel;
final NgModelOptions ngModelOptions;
final Scope scope;


Expand All @@ -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() {
Expand Down Expand Up @@ -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";
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 +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)));
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 +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;
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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)
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 +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;
Expand Down
52 changes: 52 additions & 0 deletions lib/directive/ng_model_options.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
part of angular.directive;

@Decorator(selector: 'input[ng-model-options]')
Copy link
Contributor

Choose a reason for hiding this comment

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

Choose a reason for hiding this comment

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

= null is not required

Copy link
Contributor Author

Choose a reason for hiding this comment

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

is int default value not 0?
sorry for some of these question am normally c# developer

Copy link
Contributor

Choose a reason for hiding this comment

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

Choose a reason for hiding this comment

The 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("'", "\""));
Copy link
Contributor

Choose a reason for hiding this comment

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

shouldn't we just have valid JSON as input ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

only thing i was trying to achieve to match the angularjs spec

Copy link
Contributor

Choose a reason for hiding this comment

The 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

Copy link
Contributor

Choose a reason for hiding this comment

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

the comment has been removed: please check ng-pluralize

Copy link
Contributor Author

Choose a reason for hiding this comment

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

what should i check ng-pluralize for?

Copy link
Contributor

Choose a reason for hiding this comment

The 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:

In lib/directive/ng_model_options.dart:

+part of angular.directive;
+
+@decorator(selector: 'input[ng-model-options]')
+class NgModelOptions {

  • int _debounceDefaultValue = 0;
  • int _debounceBlurValue;
  • int _debounceChangeValue;
  • int _debounceInputValue;
  • 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("'", """));

what should i check ng-pluralize for?


Reply to this email directly or view it on GitHub
https://github.com/angular/angular.dart/pull/974/files#r12073468.


if (options["debounce"].containsKey(DEBOUNCE_DEFAULT_KEY)) _debounceDefaultValue = options["debounce"][DEBOUNCE_DEFAULT_KEY];
Copy link
Contributor

Choose a reason for hiding this comment

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

if () {
   ...
}

you can omit {} when:

  • no else branch
  • line < 100ch

_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;
Copy link
Contributor

Choose a reason for hiding this comment

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

Choose a reason for hiding this comment

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

if () {
} else {
}

notice ws & formatting

func();
Copy link
Contributor

Choose a reason for hiding this comment

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

add missing {}

}
else{
setTimer(new async.Timer(new Duration(milliseconds: delay), func));
Copy link
Contributor

Choose a reason for hiding this comment

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

what about dropping the 3rd args & returning the timer

}
}
}
Loading