From 715d3d1ee856c961c697217f16c68bca74ef6d92 Mon Sep 17 00:00:00 2001 From: Giovanni Silva <giovanni@atende.info> Date: Fri, 10 Jan 2014 21:45:46 -0200 Subject: [PATCH] feat(directives): Add support for contenteditable with ng-model --- lib/directive/module.dart | 1 + lib/directive/ng_model.dart | 20 ++++++++++++++++++++ test/directive/ng_model_spec.dart | 27 ++++++++++++++++++++++++++- 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/lib/directive/module.dart b/lib/directive/module.dart index 4ae39ab14..1190e923e 100644 --- a/lib/directive/module.dart +++ b/lib/directive/module.dart @@ -58,6 +58,7 @@ class NgDirectiveModule extends Module { value(TextAreaDirective, null); value(InputSelectDirective, null); value(OptionValueDirective, null); + value(ContentEditableDirective, null); value(NgModel, null); value(NgSwitchDirective, null); value(NgSwitchWhenDirective, null); diff --git a/lib/directive/ng_model.dart b/lib/directive/ng_model.dart index 00eea02a7..2f6406fc8 100644 --- a/lib/directive/ng_model.dart +++ b/lib/directive/ng_model.dart @@ -325,3 +325,23 @@ class InputRadioDirective { }); } } + +/** + * Usage (span could be replaced with any element which supports text content, such as `p`): + * + * <span contenteditable= ng-model="name"> + * + * This creates a two way databinding between the expression specified in + * ng-model and the html element in the DOM. If the ng-model value is + * `null`, it is treated as equivalent to the empty string for rendering + * purposes. + */ +@NgDirective(selector: '[contenteditable][ng-model]') +class ContentEditableDirective extends _InputTextlikeDirective { + ContentEditableDirective(dom.Element inputElement, NgModel ngModel, Scope scope): + super(inputElement, ngModel, scope); + + // The implementation is identical to _InputTextlikeDirective but use innerHtml instead of value + get typedValue => (inputElement as dynamic).innerHtml; + set typedValue(String value) => (inputElement as dynamic).innerHtml = (value == null) ? '' : value; +} diff --git a/test/directive/ng_model_spec.dart b/test/directive/ng_model_spec.dart index 1f63ba402..f2bded141 100644 --- a/test/directive/ng_model_spec.dart +++ b/test/directive/ng_model_spec.dart @@ -44,7 +44,6 @@ describe('ng-model', () { var input = probe.directive(InputTextDirective); input.processValue(); expect(_.rootScope.model).toEqual('def'); - })); it('should write to input only if value is different', inject(() { @@ -438,5 +437,31 @@ describe('ng-model', () { expect(blueBtn.checked).toBe(false); })); }); + + describe('contenteditable', () { + it('should update content from model', inject(() { + _.compile('<p contenteditable ng-model="model">'); + _.rootScope.$digest(); + + expect((_.rootElement as dom.Element).text).toEqual(''); + + _.rootScope.$apply('model = "misko"'); + expect((_.rootElement as dom.Element).text).toEqual('misko'); + })); + + it('should update model from the input value', inject(() { + _.compile('<p contenteditable ng-model="model">'); + Element element = _.rootElement; + + element.innerHtml = 'abc'; + _.triggerEvent(element, 'change'); + expect(_.rootScope.model).toEqual('abc'); + + element.innerHtml = 'def'; + var input = ngInjector(element).get(ContentEditableDirective); + input.processValue(); + expect(_.rootScope.model).toEqual('def'); + })); + }); });