dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.36k stars 9.99k forks source link

Blazor: bind-value-oninput or bind does not work with contenteditable divs #9974

Open PirasannaRavi opened 5 years ago

PirasannaRavi commented 5 years ago

bind-value-oninput or bind does not work with contenteditable divs

Bug Description

In the below code, the expectation is as and when I edit the div content I need to update the model so that I can then save it back to Database.

To Reproduce

Steps to reproduce the behavior:

  1. Using the latest preview version of ASP.NET Core 3
  2. Run the below code <div contenteditable="true" bind-value-oninput="@contentEditableText"> You can Edit this Text </div> @contentEditableText @functions { string contentEditableText = "You can Edit this Text"; }
  3. As I Type something in the editable div, I need to see the same reflected in the body, but it does not happen that way. The OnChange event does not fire automatically.

Expected behavior

OnChange Event needs to fire and changes in editable div should be bound to the model.

Screenshots

Screen Shot 2019-05-04 at 2 01 06 PM Screen Shot 2019-05-04 at 2 02 50 PM
SteveSandersonMS commented 5 years ago

We don't currently support bind with contenteditable. It might be something we add in the future, but it's not directly planned.

In the meantime, you can use contenteditable in conjunction with JS interop to receive notification when edits occur and update your .NET models.

SteveSandersonMS commented 5 years ago

Reopening in case this is something we choose to address in the future.

Andrzej-W commented 5 years ago

@SteveSandersonMS please look at #10087. It looks that Blazor renders incorrect HTML when we try to use contenteditable with simple JS interop.

neroqfi commented 4 years ago

Hello,

if you're planning to implement contenteditable div binding, I addressed an issue few weeks ago related to this (FYI):

https://developercommunity.visualstudio.com/content/problem/1175416/blazor-webassembly-runtimeerror-memory-access-out.html

@SteveSandersonMS: Maybe the contenteditable div binding could resolve my issue also? There comes restrictions when I try to fetch innerHTML from the C# by using JS interop.

{Q}

kkentt commented 4 years ago

Reopening in case this is something we choose to address in the future.

That would be great if this feature is supported in future releases.

hshimshon commented 3 years ago

I agree definitely a must-have feature textarea is getting killed! contenteditable is so much more user-friendly

kefyru commented 3 years ago

add js script:

...
document.addEventListener("input", onInput);

function onInput(e) {
  let target = e.target;

  if (!target.value && !target.__contenteditable) target.__contenteditable = true;

  if (target.__contenteditable) target.value = target.innerText;
}
...
EislerDavid commented 3 years ago

kefyru

Your code breaks textareas and inputs. (Try to write somethiong in the textarea, then delete it all. After that is textarea broken.)

Here is my fix:

document.addEventListener("input", onInput);
function onInput(e) {
  let target = e.target;
  if (target.localName == "div") {
    if (!target.value && !target.__contenteditable) target.__contenteditable = true;
    if (target.__contenteditable) target.value = target.innerText;
  }
}
ghost commented 3 years ago

We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.

uabarahona commented 2 years ago

I hope this can get into .NET 7, as an additional info:

in essence we should be able to do the following:

<div contenteditable="true" @bind-innerHTML="PureHtml" @bind-innerHTML:event="input"></div>

and

<div contenteditable="true" @bind-textContent="PureHtml" @bind-textContent:event="input"></div>

📝 It could also be great if the event can be inferred too but is fine if its not.

TomoPeeka commented 2 years ago

Any news on this matter?

ersk commented 2 years ago

I use contenteditable all the time. Definitely a feature I would like.

BieleckiLtd commented 2 years ago

@EislerDavid

how does one use your js?

ShaunCurtis commented 2 years ago

The examples I see above are "Happy Path" examples. I started to look at question on SO about this: again a nice simple happy path example given.

I can see using contenteditable in an InputBase or similar controlled environment. But as an attribute?

Here's some examples going from happy path to very edge conditions. There's the RenderFragment problem - code between a <div> and </div> in a Razor file is built as a RenderFragment not text. And how would you start trying to decipher the content in the Edge example????

@page "/"

<PageTitle>Index</PageTitle>

<h3 class="text-secondary border-bottom border-secondary">Happy Path</h3>
<div contenteditable="true" class="m-3 p-3 bg-light border border-primary">
    Welcome to your new app.
</div>

<h3 class="text-secondary border-bottom border-secondary">More Edge</h3>
<div contenteditable="true" class="m-3 p-3 bg-light border border-primary">
    <h1>Hello, world!</h1>

    Welcome to your new app.
</div>

<h3 class="text-secondary border-bottom border-secondary">Very Edge!</h3>
<div contenteditable="true" class="m-3 p-3 bg-light border border-primary">
    <EditForm Model=this.model>
        Value: <InputText @bind-Value=model.Value />
        <button type="submit">Submit</button>
    </EditForm>
</div>

@code {
    private DataModel model = new DataModel();

    public class DataModel
    {
        public string Value { get; set; } = string.Empty;
    }
}
drocha87 commented 2 years ago

I would like to share a demo repository that I have where I used a contenteditable to implement a mention text area. This is not the very edge use case as suggested by @ShaunCurtis but I think it's a little bit more complex than the "happy path".

You'll realized that I used a lot of JS to handle the editor, this is because my project was a Blazor Server Side so I need to manage the editor on client side for obvious reasons. I'm not sure if I'm doing things the right way, but it ended up working properly.

Blazor Server Mentions Repository

You may be interested in the component and in the JS Interop.

ghost commented 2 years ago

Thanks for contacting us.

We're moving this issue to the .NET 8 Planning milestone for future evaluation / consideration. We would like to keep this around to collect more feedback, which can help us with prioritizing this work. We will re-evaluate this issue, during our next planning meeting(s). If we later determine, that the issue has no community involvement, or it's very rare and low-impact issue, we will close it - so that the team can focus on more important and high impact issues. To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.

Andrzej-W commented 2 years ago

Based on the number of thumbs up I think a lot of people (including me) are interested in this feature. What should we do to prioritize this work?

ghost commented 1 year ago

We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.

ghost commented 10 months ago

Thanks for contacting us.

We're moving this issue to the .NET 9 Planning milestone for future evaluation / consideration. We would like to keep this around to collect more feedback, which can help us with prioritizing this work. We will re-evaluate this issue, during our next planning meeting(s). If we later determine, that the issue has no community involvement, or it's very rare and low-impact issue, we will close it - so that the team can focus on more important and high impact issues. To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.

vukasinpetrovic commented 6 months ago

I just came across this issue while searching for a solution. I was hoping so much that it would be included in .net 8 release, while I was reading the comments here. I tried the proposed solution with JS function, but for some reason I did not manage to make it work and trigger second way of two way binding. I'm trying to find solution without using some component library to have "inline edit" feature for some label/text element.

For example here, if I change the input field value, it reflects and changes the displayed section name in both input field and editable div. But if I try to change value in div (via contenteditable), it does not trigger the value change and thus it does not change SectionName variable value. I set the breakpoint in that JS, that code is reached, but no changes are made to the model variable. Am I doing something wrong?

<div contenteditable="true" placeholder="Section Name" @bind-value-oninput="@SectionName"></div>
<InputText @bind-Value="SectionName" placeholder="Section Name"/>
<script>
        document.addEventListener("input", onInput);
        function onInput(e) {
            let target = e.target;
            if (target.localName == "div") {
                if (!target.value && !target.__contenteditable) target.__contenteditable = true;
                if (target.__contenteditable) target.value = target.innerText;
            }
        }
    </script>
vukasinpetrovic commented 6 months ago

I tried now with this combination, where it reflects the changes from div into input, but it does not work the other way around

<div contenteditable="true" placeholder="Section Name" @bind-value="SectionName" @bind-value:event="oninput"></div>
<InputText @bind-Value="SectionName" placeholder="Section Name"/>
vukasinpetrovic commented 6 months ago

Ok, another update, in order to display the value inside the div, I added <div>@SectionName</div> so the variable is it's inner content. Now two way binding and all the changes are reflected on both the div and the input. BUT, when I change text value inside div, after every input (key press) it resets the cursor to the beginning of the content. This is probably because Blazor is re-rendering variable which is set as content of the div. I'm not sure how to solve this. Any help is appreciated.

P.S. I'm basically trying to implement in-place editor this way. Yes there are components for it, but with contenteditable is the most user friendly for my need, as it prevents the width and height before, while and after editing.