0

In my Blazor app I have a list of items. Clicking one of the items will open a dialog component with the item as a parameter. Within the dialog is an EditForm:

<div class="modal-container">
    <div class="modal">
        <EditForm Model="@Item" OnValidSubmit="SaveForm">
            <p><input type="text" @bind="@Item.Title" /></p>
            <p><input type="button" @onclick="Cancel" value="Cancel" /><input type="submit" value="Save" /></p>
        </EditForm>
    </div>
</div>

@code {

    [Parameter]
    public EventCallback<Item> Callback { get; set; }

    [Parameter]
    public Item Item { get; set; } = new();
    public Item OriginalItem => Item; // <= First attempt

    protected override async Task OnInitializedAsync()
    {
        OriginalItem = Item; // <= Second attempt
    }

    async Task Cancel
    {
        Item = OriginalItem; // <= This doesn't work

        await Callback.InvokeAsync(null);
    }

    async Task SaveForm
    {
        // ...
    }
}

When I change the Item.Title value and click the Cancel-button and the dialog closes, the Item model is still updated and I see the change in the list of items. That's how Blazor works, but not what I want in this case.

I try to "reset" the Item model by keeping a copy of the original Item model parameter and overwrite it in the Cancel-function, but that doesn't seem to work.

What is the right approach?

As far as I can see the opposite happens; clicking the Cancel-button sets OriginalItem = Item. I really don't get why.

Mads
  • 385
  • 1
  • 5
  • 18
  • 1
    You're not keeping a copy of the original object, you're keeping a copy of the reference of the original object, meaning, `Item` and `OriginalItem` both point to the *same* object in memory. Modifying one means modifying the other ([demo](https://dotnetfiddle.net/26XXKy)). You'll probably want to *clone* (deep clone) the object if you want this to work with your current code. To do this, either manually implement a `DeepClone` method or use something proposed [here](https://stackoverflow.com/q/78536/9363973) – MindSwipe May 20 '22 at 10:16
  • To add to @MindSwipe comment, one approach is pull all your data from datastores as `records` - immutable objects. You then create an editable class - which can populate itself from the record, and your editor uses that as the `EditContext`. When you save/update you create a new `record` and submit that to your data store to save/update. Or replace the existing object if it's not persisted. You can use the notification pattern to trigger updates on any components that need updating. – MrC aka Shaun Curtis May 20 '22 at 11:16
  • Thanks to both of you. I think I'll go with the serialize/deserialize method, that I can see most others use. – Mads May 20 '22 at 11:34

2 Answers2

0

This question is answered here Modal with Parameters still apply changes after beeing canceled

Surinder Singh
  • 1,165
  • 1
  • 3
  • 11
0

I assume your dialog is inside a Component which is passed a Parameter of type Item? Anyway, I had the same issue as you and solved it quite easily.

Give your dialog component local properties.

Public string Title {get;set;}

In OnInitializedAsync, set your local properies to the value of your Item properties

this.Title = Item.Title

Bind the Input field of the dialog to its local properties instead of Item properties.

<Input @bind=Title>

When you hit cancel just do nothing. Only close the dialog.

When you hit Save, set the Item properties to the value of local properties

Item.Title = Title

The should do the trick

Gilles Radrizzi
  • 999
  • 3
  • 10
  • 20
  • Thanks. That would surely work, but the model has 20 og 30 properties already that I don’t want to specify one by one and also the solution is not easy to maintain. – Mads May 21 '22 at 06:57