ckeditor / ckeditor5

Powerful rich text editor framework with a modular architecture, modern integrations, and features like collaborative editing.
https://ckeditor.com/ckeditor-5
Other
9.55k stars 3.7k forks source link

After update model by modelWriter, widget (editing-view) not updated. #1845

Closed nikitalarionov closed 5 years ago

nikitalarionov commented 5 years ago

I asked question in gitter channel. But Szymon Cofalik tells that my problem becomes big for gitter and should be an github ckeditor issue.

I prepared source code in github gist: https://gist.github.com/nikitalarionov/e0dbbb580d181e6363b19b49ac1d46d4

🐞 Bug | Other

πŸ’» Version of CKEditor - Latest

πŸ“‹ Steps to reproduce

  1. Execute command 'editDailyNote'.
  2. Open inspector, check that model was updated.
  3. Check that editing-view layer in ckEditor instance not reacted on model changes.

βœ… Expected result

It's seems that editing-view must be automatic updated after command executes and change model.

❎ Actual result

I see old text in editing-view (there is old result in view like at time that called toWidget method in editingDownCast convector).

πŸ“ƒ Other details that might be useful

1) Upcast convector is work as expected. 2) EditingDownCast convector only called for first init time. I don't know if it needs react after on command begin executed, after model begin changed. 3) Downcast convector is work as expected, after running command, i can run getData() and see expected result - text has new value.

I think i not should update editing-view manually, it must be done by editor itself.

My use case:

I need implement plugin - footnote. User click to button ('addNote'). In editing-view will be added widget 'text' + icon. (By adding model in ckeditor document schema via command that not yet implemented). When user click to icon, there will be opened popup window in angular app - where user can change text and image for note. When user finished editing note object he press save button in popup. At this time i want listen this action on ckEditor plugin side. (I know how). When ckEditor receives this event, i will update text attribute, image attribute in model (Like i do it now). And as result i expect that ckEditor will handle updates in editing-view automatic.

It is simple user case. I avoiding to do many thing like ckEditor does. Trying to keep implementing some ui, data updates features on my app side.

nikitalarionov commented 5 years ago

I added a screenshot to show the problem visually.

There is state after i was clicked on note icon, that will executes command ('editDailyNote') to simulate user popup editing action.

Π‘Π½ΠΈΠΌΠΎΠΊ экрана 2019-06-28 Π² 15 46 59

nikitalarionov commented 5 years ago

Any ideas? Maybe i do something wrong?

scofalik commented 5 years ago

Hi, sorry for no reply, but we are just closing the current iteration and all team members are focused on things like testing, closing documentation and issues. We will try to look at it in a few days.

scofalik commented 5 years ago

Hello,

sorry for such delayed reply 😒.

AFAICS, you are missing attribute converter for editing downcast. You defined converters for inserting your widget but you haven't defined what should happen when the text attribute changes. And here https://gist.github.com/nikitalarionov/e0dbbb580d181e6363b19b49ac1d46d4#file-edit_command-js-L16 you change just the attribute. Initialization works because then the widget is inserted and the converter you specified is fired. But after that changes are not converted.

You need to specify an attribute converter that will do those changes. Unfortunately, this is not a typical thing to do, so you will have to use "custom converter" for that. Here is a template for that:

// Add a converter for editing downcast pipeline.
conversion.for( 'editingDowncast' ).add( dispatcher => {
    // Specify converter for attribute `text` on element `dailyNote`.
    dispatcher.on( 'attribute:text:dailyNote', ( evt, data, conversionApi ) => {
        // Skip adding and removing attribute, we are interesting only in changes in this case.
        if ( !data.attributeOldValue || !data.attributeNewValue ) {
            return;
        }

        // Here, use `data` and `conversionApi.mapper` and `conversionApi.writer`
        // to change the view. You will have to map the changed model element to
        // view element using `conversionApi.mapper` and replace the text
        // using `conversionApi.writer`.
    } );
} );

I hope this will help you with the issue 🀞. In the case of more questions, feel free to post here.

BTW.: it works for .getData() because .getData() performs full conversion each time it is called (so all the editor content is treated as it was just inserted).