Why has my unobtrusive ajax stopped updating my partial view in ASP.NET Core 3.1?

134 Views Asked by At

I'm using unobtrusive ajax inside a kendo window to update a form once it's been filled in. The form should update the Id's of the DOM elements dynamically and also show the relative data inside the form as returned from the controller.

Let's start, here is the window element that houses the partial view which is a form:

@model Requirement
@{
    int localId = Model.Id;
}
<div class="window-content">
    <form method="post" data-ajax-url="/Home/Process_Requirement" data-ajax="true" data-ajax-method="post" data-ajax-loading="#spinner" data-ajax-update="#update-form-requirement" data-ajax-success="form_requirement_success">
        <div id="update-form-requirement">
            <partial name="_Form_Requirement" />
        </div><!--/update-panel-->
        <div class="window-footer">
            <div class="container">
                <div class="row no-gutters">                    
                    <div class="col">
                        <button type="submit" class="input-submit float-right">Save</button>
                    </div>
                </div>
            </div>
        </div>
    </form>
</div>

_Form_Requirement

@model Requirement

@{
    int localId = Model.Id;
}
  
<div class="tab-content">
    <div class="tab-pane fade show active" id="form-requirement-basic-@localId" role="tabpanel" aria-labelledby="requirement-tab">
        <div asp-validation-summary="ModelOnly" class="text-danger"></div>    
        <input type="text" id="Id_@localId" name="Id" asp-for="Id" readonly />
        <input type="text" id="CreatedUser_@localId" asp-for="CreatedUser" readonly />

        <div class="container">
            <div class="row">
                <div class="col">
                    <div class="form-group">
                        <label>Vessel Type</label>
                        <kendo-dropdownlist name="VesselType"
                                            for="VesselType"
                                            id="VesselType_@localId"
                                            datatextfield="TypeName"
                                            datavaluefield="Id"
                                            min-length="3"
                                            style="width: 100%"
                                            value-primitive="true"
                                            option-label="Select vessel type"
                                            footer-template="<button class='dropdown-button k-icon k-i-plus-outline' data-object-title='Add vessel type' data-object-function='_Window_Vessel_Type' onclick='open_data_window(this, event)'></button>"
                                            filter="FilterType.Contains">
                            <datasource type="DataSourceTagHelperType.Ajax" page-size="80">
                                <transport>
                                    <read url="/Vessel/ReadVesselTypes" />
                                </transport>
                            </datasource>
                            <popup-animation>
                                <open duration="300" effects="fadeIn" />
                                <close duration="300" effects="fadeOut" />
                            </popup-animation>
                        </kendo-dropdownlist>                       
                    </div>
                </div>
            </div>
        </div>       
    </div>
</div>

When the form is submitted the controller action does the following:

/Home/Process_Requirement

public IActionResult Process_Requirement(Requirement model)
{
    //Define the partial view we want
    string modal = "_Form_Requirement";

    //If the Id is 0 then create a new requirement
    if (model.Id == 0)
    {
        if (ModelState.IsValid)
        {
            try {
                _requirementService.InsertRequirement(model);
                var getData = _requirementService.GetRequirement(model.Id);
                return PartialView(modal, getData);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }
    else
    {
        try
        {
            _requirementService.UpdateRequirement(model);
            return PartialView(modal, model);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }
    return PartialView(modal);
}

So, when you first open a window to create a new requirement the localId is 0 because you're not editing one, that's expected behavior.

When you then fill in all the details and submit the form, the data is posted to the database and saved correctly but the model doesn't seem to update with the new data, for example the input for the Id remains as 0:

<input type="text" id="Id_@localId" name="Id" asp-for="Id" readonly />

yet the id for the input updates to the newly created id number. Why is this happening and can I do anything about it?

2

There are 2 best solutions below

0
On

Is the Id primary key? If so, it is not recommend to change the primary key, you should add a new column to be the key.

the data is posted to the database and saved correctly but the model doesn't seem to update with the new data

This could be caused by the concurrency issues. I can't see your update code now, but you can

try to change your update code like this:

 public async Task<IActionResult> Process_Requirement(Requirement model)
    {
        string modal = "_Form_Requirement";
        if (model.Id == 0)
        {
            //....
        }
        else //to update
        {
            await  TryUpdateModelAsync<Requirement>(_context.Requirements.FirstOrDefault(x => x.RId ==model.RId),"",c => c.Id, c => c.CreatedUser);
            _context.SaveChanges();
            return PartialView(modal, model);     
        }
        return PartialView(modal);
    }

My Model:

public class Requirement
{
    [Key]
    public int RId { get; set; } //new column
    public int Id { get; set; }
    public string CreatedUser { get; set; }
}

And in partial, pass the key with a hidden field:

<input type="text" asp-for="RId" hidden/>
<input type="text" id="Id_@localId" name="Id" asp-for="Id"  />
<input type="text" id="CreatedUser_@localId" asp-for="CreatedUser" />

Result:

enter image description here

0
On

you have a bug. fix the last return

 return PartialView(modal,model);