Search code examples
angularfroala

Call custom methods from a Froala custom button


I am developing an Angular 7 app and in this app I am using the WYSIWYG editor library called Froala.

I have added a custom button to the toolbar and now I want to call a method in the same class the user clicks on this button (to open up a custom modal). I use the code below but I get an error saying it does not find the openPictureModal method.

$.FroalaEditor.DefineIcon('imagePicker', {NAME: 'info'});
    $.FroalaEditor.RegisterCommand('imagePicker', {
      title: 'Image picker',
      focus: false,
      undo: false,
      refreshAfterCallback: false,
      callback: function (data) {
        this.openPictureModal();
      }
    });

I get this error:

Uncaught TypeError: this.openPictureModal is not a function

This is my modal method:

openPictureModal() {
    const modalRef = this.modalService.open(PictureManageComponent, { size: 'lg' });
          modalRef.componentInstance.formFinished.subscribe(($event) => {
            modalRef.close();
          });
  }

How can I call custom methods in the same class from a custom button?


Solution

  • There are two issues in your code. The first one, which is very common, is that this is lost inside of the callback. Defining the callback as an arrow function should take care of that problem. See this question for more details.

    The second issue is more subtle. The callback, being a jQuery event handler, is probably called outside of the Angular zone. As a consequence, it does not trigger change detection. You can wrap the callback code in NgZone.run() to solve that problem.

    The resulting code would be something like this:

    import { NgZone } from '@angular/core';
    
    constructor(private ngZone: NgZone) { }
    
    ...
    
    initializeFroala() {
      $.FroalaEditor.DefineIcon('imagePicker', {NAME: 'info'});
      $.FroalaEditor.RegisterCommand('imagePicker', {
        title: 'Image picker',
        focus: false,
        undo: false,
        refreshAfterCallback: false,
        callback: (data) => {            // Define the callback as arrow function
          this.ngZone.run(() => {        // Run the callback code in Angular zone
            this.openPictureModal();
          });
        }
      });
    }