Sign up (with export icon)

Events and observables

Contribute to this guide Show the table of contents

Reactivity

Copy link

In the previous chapter of this tutorial, we wrote the following code to bind selected properties between the button and command objects:

button.bind( 'isOn', 'isEnabled' ).to( command, 'value', 'isEnabled' );
Copy code

This line allowed us to make the button reactive and reflect the state of the command. For example, if the command is not allowed to run, the corresponding button should not be clickable.

The reactivity described above is enabled by the observables used in the CKEditor framework. Observables are objects that fire an event when their properties change. These changes can be observed and acted upon, which is exactly what we did with the highlight button.

Under the hood, observables use an even more powerful event system similar to the one in the DOM.

Observables

Copy link

Let’s analyze the code we wrote to create the reactive button.

Creating an observable

Copy link

Many classes in the editor are already observables. This includes the Editor class, the Command class, all UI elements that extend the View class and many more.

Since the ButtonView class is already an observable, we did not have to do anything other than create a new instance.

const button = new ButtonView( locale );
Copy code

Then, we called the .set() method to update a few button properties.

button.set( {
    label: t( 'Highlight' ),
    withText: true,
    tooltip: true,
    isToggleable: true
} );
Copy code

If you want to make a custom class an observable, see the Observables guide.

Reacting to user input

Copy link

Next, we registered a callback that will be called whenever the execute event (bound to the click event in the DOM) is fired:

button.on( 'execute', () => {
    editor.execute( 'highlight' );
    editor.editing.view.focus();
} );
Copy code

Clicking the button sets the focus on that button, making it impossible for the user to continue typing without clicking the editing view. The editor.editing.view.focus() line returns the focus to the editing view, allowing the user to continue typing without interruption.

To learn more about focus, see the Focus tracking document.

Binding properties

Copy link

Finally, because the button and the command are both observables, we can bind selected properties between them:

button.bind( 'isOn', 'isEnabled' ).to( command, 'value', 'isEnabled' );
Copy code

The above line will attach listeners that listen for changes of the value and isEnabled properties of the command, and update the isOn andisEnabled button properties accordingly.

This is what the code would look like if you used the event system directly, without using the bind(...).to(...) abstraction provided by the observables:

command.on( 'change:value', ( event, propName, newValue, oldValue ) => {
    button.isOn = newValue;
} );

command.on( 'change:isEnabled', ( event, propName, newValue, oldValue ) => {
    button.isEnabled = newValue;
} );
Copy code

What’s next

Copy link

If you want to learn more about events and observables, see the Observables and Event system documents.

Otherwise, go to the next chapter where you will learn more about handling keystrokes, which also uses the CKEditor’s event system.