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

feat(form): Add support for input[type=color] #1080

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions example/web/hello_world.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import 'package:angular/application_factory.dart';
publishAs: 'ctrl')
class HelloWorld {
String name = "world";
String color = "#aaaaaa";
}

main() {
Expand Down
5 changes: 3 additions & 2 deletions example/web/hello_world.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
</head>
<body hello-world-controller>

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

<script type="application/dart" src="hello_world.dart"></script>
<script src="packages/browser/dart.js"></script>
Expand Down
1 change: 1 addition & 0 deletions lib/directive/module.dart
Original file line number Diff line number Diff line change
Expand Up @@ -118,5 +118,6 @@ class DirectiveModule extends Module {
bind(NgModelPatternValidator, toValue: null);
bind(NgModelMinLengthValidator, toValue: null);
bind(NgModelMaxLengthValidator, toValue: null);
bind(NgModelColorValidator, toValue: null);
}
}
5 changes: 3 additions & 2 deletions lib/directive/ng_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ class InputCheckbox {
*
* **Usage**
*
* <input type="text|url|password|email|search|tel" ng-model="myModel">
* <input type="text|url|password|email|search|tel|color" ng-model="myModel">
* <textarea ng-model="myModel"></textarea>
*
* When the `ng-model` attribute is present on the input element,
Expand All @@ -348,6 +348,7 @@ class InputCheckbox {
@Decorator(selector: 'input[type=email][ng-model]')
@Decorator(selector: 'input[type=search][ng-model]')
@Decorator(selector: 'input[type=tel][ng-model]')
@Decorator(selector: 'input[type=color][ng-model]')
class InputTextLike {
final dom.Element inputElement;
final NgModel ngModel;
Expand Down Expand Up @@ -707,7 +708,7 @@ class NgValue {

@NgOneWay('ng-value')
void set value(val) {
this._value = val;
_value = val;
}
dynamic get value => _value == null ? (element as dynamic).value : _value;
}
Expand Down
16 changes: 16 additions & 0 deletions lib/directive/ng_model_validators.dart
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,22 @@ class NgModelUrlValidator implements NgValidator {
modelValue == null || modelValue.isEmpty || URL_REGEXP.hasMatch(modelValue);
}

/**
* Validates the model to see if its contents match a valid color pattern.
*/
@Decorator(selector: 'input[type=color][ng-model]')
class NgModelColorValidator implements NgValidator {
static final COLOR_REGEXP = new RegExp(r'^#[0-9a-f]{6}$', caseSensitive: false);
final String name = 'ng-color';

NgModelColorValidator(NgModel ngModel) {
ngModel.addValidator(this);
}

bool isValid(modelValue) =>
modelValue == null || modelValue.isEmpty || COLOR_REGEXP.hasMatch(modelValue);
}

/**
* Validates the model to see if its contents match a valid email pattern.
*/
Expand Down
1 change: 1 addition & 0 deletions test/angular_spec.dart
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ main() {
"angular.directive.NgInclude",
"angular.directive.NgModel",
"angular.directive.NgModelOptions",
"angular.directive.NgModelColorValidator",
"angular.directive.NgModelConverter",
"angular.directive.NgModelEmailValidator",
"angular.directive.NgModelMaxLengthValidator",
Expand Down
54 changes: 54 additions & 0 deletions test/directive/ng_model_spec.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1101,6 +1101,60 @@ void main() {
});
});

describe('type="color"', () {
it('should update input value from model', () {
_.compile('<input type="color" ng-model="model">');
_.rootScope.apply();

expect((_.rootElement as dom.InputElement).value).toEqual('#000000');

_.rootScope.apply('model = "#123456"');
expect((_.rootElement as dom.InputElement).value).toEqual('#123456');
});

it('should render as #000000 on default and when a null value is present', () {
_.compile('<input type="color" ng-model="model">');
_.rootScope.apply();

expect((_.rootElement as dom.InputElement).value).toEqual('#000000');

_.rootScope.apply('model = null');
expect((_.rootElement as dom.InputElement).value).toEqual('#000000');
});

it('should update model from the input value', () {
_.compile('<input type="color" ng-model="model" probe="p">');
Probe probe = _.rootScope.context['p'];
var ngModel = probe.directive(NgModel);
InputElement inputElement = probe.element;

inputElement.value = '#000000';
_.triggerEvent(inputElement, 'change');
expect(_.rootScope.context['model']).toEqual('#000000');

inputElement.value = '#ffffff';
var input = probe.directive(InputTextLike);
input.processValue();
expect(_.rootScope.context['model']).toEqual('#ffffff');
});

it('should only render the input value upon the next digest', (Scope scope) {
_.compile('<input type="color" ng-model="model" probe="p">');
Probe probe = _.rootScope.context['p'];
var ngModel = probe.directive(NgModel);
InputElement inputElement = probe.element;

ngModel.render('#aabbcc');
scope.context['model'] = '#aabbcc';

expect(inputElement.value).not.toEqual('#aabbcc');

scope.apply();

expect(inputElement.value).toEqual('#aabbcc');
});
});

describe('contenteditable', () {
it('should update content from model', () {
_.compile('<p contenteditable ng-model="model">');
Expand Down
27 changes: 26 additions & 1 deletion test/directive/ng_model_validators_spec.dart
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,31 @@ void main() {
});
});

describe('[type="color"]', () {
it('should validate the input field given a valid or invalid color', (RootScope scope) {
_.compile('<input type="color" ng-model="val" probe="i" />');
Probe probe = _.rootScope.context['i'];
var model = probe.directive(NgModel);

expect(model.valid).toEqual(true);
expect(model.invalid).toEqual(false);

_.rootScope.apply(() {
_.rootScope.context['val'] = 'red';
});

expect(model.valid).toEqual(false);
expect(model.invalid).toEqual(true);

_.rootScope.apply(() {
_.rootScope.context['val'] = '#ff0000';
});

expect(model.valid).toEqual(true);
expect(model.invalid).toEqual(false);
});
});

describe('[type="email"]', () {
it('should validate the input field given a valid or invalid email address', (RootScope scope) {
_.compile('<input type="email" ng-model="val" probe="i" />');
Expand Down Expand Up @@ -627,6 +652,6 @@ void main() {

expect(model.valid).toBe(true);
});
});
});
});
}