wobsoriano / lexical-vue

An extensible Vue 3 web text-editor based on Lexical.
https://lexical-vue.vercel.app/
MIT License
251 stars 30 forks source link

Two-way binding of content not working #13

Closed toniengelhardt closed 7 months ago

toniengelhardt commented 1 year ago

In the example it says that content has two way binding, which doesn't seem to be correct. Changing content programmatically doesn't update the editor content. Also giving the ref an initial value doesn't seem to work. Is this a bug or rather misleading docs?

In case of the later, is there any way to populate the editor with initial data from outside?

Thanks 🙏🏽

chervyachok commented 1 year ago

@toniengelhardt Use editorState property to set initial editor content image

image

toniengelhardt commented 1 year ago

Thanks 🙏🏽

abdulmlik commented 8 months ago

The solution to this issue is custom plugins for Two-way binding like this

<LexicalComposer :initial-config="config" @error="onError">
    <EditorBindingPlugin v-model="content" />
    ...
</LexicalComposer>
//EditorBindingPlugin.vue 
<script setup lang="ts">
import type { EditorState } from "lexical";
import {
  TRANSFORMERS,
  $convertToMarkdownString,
  $convertFromMarkdownString,
} from "@lexical/markdown";
import { useEditor, LexicalOnChangePlugin } from "lexical-vue";
import { computed, ref, watch } from "vue";

const emit = defineEmits<{
  (e: "update:modelValue", value: string): void;
}>();
const props = defineProps({
  modelValue: {
    type: String,
    default: "",
  },
});

const editorUpdate = ref(true);
const editornum = ref(0);
const content = computed<string>({
  set(v) {
    editornum.value++;
    // onChange is fired when create LexicalOnChangePlugin with an empty value
    if (editornum.value > 1) {
      editorUpdate.value = false;
      emit("update:modelValue", v);
    }
  },
  get() {
    return props.modelValue;
  },
});

const editor = useEditor();

watch(content, () => {
  if (editor && editorUpdate.value && content.value.length >= 0) {
    editor.update(() => {
      $convertFromMarkdownString?.(content.value);
    });
  }
  editorUpdate.value = true;
});

function onChange(editorState: EditorState) {
  editorState.read(() => {
    content.value = $convertToMarkdownString(TRANSFORMERS);
  });
}

defineExpose({
  editor,
});
</script>

<template>
  <LexicalOnChangePlugin @change="onChange" />
</template>
ynechaev commented 8 months ago

@abdulmlik this is a great snippet! I was able to use it as a component in my Nuxt 3 app with only one minor change: I removed editornum count variable with the related logic, since it's common to have an initial value in reactive connections.

wobsoriano commented 7 months ago

Thank you @abdulmlik. Closing this for now.