2

Please see this code for working with Quilljs:

window.InitialQuill = {
  createQuill: function (quillElement) {
    var options = {
      debug: 'info',
      modules: {
        toolbar: '#toolbar',
      },
      placeholder: 'write something...',
      readonly: false,
      theme: 'snow',
    };

    new Quill(quillElement, options);
  },
  getQuillContent: function (quillControl) {
    return JSON.stringify(quillControl.__quill.getContents());
  },
  getQuillText: function (quillControl) {
    return quillControl.__quill.getText();
  },
  getQuillHTML: function (quillControl) {
    return quillControl.__quill.root.innerHTML;
  },
  loadQuillContent: function (quillControl, quillContent) {
    // return quillControl.__quill.setContents(JSON.parse(quillContent), 'api');
    var ops = [
      { insert: 'Hello ' },
      { insert: 'World!', attributes: { bold: true } },
      { insert: '\n' },
    ];
    return quillControl.__quill.setContents(ops, 'api');
  },
};

I'm using the above code in blazor this way:

@inject IJSRuntime JsRuntime

@if(EditorEnabled)
{
<br>
<button class="btn btn-primary" @onclick="GetText">Get Text</button>
<button class="btn btn-primary" @onclick="GetHTML">Get HTML</button>
<button class="btn btn-primary" @onclick="GetEditorContent">Get Content</button>

<br />

<div>
    @EditorContent
</div>
<div>
    @((MarkupString)@EditorHTMLContent)
</div>

<br />
<button class="btn btn-danger" @onclick="SaveContent">Save Content</button>
<button class="btn btn-success" @onclick="LoadContent">Load Content</button>

<br />
<br />
<br />

<div id="toolbar">
    <span class="ql-formats">
        <select class="ql-font">
            <option selected=""></option>
            <option value="serif"></option>
            <option value="tahoma"></option>
        </select>
        <select class="ql-size">
            <option value="small"></option>
            <option selected=""></option>
            <option value="large"></option>
            <option value="huge"></option>
        </select>
    </span>
    <span class="ql-formats">
        <button class="ql-bold"></button>
        <button class="ql-italic"></button>
        <button class="ql-undeline"></button>
        <button class="ql-strike"></button>
    </span>
    <span class="ql-formats">
        <select class="ql-color"></select>
        <select class="ql-background"></select>
    </span>
    <span class="ql-formats">
        <button class="ql-list" value="ordered"></button>
        <button class="ql-list" value="bullet"></button>
        <button class="ql-indent" value="-1"></button>
        <button class="ql-indent" value="+1"></button>
        <select class="ql-align">
            <option selected=""></option>
            <option value="center"></option>
            <option value="right"></option>
            <option value="justify"></option>
        </select>
    </span>
    <span class="ql-formats">
        <button class="ql-link"></button>
    </span>
</div>
}

<div @ref="@DivEditorElement"></div>

@code {
    private string strSavedContent = "";
    private ElementReference DivEditorElement;
    private string EditorContent;
    private string EditorHTMLContent;
    private bool EditorEnabled = true;

protected override async Task OnAfterRenderAsync(bool firstRender)
{
    if(firstRender == true)
    {
        await JsRuntime.InvokeAsync<string>("InitialQuill.createQuill", DivEditorElement);
    }
}

private async Task GetText()
{
    EditorHTMLContent = "";
    EditorContent = await JsRuntime.InvokeAsync<string>("InitialQuill.getQuillText", DivEditorElement);
}

private async Task GetHTML()
{
    EditorContent = "";
    EditorHTMLContent = await JsRuntime.InvokeAsync<string>("InitialQuill.getQuillHTML", DivEditorElement);
}

private async Task GetEditorContent()
{
    EditorHTMLContent = "";
    EditorContent = await JsRuntime.InvokeAsync<string>("InitialQuill.getQuillContent", DivEditorElement);
}

private async Task SaveContent()
{
    strSavedContent = await JsRuntime.InvokeAsync<string>("InitialQuill.getQuillContent", DivEditorElement);
}

    private async Task LoadContent()
{
    var QuillDelta = await JsRuntime.InvokeAsync<string>("InitialQuill.loadQuillContent", DivEditorElement, strSavedContent);
}
}

All buttons work fine except Load Content. It works and specific text shows in the editor but after then it cause a problem.

Unhandled exception rendering component: An exception occurred executing JS interop: The JSON value could not be converted to System.String. Path: $ | LineNumber: 0 | BytePositionInLine: 1.. See InnerException for more details. Microsoft.JSInterop.JSException: An exception occurred executing JS interop: The JSON value could not be converted to System.String. Path: $ | LineNumber: 0 | BytePositionInLine: 1.. See InnerException for more details.

I wrote the code this way:

quillControl.__quill.setContents(JSON.parse(quillContent), 'api');

but I got the same error. Where is my problem?

Remi Guan
  • 21,506
  • 17
  • 64
  • 87
Arian
  • 12,793
  • 66
  • 176
  • 300
  • Could you output the value of the JSON to see why this conversion would throw an error? Could your '\n' be the cause of this? Maybe escape double? – Alb Jan 11 '22 at 09:52
  • Hey, do you feel okay with my edit to your code format in your question? You can revert my edit if it's not good in your opinion. – Remi Guan Jan 11 '22 at 09:55
  • so you use JSON.parse to make object out of string and your error is object cannot be converted to string, maybe just ommit JSON.parse ? – john Smith Jan 11 '22 at 09:57
  • @RemiCrystal Please see my first comment below the "Albert" answer. – Arian Jan 12 '22 at 04:42
  • @johnSmith Please see my first comment below the "Albert" answer. – Arian Jan 12 '22 at 04:43
  • When you get this type of problem, it is helpful to log the value on either side of the JSInterop call - so inside the JS: loadQuillContents you could `console.log` the results of `quillControl.__quill.setContents(ops, 'api')` and in C# LoadContent, change the call to `InvokeAsync` and `Console.WriteLine(QuillDelta)` - also put a breakpoint and inspect QuillDelta to see what is being returned. – Mister Magoo Jan 14 '22 at 09:35

2 Answers2

2

If you're converting a string to JSON, make sure that some characters are escaped, otherwise the conversion will not work as expected.

Alb
  • 1,063
  • 9
  • 33
  • As you see in my code: `strSavedContent = await JsRuntime.InvokeAsync("InitialQuill.getQuillContent", DivEditorElement);` I get content from `Quill` by it's function and then I want to show that value in editor. I bind whatever I get from `Quill` to `Quill` – Arian Jan 12 '22 at 04:41
  • @Arian it still does not mean that everything is escaped correctly. Putting output back as input again doesn't guarantee that it works. Can you update your code with the output? – Alb Jan 12 '22 at 08:09
  • Could you explain more, What type of change you consider? – Arian Jan 12 '22 at 09:04
  • As I wrote as a comment on your post before, I don't know what the output looks like. If you could update your code with the output (just `console.log(strSavedContent)`), I could tell where the error lies and how to handle that. Your title implies that the error is with quill but I think that it is more of a parsing error when you're trying to convert to a JSON object. – Alb Jan 12 '22 at 09:07
  • @Arian have you tried my suggestion? – Alb Jan 15 '22 at 14:25
  • Yes, didn't work – Arian Jan 16 '22 at 05:27
  • 1
    @Arian my suggestion was not a solution... It's for debugging what you're throwing into the Plugin... – Alb Jan 16 '22 at 12:47
0

You've set the expected return type as a string and are passing a full JSON object (the delta) which is why you're getting the error. So here are your options:

If you want to return an object you can change the type to object.

private async Task LoadContent()
{
    var QuillDelta = await JsRuntime.InvokeAsync<Object>("InitialQuill.loadQuillContent", DivEditorElement, strSavedContent);
}

If you want to return a string from the client-side you need to adjust the return value to also be stringified.

loadQuillContent: function (quillControl, quillContent) {
    // return quillControl.__quill.setContents(JSON.parse(quillContent), 'api');
    var ops = [
        { insert: 'Hello ' },
        { insert: 'World!', attributes: { bold: true } },
        { insert: '\n' },
    ];

    return JSON.stringify(quillControl.__quill.setContents(ops, 'api'));
}

If you want to return the object and stringify it server-side you can do the following.

private async Task LoadContent()
{
    var QuillDelta = await JsRuntime.InvokeAsync<Object>("InitialQuill.loadQuillContent", DivEditorElement, strSavedContent);
    //this is using the Json namespace '@using System.Text.Json'
    var stringFromObject= JsonSerializer.Serialize(QuillDelta);
}
Onboardmass
  • 84
  • 3
  • 11