froala / angular-froala-wysiwyg

Angular 4, 5, 6, 7, 8 and 9 plugin for Froala WYSIWYG HTML Rich Text Editor.
https://froala.com/wysiwyg-editor
729 stars 200 forks source link

Frolala Custom dropdown values are not getting updated properly in froala with latest version(4.x.x) #506

Open dhilipbabu1 opened 1 year ago

dhilipbabu1 commented 1 year ago

If you have a feature suggestion, please add it on the Feature List instead.

Expected behavior.

we have a functionality, on click of add button, it will add a formgroup say ( Parent ) with Froala editor enabled. Each parent will have a button to add a child node to it, child nodes can be sorted out based on the priority chosen/given by the user. we are using angular 12 and reactive forms

For example, Parent node 1 Child node 1 - Priority 1 Child node 2 - Priority 2, etc.

In this workflow, when Child node 2 is been added, the priority dropdown( custom drop-down in Froala ) is expected to have the number of child nodes added count as a drop-down option. So, the user can change the dropdown option at any point of time. i.e, when I add child Node 10, from node 1 to node 9's dropdown should have options from 1,2,3...10.

Eg: 1 For 1 parent - 1 child parent 1: Richtext editor -1

Eg: 2

For 1 parent - 2 child parent 1: Richtext editor -1

Eg: 3 For 1 parent - 3 child parent 1: Richtext editor -1

Actual behavior.

The issue is very simple, the custom dropdown values are not getting updated in each Froala editor instance(FroalaEditor) changing, So it's creating a new Froala instance every time and custom dropdown values are not updated for the same instance, Do we need to update further in custom dropdown configuration or any code change need to perform? The same code is working in Froala 3.2.0 version and the issue is occurring only we upgrade the Froala version to 4.x.x version.

test

Eg: 1 For 1 parent - 1 child parent 1: Richtext editor -1

Eg: 2

For 1 parent - 2 child parent 1: Richtext editor -1

Eg: 3 For 1 parent - 3 child parent 1: Richtext editor -1

Steps to reproduce the problem.

(Describe the steps to reproduce the problem here. A jsFiddle is awesome when possible.)

Parent component -> cause-solution.component.html

<app-froala-rich-text-editor id="{{getCauses().controls[causeIndex].value.causeName}}_{{getSolutions(causeIndex).controls[solutionIndex].value.solutionName}}" [(content)]="getSolutions(causeIndex).controls[solutionIndex]" [optionalControls]="solutionsOptionalControls" [dropdownOptions]="causeEditorFlags[getCauses().controls[causeIndex].value.causeName].priorityDropdownOptions" (closeClicked)="removeSolution(causeIndex, solutionIndex, getSolutions(causeIndex).controls[solutionIndex].value.solutionName, getCauses().controls[causeIndex].value.causeName)" (toggleEditorFullscreen)="toggleFullScreen(getSolutions(causeIndex).controls[solutionIndex].value.solutionName)" [ngClass]="{'enable-fullscreen': enableFullScreenView && editorValueInFullScreen === getSolutions(causeIndex).controls[solutionIndex].value.solutionName}" (addParts)="addPartsClicked(causeIndex, solutionIndex)" (removePart)="removePart($event, causeIndex, solutionIndex)" [options]="solutionEditorOptions" [addedParts]="getSolutions(causeIndex).controls[solutionIndex].value.parts" (validatePriority)="validatePriorityOnChange(causeIndex, getSolutions(causeIndex).controls[solutionIndex].value.priority, solutionIndex)" [(attachmentDetails)]="causeEditorFlags[getCauses().controls[causeIndex].value.causeName].attachmentDetails" (addTagsForSympOrCauseOrSol)="onAddTagsEventEmit(causeIndex, solutionIndex)" (removeTag)="removeTagForCauseORSolution($event, causeIndex, solutionIndex, true)" [tags]="getSolutions(causeIndex).controls[solutionIndex].value.solutionTags">


Child component(froala rich text editor component) ---> froala-rich-text-editor.component.html

<div class="froala-container" [formGroup]="content"> <div id="{{content.value.causeName || content.value.solutionName}}" [froalaEditor]="options" formControlName="richTextDescription" (froalaInit)="initializeEditor($event)">

froala-rich-text-editor.component.ts import FroalaEditor from '../../../../node_modules/froala-editor';

@Component({ selector: 'app-froala-rich-text-editor', templateUrl: './froala-rich-text-editor.component.html', styleUrls: ['./froala-rich-text-editor.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush }) export class FroalaRichTextEditorComponent implements OnInit, OnChanges, OnDestroy { @Input() public options!: RichTextEditorOptions; @Input() @Output() public content: FormGroup; @Input() public optionalControls: OptionalControls = new OptionalControls(); public editorInstance: FroalaEditor;

public ngOnInit(): void { this.options = this._setEditorOptions(this.options); if (this.optionalControls?.showPriority) { this._setPriorityDropdownOptions(); } this._setFroalaEvents(); }

private _setEditorOptions(optionsList: RichTextEditorOptions): RichTextEditorOptions { if (!optionsList) { optionsList = new RichTextEditorOptions(); }
// Added JSON.parse to optionsList inoder to create a deep copy of nested object instead of shallow copy optionsList = this._setRichTextEditorCustomOptions(this.optionalControls, JSON.parse(JSON.stringify(optionsList))); return optionsList; }

private _setRichTextEditorCustomOptions(optionalControls: OptionalControls, options: RichTextEditorOptions): RichTextEditorOptions { const { showClose, showOnComplete, showPriority } = optionalControls || {}; if (showPriority) { // add priority option for all toolbar resolutions options.toolbarButtons.moreDropdown = { buttons: ['|', 'Priority_Caption', 'priority'], align: 'left', buttonsVisible: 3 }; } return options; }

private _setPriorityDropdownOptions(): void { this.options.priority = {'0': 0, '1': 1}; const optionKeys = Object.keys(this.dropdownOptions); if (optionKeys.indexOf(this.content.value.priority) > -1) { this.options.PriorityDefaultSelection = this.content.value.priority; } else { this.options.PriorityDefaultSelection = '--Select--'; this.content.value.priority = undefined; } }

private _setFroalaEvents(): void { this.options.events = { 'commands.after': (command: string, value: string) => { // to reflect changes in UI this.ngZone.run(() => { this._afterCommandClick(command, value); }); } } }
private _afterCommandClick(command: string, valueSelected: string): void { if (command === 'priority') { const editorId = this.editorInstance.getEditor().id; const btn = document.querySelectorAll(button[id="${command}-${editorId}"] span); btn[0].innerHTML = this.dropdownOptions[valueSelected]; if (valueSelected !== '0') { this.content.controls['priority'].setValue(valueSelected); } else { this.content.controls['priority'].setValue(''); } this.content.controls['priority'].markAsDirty(); this.validatePriority.emit(); } } public initializeEditor(editorControls: FroalaEditor): void { this.editorInstance = editorControls; if (this.editorInstance) { this.editorInstance.initialize(); } } public ngOnDestroy(): void { // Called once, before the instance is destroyed. if (this.editorInstance) { this.editorInstance.destroy(); } } }


class configuration: -> richtext-editor-options.ts import FroalaEditor from '../../../../node_modules/froala-editor';

public PriorityDefaultSelection: string; public constructor() { this.PriorityDefaultSelection = '--Select--'; } public setCustomButtons(): void { this.setPriorityCommand(); } *public setPriorityCommand(): void { FroalaEditor.DefineIconTemplate('Priority_Caption_Template', ''); // For dropdown label, FroalaEditor.DefineIcon('priorityCaption', { NAME: 'priority', template: 'Priority_Caption_Template' }); FroalaEditor.RegisterCommand('Priority_Caption_Template', { icon: 'priorityCaption' }); FroalaEditor.RegisterCommand('priority', { // For dropdown options: title: 'priority', displaySelection: (editor: any) => { return editor.opts.PriorityDefaultSelection; }, type: 'dropdown', focus: true, undo: false, refreshAfterCallback: true, html: function () { // will be used for building options let html = '

'; return html; }, refreshOnShow: function ($btn: any, $dropdown: any) { const list = $dropdown.find('ul.fr-dropdown-list'); const containerElement = document.createElement('div'); // buildList() method refers above html template section for building options containerElement.innerHTML = this.button.buildList([EDITOR_CONSTANTS.PRIORITY_CONTROL.COMMAND]); list.replaceWith(containerElement.querySelector('ul.fr-dropdown-list')); $dropdown.find('.fr-command.fr-active').removeClass('fr-active').attr('aria-selected', false); $dropdown.find('.fr-command[title="' + $btn[0].innerText + '"]').addClass('fr-active').attr('aria-selected', true); }, defaultSelection: (e: any) => { return e.opts.PriorityDefaultSelection; } }); }**


Editor version.

Previous version(working): angular-froala-wysiwyg@3.2.0 Current version(not working): angular-froala-wysiwyg@4.0.14

OS.

(Windows 64bit)

Browser.

Chrome

Recording.

Working as expected in 3.2.0 https://user-images.githubusercontent.com/117508086/200112630-8a5fdb11-48ba-44db-b1a1-b2643068d9c9.mp4

Issue after upgrading(4.0.14) https://user-images.githubusercontent.com/117508086/200112662-a073692f-4b41-4fdb-8d3d-b442d76968bf.mp4