Example of Multiple Quill JS Editors

updated on 19-Nov-2019: Added comments on form_show()

I had a similar problem to this where I wanted multiple Rich-Text Editors and needed to access each JS instance of the editor.

I learned about about Quill JS here

My implementation is slightly different than the Code Mirror example in the following way

No Global Array to manage JS object references to editor

Outline of implementation.

I create a custom HTML Form, which houses the Javascript, HTML, and core Quill JS interactions.

Initialization does two passes. First pass renames a div component which will wrap the JS editor. That is, the base Custom HTML will have something like this <div id="some_id">

First pass initialization will change the id for the div tag to be unique based on a random identifier.

The second stage initialization, will use this new div tag id in the Javascript Quill client initialization.

This custom / unique id, is created on the Anvil Python side, so each instance, knows its own identifier.

Then to interact with each editor, I use JQuery, to find the right element, extract the DOM node, and pass that to a static find function in the Quill JS library, that will return a reference to the instance based on a DOM node.

Using these custom identifiers and changing the div tag id 's on instantiation allows to query for the correct instance without maintaining the global array.

Standard Disclaimers… this is just a demo app. I am not a javascript / jquery expert. I arrived at this example through trial & error, fumbling in the dark.

Anyway, here is a an app that creates 4 Quill Rich Editor widgets on the same screen, with ability to interact with each editor.

https://anvil.works/build#clone:IAOL3A7B6ABMVGGA=6H45HQO3DQ6QCPPCYMUEKGEU

Potential issue with more complex Embedding

In my “real app”, I am building a form with 4 levels of nesting … Column Panel contains a Grid panel, contains my RTF Email Form which contains the CustomHTML Form (Quill JS for Text Area.) I had to do some troubleshooting, which I thought I’d share.

When using more complex patterns, I have found the form_show() method on my Custom HTML form, is not getting fired. It’s not an issue in the example code above, but might be an issue on more complicated embeddings (“in the wild” as it were).

My solution (not in example here, but in my real code), is explicitly calling form_show() from my “Wrapper” Form. In this example code, it would be whatever you use to replace the RTFWrapper Form.

Be on the lookout! The error you will see is something like this

ExternalError: TypeError: Cannot read property '__quill' of undefined
at QuillEditorWidget, line 27

Which is a symptom that the <div id="xxx"> did not get set with the instance id. So HTML DOM node still has generic id, but Anvil / Javascript code is using a specific id. Hence the quill reference cannot be found.

The resolution is to make sure that the form_show() method on the CustomHTML (widget) form is called. First place to check is to ensure whatever is wrapping the CustomHTML Form actually cascades the form_show() event, so that the two Javascript Initialization functions will get called.

Comments on Unique Identifiers

I borrowed the random string from Code Mirror example, but enhanced it by prepending a time element.

This tactic is inspired by python SimpleFlake implementation, which has an issue in that Sculpt / Anvil does not allow all Python Random module functions. The result is the pure SimpleFlake implementation only works in Server modules.

Presentation on SimpleFlake if you are interested.

Anyway, I used a similar tact, grab the time in seconds, and combine with random portion (6 random characters from an alphabet of 36 letters)
It might be a bit overkill, but I might re-use this when I need a more robust distributed UUID since the collision likelihood is small enough for my needs. (i.e match a random selection of 6 / 36 for a given second … i.e there are over two billion ways to draw 6 characters out of an alphabet of 36, accounting for fact that each draw is ordered, (A, B, C does not collide with C, B, A) and repeats are OK, AAA is a valid unique identifier.

So the Anvil Forms compliant conflation of SimpleFlake with @DavidWylie 's implementation.

2 Likes

Nice!

i wish i would have been this clever when I was trying to have multiple rich text editors on a page

I haven’t tried the whole thing yet (I’m on a cell right now), but I would like to comment on the unique identifier, which seems a little too complex.
Wouldn’t be enough (and simpler) a module that returns an incremental value?
A client side module can keep track of global variables and make sure you don’t get the same value twice in the same session by just incrementing a counter. There is no need to make sure that the identifier is unique in the galaxy, it’s enough to manage one session.

I just created a front-end application where I use the same toolbar but with multiple editable areas. If someone is interested in my solution, please look it up here: https://github.com/maxfahl/Quill-Edit-Multiple#readme

1 Like