I need help in two things related to Phoenix LiveView.
I’m doing a LiveView page to create Questions to Tests (like math tests, for example).
A question has one wording and one or more alternatives.
I’m using “Quill JS” javascript library to edit data of the question. So, i’ve a screen like this:
First is the question’s wording, second is an alternative answer.
All editors works by events. For example, user change some text of the wording, then frontend emits an event to LiveView module with changes, and then record is updated in database. Or, when LiveView load data of the question’s wording, it emits an event to the frontend, and the browser initializes Quill Js component. Things like this.
Here are some snippets of the code:
@impl true
def mount(_params, _session, socket) do
# async loading question record
send(self(), :load_question)
socket =
assign(socket, :question_is_loading, true)
|> assign(:alternatives_are_loading, true)
|> assign(:alternatives_count, 0)
|> assign(:alternatives, [])
{:ok, socket, temporary_assigns: [alternatives: []]}
end
@impl true
def handle_event("editorjs_is_ready", _params, socket) do
question = socket.assigns.current_question
socket = push_event(socket, "setup_data_editorjs", Jason.decode!(question.statement))
{:noreply, socket}
end
@impl true
def handle_event("editor_save", params, socket) do
question = socket.assigns.current_question
json_encoded = Jason.encode!(params)
{:ok, question} =
Questions.update_question(question, %{
statement: json_encoded
})
socket = assign(socket, :current_question, question)
{:noreply, socket}
end
@impl true
def handle_info(:load_question, socket) do
# if it's not created, create a new question
# in `draft` mode.
# This question will be persisted and opened until
# the question is created.
# If a question in `draft` status created by the user
# already exists, only load the question and show.
%User{id: user_id} = socket.assigns.current_user
socket =
case Questions.get_draft_question_of_user(user_id) do
nil -> create_question(socket, user_id)
question -> assign(socket, :current_question, question)
end
socket = assign(socket, :question_is_loading, false)
question = socket.assigns.current_question
socket = push_event(socket, "question_statement_ready", Jason.decode!(question.statement))
# load alternatives
send(self(), :load_alternatives)
{:noreply, socket}
end
Javascript:
fromEvent(editor, "text-change")
.pipe(skip(1), debounceTime(1500))
.subscribe((a) => {
/**
* Operation to remove unecessary
* break line
*/
let delta = editor.getContents();
let lastOpIndex = delta.ops.length - 1;
let lastOpInstace = delta.ops[lastOpIndex];
lastOpInstace.insert = lastOpInstace.insert?.replace(/\n$/, "");
hook.pushEventTo(selector, "editor_save", delta);
});
- The first question is whether this is the best way to implement this logic ??
Ok, it’s working. But i’m having a problem. I’m using, in the tags that will be used by Quill JS phx-update="ignore"
, to not participate of change detection, and not reload component all the time.
But, when the server crashes and restart, the page is reloading. It’s a big problem in UX, because if the user is editing when is being restarted, (1) he lost some of the text that he was writing, and the cursor of the mouse leaves the component. Here is an example:
https://media.giphy.com/media/K8Trv2mce6oMbMkP9j/giphy.gif
How to avoid this problem?