Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

INT-2974: Support OnPush change detection #368

Merged
merged 9 commits into from
Apr 5, 2024
12 changes: 12 additions & 0 deletions stories/Editor.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { EventBindingComponent } from './event-binding/EventBinding.component';
import { EventForwardingComponent } from './event-forwarding/EventForwarding.component';
import { FormControlComponent } from './form-control/FormControl.component';
import { FormWithOnPushComponent } from './form-with-on-push/form-with-on-push.component';
import { BlogComponent } from './formvalidation/FormValidation.component';
import { DisablingComponent } from './disable/Disable.component';
import { ViewQueryComponent } from './viewquery/Viewquery.component';
Expand Down Expand Up @@ -97,6 +98,17 @@ export const FormControlStory: StoryObj<EditorComponent> = {
}
};

export const FormStateStory: StoryObj<EditorComponent> = {
name: 'Form with on-push change detection',
render: () => ({
moduleMetadata: {
imports: [ ReactiveFormsModule, FormsModule ],
declarations: [ FormWithOnPushComponent ],
},
template: `<form-with-on-push apiKey="${apiKey}"/>`
}),
};

export const FormValidationStory: StoryObj<EditorComponent> = {
name: 'Form Validation',
render: () => ({
Expand Down
31 changes: 31 additions & 0 deletions stories/form-with-on-push/form-with-on-push.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/* eslint-disable @typescript-eslint/unbound-method */
/* eslint-disable @typescript-eslint/no-parameter-properties */
import {
Component,
ChangeDetectionStrategy,
Input,
} from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import type { EditorComponent } from '../../tinymce-angular-component/src/main/ts/public_api';

@Component({
selector: 'form-with-on-push',
templateUrl: './form-with-on-push.html',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class FormWithOnPushComponent {
@Input() public apiKey = '';
public readonly initialValue = '';
public readonly init: EditorComponent['init'] = {
plugins: [ 'help' ],
};
public readonly form = new FormGroup({
tiny: new FormControl('', {
validators: Validators.compose([
Validators.required,
Validators.minLength(10)
]),
}),
regular: new FormControl(''),
});
}
24 changes: 24 additions & 0 deletions stories/form-with-on-push/form-with-on-push.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<form [formGroup]="form" style="display: flex; gap: 0.2em; flex-direction: column;">
<editor
formControlName="tiny"
plugins="table"
init="{ width: '200px', }"
/>
<br />
<label>
<span>Regular input</span>
<br />
<input type="text" formControlName="regular" />
</label>
<br />
<button type="reset" style="width: 200px">Reset form</button>
<button [disabled]="form.invalid" type="submit" style="width: 200px">Submit form</button>
</form>
<br />
<pre>
Pristine: {{ form.pristine }}
Touched: {{ form.touched }}
Dirty: {{ form.dirty }}
Valid: {{ form.valid }}
Data: {{ form.value | json }}
</pre>
22 changes: 20 additions & 2 deletions tinymce-angular-component/src/main/ts/editor/editor.component.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,20 @@
/* eslint-disable @typescript-eslint/no-parameter-properties */
import { isPlatformBrowser, CommonModule } from '@angular/common';
import { AfterViewInit, Component, ElementRef, forwardRef, Inject, Input, NgZone, OnDestroy, PLATFORM_ID, InjectionToken, Optional } from '@angular/core';
import {
AfterViewInit,
Component,
ElementRef,
forwardRef,
Inject,
Input,
NgZone,
OnDestroy,
PLATFORM_ID,
InjectionToken,
Optional,
ChangeDetectorRef,
ChangeDetectionStrategy
} from '@angular/core';
import { FormsModule, ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { Subject, takeUntil } from 'rxjs';
import { getTinymce } from '../TinyMCE';
Expand All @@ -25,7 +39,8 @@ const EDITOR_COMPONENT_VALUE_ACCESSOR = {
styles: [ ':host { display: block; }' ],
providers: [ EDITOR_COMPONENT_VALUE_ACCESSOR ],
standalone: true,
imports: [ CommonModule, FormsModule ]
imports: [ CommonModule, FormsModule ],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class EditorComponent extends Events implements AfterViewInit, ControlValueAccessor, OnDestroy {

Expand Down Expand Up @@ -77,6 +92,7 @@ export class EditorComponent extends Events implements AfterViewInit, ControlVal
public constructor(
elementRef: ElementRef,
ngZone: NgZone,
private cdRef: ChangeDetectorRef,
@Inject(PLATFORM_ID) private platformId: Object,
@Optional() @Inject(TINYMCE_SCRIPT_SRC) private tinymceScriptSrc?: string
) {
Expand Down Expand Up @@ -187,10 +203,12 @@ export class EditorComponent extends Events implements AfterViewInit, ControlVal

private initEditor(editor: TinyMCEEditor) {
listenTinyMCEEvent(editor, 'blur', this.destroy$).subscribe(() => {
this.cdRef.markForCheck();
this.ngZone.run(() => this.onTouchedCallback());
});

listenTinyMCEEvent(editor, this.modelEvents, this.destroy$).subscribe(() => {
this.cdRef.markForCheck();
this.ngZone.run(() => this.emitOnChange(editor));
});

Expand Down