From ba350a8309c6f4d83419278a7155275304dd33af Mon Sep 17 00:00:00 2001 From: Sibiraj Date: Sat, 25 Nov 2017 01:52:00 +0530 Subject: [PATCH] feat: formControl support BREAKING CHANGE: use `ngModel` instead of `html` for HTML content binding --- src/app/app.component.html | 2 +- src/app/app.component.spec.ts | 4 +- src/app/app.module.ts | 4 +- src/app/ngx-editor/ngx-editor.component.html | 2 +- src/app/ngx-editor/ngx-editor.component.ts | 88 +++++++++++++------ .../ngx-grippie/ngx-grippie.component.spec.ts | 10 +-- 6 files changed, 73 insertions(+), 37 deletions(-) diff --git a/src/app/app.component.html b/src/app/app.component.html index 3cb75d25..280175b5 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -12,7 +12,7 @@
WYSIWYG Editor for Angular Applications.
- +
diff --git a/src/app/app.component.spec.ts b/src/app/app.component.spec.ts index 5e8eb343..837cb3e1 100644 --- a/src/app/app.component.spec.ts +++ b/src/app/app.component.spec.ts @@ -1,4 +1,6 @@ import { TestBed, async } from '@angular/core/testing'; +import { FormsModule } from '@angular/forms'; + import { AppComponent } from './app.component'; import { NgxEditorModule } from './ngx-editor/ngx-editor.module'; import { HttpClientModule } from '@angular/common/http'; @@ -6,7 +8,7 @@ import { HttpClientModule } from '@angular/common/http'; describe('AppComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [HttpClientModule, NgxEditorModule], + imports: [FormsModule, HttpClientModule, NgxEditorModule], declarations: [ AppComponent ], diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 253b4545..e6fb1295 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -1,6 +1,7 @@ import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { HttpClientModule } from '@angular/common/http'; +import { FormsModule } from '@angular/forms'; import { AppComponent } from './app.component'; import { NgxEditorModule } from './ngx-editor/ngx-editor.module'; @@ -12,7 +13,8 @@ import { NgxEditorModule } from './ngx-editor/ngx-editor.module'; imports: [ BrowserModule, HttpClientModule, - NgxEditorModule + NgxEditorModule, + FormsModule ], providers: [], bootstrap: [AppComponent] diff --git a/src/app/ngx-editor/ngx-editor.component.html b/src/app/ngx-editor/ngx-editor.component.html index 2527ab04..19014bf9 100644 --- a/src/app/ngx-editor/ngx-editor.component.html +++ b/src/app/ngx-editor/ngx-editor.component.html @@ -5,7 +5,7 @@
+ [style.resize]="Utils?.canResize(resizer)" (focus)="onFocus()" (blur)="onBlur()" #ngxTextArea>
diff --git a/src/app/ngx-editor/ngx-editor.component.ts b/src/app/ngx-editor/ngx-editor.component.ts index e5315bbd..cfaa4b4e 100644 --- a/src/app/ngx-editor/ngx-editor.component.ts +++ b/src/app/ngx-editor/ngx-editor.component.ts @@ -1,7 +1,9 @@ import { - Component, OnInit, OnChanges, Input, - Output, ViewChild, HostListener, ElementRef, EventEmitter, SimpleChanges + Component, OnInit, Input, Output, + ViewChild, HostListener, ElementRef, EventEmitter, + Renderer2, forwardRef } from '@angular/core'; +import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms'; import { CommandExecutorService } from './common/services/command-executor.service'; import { MessageService } from './common/services/message.service'; @@ -12,10 +14,17 @@ import * as Utils from './common/utils/ngx-editor.utils'; @Component({ selector: 'app-ngx-editor', templateUrl: './ngx-editor.component.html', - styleUrls: ['./ngx-editor.component.scss'] + styleUrls: ['./ngx-editor.component.scss'], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => NgxEditorComponent), + multi: true + } + ] }) -export class NgxEditorComponent implements OnInit, OnChanges { +export class NgxEditorComponent implements OnInit, ControlValueAccessor { @Input() editable: boolean; @Input() spellcheck: boolean; @@ -26,22 +35,23 @@ export class NgxEditorComponent implements OnInit, OnChanges { @Input() width: string; @Input() minWidth: string; @Input() toolbar: any; - @Input() html = ''; @Input() resizer = 'stack'; @Input() config = ngxEditorConfig; @ViewChild('ngxTextArea') textArea: any; - @Output() htmlChange: EventEmitter = new EventEmitter(); - enableToolbar = false; Utils = Utils; - lastViewModel: any; + + private lastViewModel: any = ''; + private onChange: (value: string) => void; + private onTouched: () => void; constructor( private _elementRef: ElementRef, private _messageService: MessageService, - private _commandExecutor: CommandExecutorService) { } + private _commandExecutor: CommandExecutorService, + private _renderer: Renderer2) { } /* * events @@ -56,12 +66,20 @@ export class NgxEditorComponent implements OnInit, OnChanges { } onContentChange(html): void { - this.update(html); + + if (typeof this.onChange === 'function') { + this.onChange(html); + } + return; } - onBlur(html): void { - this.update(html); + onBlur(): void { + + if (typeof this.onTouched === 'function') { + this.onTouched(); + } + return; } @@ -88,15 +106,39 @@ export class NgxEditorComponent implements OnInit, OnChanges { return; } - // update view - refreshView(): void { - this.textArea.nativeElement.innerHTML = this.html || ''; - return; + /* + * Write a new value to the element. + */ + writeValue(value: any): void { + if (value === undefined) { + return; + } + + this.refreshView(value); } - update(value): void { - this.lastViewModel = value; - this.htmlChange.emit(value); + /* + * Set the function to be called + * when the control receives a change event. + */ + registerOnChange(fn: any): void { + this.onChange = fn; + } + + /* + * Set the function to be called + * when the control receives a touch event. + */ + registerOnTouched(fn: any): void { + this.onTouched = fn; + } + + /* + * refresh view/HTML of the editor + */ + refreshView(value): void { + const normalizedValue = value == null ? '' : value; + this._renderer.setProperty(this.textArea.nativeElement, 'innerHTML', normalizedValue); return; } @@ -109,12 +151,4 @@ export class NgxEditorComponent implements OnInit, OnChanges { this.executeCommand('enableObjectResizing'); } - ngOnChanges(changes: SimpleChanges) { - if (changes.html) { - if (this.lastViewModel !== changes.html.currentValue) { - this.refreshView(); - } - } - } - } diff --git a/src/app/ngx-editor/ngx-grippie/ngx-grippie.component.spec.ts b/src/app/ngx-editor/ngx-grippie/ngx-grippie.component.spec.ts index 83fabfdf..a6949368 100644 --- a/src/app/ngx-editor/ngx-grippie/ngx-grippie.component.spec.ts +++ b/src/app/ngx-editor/ngx-grippie/ngx-grippie.component.spec.ts @@ -1,15 +1,11 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { ElementRef } from '@angular/core'; +import { ElementRef, Renderer2 } from '@angular/core'; import { NgxGrippieComponent } from './ngx-grippie.component'; import { NgxEditorComponent } from '../ngx-editor.component'; import { MessageService } from '../common/services/message.service'; import { CommandExecutorService } from '../common/services/command-executor.service'; -export class MockElementRef extends ElementRef { - constructor() { super(null); } -} - describe('NgxGrippieComponent', () => { let component: NgxGrippieComponent; let fixture: ComponentFixture; @@ -21,7 +17,9 @@ describe('NgxGrippieComponent', () => { NgxEditorComponent, MessageService, CommandExecutorService, - { provide: ElementRef, useClass: MockElementRef }] + { provide: ElementRef, useValue: this.elementRef }, + { provide: Renderer2, useValue: this.renderer } + ] }) .compileComponents(); }));