Stale data with Quill editor


#1

I am integrating the Quill editor with Rails and would like to control it with Stimulus. Essentially I have a field on a Rails form, which has html stored in it, and it becomes and Quill rich text editor. There are also 2 other field consuming data from Quill: plain text (stripped of tags) and deltas (changes log).

All three are then saved to the db via the usual form submit.

It is almost working.

The form and controller code

<div data-controller='quill'>
      <%= f.input :target_note,
            input_html: {
              data: {
                target: 'quill.editor',
                action: "keyup->quill#update" } } %>
      <input data-target='quill.delta'/>
      <input data-target='quill.text' />
    </div>

The Stimulus controller

import { Controller } from "stimulus";

export default class extends Controller {
  static targets = ['editor','delta','text'];

  connect() {
    console.log('connected');
    this.quill = new Quill('#grammar_note_target_note', {
      theme: 'snow'
    });
  }

  update(){
    console.log(this.quill.getContents());
    console.log(this.quill.getText());
    this.textTarget.value = this.quill.getText();
    this.deltaTarget.value = this.quill.getContents();
  }
}

Problem

When the user types into the editor field, the data that was previously saved is copied as delta / plain text to the textTarget and deltaTarget fields. In the image below, the value of ‘asdasdasdsa’ was previously saved into the field, while the user just typed ‘hhh’.

Expected behaviour

On every keystroke, the actual text would be transformed into deltas or text and stored in the 2 fields.

Any help would really be appreciated. :grin:


#2

I had a similar issue and as a solution I ended up defining my event bindings in the connect function of my stimulus controller.

something like this should work in your case:

import { Controller } from "stimulus";
import Quill from "Quill";
import _ from "lodash";

export default class extends Controller {
  static targets = ["input"];
  
  connect() {
    this.quill = new Quill(this.inputTarget, {
      modules: {
        toolbar: ["bold", "italic", "underline"],
        keyboard: {
          bindings: this.keyBindings()
        }
      },
      theme: "bubble"
    });
    this.quill.on("text-change", e => {
      _.throttle(this.textChange.bind(this), 500);
    });
  }

  textChange() {
    console.log("textChange");
  }
}

#3

Hey @adrienpoly that is perfect, really exactly was I was looking for. I like the lodash throttle, a nice touch.