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.