Automatically refresh a component in Blazor

11,179

There is a problem with the way you have bound the onclick event of the button on the modal form.

you have onclick="AddNewSection()" - writing it this way will likely be interpreted as a pure javascript call and if you inspect the DOM in your browser tools, you will likely see onclick="AddNewSection()" on the button.

You should have onclick="@AddNewSection" - this way, Blazor will hook up the onclick event to your C# method.

Share:
11,179

Related videos on Youtube

Dwayne Barsotta
Author by

Dwayne Barsotta

Updated on June 04, 2022

Comments

  • Dwayne Barsotta
    Dwayne Barsotta almost 2 years

    I am working on a Blazor page for adding a new object. The object "RepairOrder" has List of object "RepairSection".

    On the page there is an area that will loop through the List "RepairOrder"."RepairSections" and show the elements:

       <div class="col-lg-10">
            @if (sections.Count > 0)
            {
                foreach (var sec in sections)
                {
                    <h3>Section @sec.SectionNumber</h3>
    
                    <div class="row">
                        <div class="col-lg-1"></div>
                        <div class="col-lg-5">
                            <label for="Failure" class="control-label">Failure: </label>
                            <input for="Failure" class="form-control" bind="@sec.Failure" readonly />
                        </div>
                        <div class="col-lg-1"></div>
    
                        <div class="col-lg-1">
                            <label><input type="checkbox" checked="@IsCApprovedChecked(sec)" />   Warranty</label>
                        </div>
                        <div class="col-lg-2">
                            <label><input type="checkbox" value="@IsWarrantyChecked(sec)" />   Repair Approved</label>
                        </div>
                    </div>
    
                    <div class="row">
                        <div class="col-lg-1"></div>
                        <div class="col-lg-10">
                            <label for="AdminComments" class="control-label">Admin Comments: </label>
                            <input for="AdminComments" class="form-control" bind="@sec.AdminComments" readonly />
                        </div>
                    </div>
                    <div class="row">
                        <div class="col-lg-1"></div>
                        <div class="col-lg-10">
                            <label for="TechComments" class="control-label">Tech Comments: </label>
                            <input for="TechComments" class="form-control" bind="@sec.TechComments" readonly />
                        </div>
                    </div>
                }
            }
        </div>
    

    After all the current sections in the list have been added to the page, there is a button to add a new section. When the button is clicked, the function changes a bool value to true to open a modal as a dialog. The modal contains fields to input a new section elements.

    function called to open the modal:

    protected void AddSectionCalled()
    {
        _newSection = new RepairSection();
        this.isAddNew = true;
    }
    

    Modal Code:

    <div class="modal" tabindex="-1" style="display:block" role="dialog">
            <div class="modal-dialog modal-dialog-scrollable modal-xl">
                <div class="modal-content">
                    <div class="modal-header">
                        <h3 class="modal-title">New Repair Section</h3>
                        <button type="button" class="close" onclick="@CloseModal"><span aria-hidden="true">X</span></button>
                    </div>
                    <div class="modal-body">
                        <form>
                            <div class="row">
                                <div class="col-lg-1"></div>
                                <div class="col-lg-2">
                                    <label for="sectionLetter" class="control-label">Section: </label>
                                    <input for="sectionLetter" class="form-control" bind="@_newSection.SectionNumber" />
                                </div>
                                <div class="col-lg-1"></div>
    
                                <div class="col-lg-2">
                                    <label><input type="checkbox" bind="@_newSection.Warranty" />   Warranty</label>
                                </div>
                                <div class="col-lg-2">
                                    <label><input type="checkbox" bind="@_newSection.CustomerApproved" />   Repair Approved</label>
                                </div>
                            </div>
                            <div class="row">
                                <div class="col-lg-1"></div>
                                <div class="col-lg-10">
                                    <label for="_failure" class="control-label">Failure: </label>
                                    <input for="_failure" class="form-control" bind="@_newSection.Failure"/>
                                </div>
                            </div>
                            <div class="row">
                                <div class="col-lg-1"></div>
                                <div class="col-lg-10">
                                    <label for="_adminComments" class="control-label">Admin Comments: </label>
                                    <input for="_adminComments" class="form-control" bind="@_newSection.AdminComments" />
                                </div>
                            </div>
                            <div class="row">
                                <div class="col-lg-1"></div>
                                <div class="col-lg-10">
                                    <label for="_techComments" class="control-label">Tech Comments: </label>
                                    <input for="_techComments" class="form-control" bind="@_newSection.TechComments"/>
                                </div>
                            </div>
                            <br/>
                            <button class="btn btn-primary float-left" onclick="AddNewSection">Add New Section</button>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    

    When the "Add New Section" button is clicked, the "_newSection" object created from the information collected in the modal is added to the "sections" list that was originally looped through when the page was loaded.

       private void AddNewSection()
            {
                sections.Add(_newSection);
                this.StateHasChanged();            
                this.isAddNew = false;
    
            }
    

    as you can see I added the "StateHasChanged()" after the new section is added to the sections list. However the page does not render to display the new section.

    I originally had created dummy data on the page "OnInitAsync()" event that loaded the sections list with data before it was displayed. This way I could make sure the page displayed what was in the list correctly.

    How can I make the page re-render the information in the list after user adds a new object to the list?

    ----Edit-----

    Below is the code for the entire page. I will try and minimize this on the weekend, however there really is not a lot here.

     @page "/AddRepairOrder"
    @using ShopLiveWebVersion2._0.Models
    @using ShopLiveWebVersion2._0.DataAccess
    @using ShopLiveWebVersion2._0.Services
    @using ShopLiveWebVersion2._0.Data
    @inject IUriHelper UriHelper
    @inject RepairOrderContext context
    
    <div class="row">
        <div class="col-lg-1"></div>
        <div class="col-lg-10"><h1>Create New Repair Order</h1></div>
    </div>
    <br /><br />
    <form id="AddROForm">
        <div class="form-group">
    
            <div class="row">
                <div class="col-lg-1"></div>
                <div class="col-lg-2">
                    <label for="ControlNumber" class="control-label">Repair Order #: </label>
                    <input for="ControlNumber" class="form-control" bind="@ro.ControlNumber" maxlength="15" required />
                </div>
                <div class="col-lg-1">
                    <label for="TagNumber" class="control-label">Tag #: </label>
                    <input for="TagNumber" class="form-control" bind="@ro.TagNumber" maxlength="8" />
                </div>
                <div class="col-lg-3">
                    <label for="VIN" class="control-label">VIN: </label>
                    <input for="VIN" class="form-control" bind="@ro.VIN" maxlength="18" />
                    @*<small id="Chasis" class="form-text text-muted">@ro.GetChassisNumber()</small> figure out how to get chassis from vin after box looses focus*@
                </div>
                <div class="col-lg-2">
                    <label for="Make" class="control-label">Make: </label>
                    <input for="Make" class="form-control" bind="@ro.Make" maxlength="30" />
                </div>
                <div class="col-lg-2">
                    <label for="Madel" class="control-label">Model: </label>
                    <input for="Madel" class="form-control" bind="@ro.Madel" maxlength="30" />
                </div>
            </div>
    
            <div class="row AddRow">
                <div class="col-lg-1"></div>
                <div class="col-lg-4">
                    <label for="Customer" class="control-label">Customer: </label>
                    <input for="Custoemr" class="form-control" bind="@ro.Customer" maxlength="50" />
                </div>
                <div class="col-lg-2">
                    <label asp-for="Location" class="control-label">Vehicle Location: </label>
                    <select asp-for="Location" class="form-control" bind="@ro.Location">
                        <option value="">-- Select a Location --</option>
                        @foreach (var loc in Location)
                        {
                            <option value="@loc">@loc</option>
                        }
                    </select>
                </div>
                <div class="col-lg-2">
                    <label asp-for="Assigned" class="control-label">Assigned: </label>
                    <select asp-for="Assigned" class="form-control" bind="@ro.Assigned">
                        <option value="">-- Select an Employee --</option>
                        @foreach (var emp in Employee)
                        {
                            <option value="@emp">@emp</option>
                        }
                    </select>
                </div>
                <div class="col-lg-2">
                    <label asp-for="Status" class="control-label">Status: </label>
                    <select asp-for="Status" class="form-control" bind="@ro.Status">
                        <option value="">-- Select a Status --</option>
                        @foreach (var st in Status)
                        {
                            <option value="@st">@st</option>
                        }
                    </select>
                </div>
            </div>
            <br />
            <div class="row"><div class="col-lg-1"></div><div class="col-lg-10"><hr id="Double" /></div></div>
            <div class="row">
                <div class="col-lg-1"></div>
                <div class="col-lg-10">
                    @if (sections.Count > 0)
                    {
                        foreach (var sec in sections)
                        {
                            <h3>Section @sec.SectionNumber</h3>
    
                            <div class="row">
                                <div class="col-lg-1"></div>
                                <div class="col-lg-5">
                                    <label for="Failure" class="control-label">Failure: </label>
                                    <input for="Failure" class="form-control" bind="@sec.Failure" readonly />
                                </div>
                                <div class="col-lg-1"></div>
    
                                <div class="col-lg-1">
                                    <label><input type="checkbox" checked="@IsCApprovedChecked(sec)" />   Warranty</label>
                                </div>
                                <div class="col-lg-2">
                                    <label><input type="checkbox" value="@IsWarrantyChecked(sec)" />   Repair Approved</label>
                                </div>
                            </div>
    
                            <div class="row">
                                <div class="col-lg-1"></div>
                                <div class="col-lg-10">
                                    <label for="AdminComments" class="control-label">Admin Comments: </label>
                                    <input for="AdminComments" class="form-control" bind="@sec.AdminComments" readonly />
                                </div>
                            </div>
                            <div class="row">
                                <div class="col-lg-1"></div>
                                <div class="col-lg-10">
                                    <label for="TechComments" class="control-label">Tech Comments: </label>
                                    <input for="TechComments" class="form-control" bind="@sec.TechComments" readonly />
                                </div>
                            </div>
                        }
                    }
                </div>
            </div>
            <div class="row"></div>
        </div>    @*Form-group*@
    </form>
    <div class="row">
        <div class="col-lg-1"></div>
        <div class="col-lg-9">
            <br /><br />
            <button class="btn btn-primary float-right" onclick="@AddSectionCalled">Add New Section</button>
        </div>
    </div>
    
    @if (isAddNew == true)
    {
        <div class="modal" tabindex="-1" style="display:block" role="dialog">
            <div class="modal-dialog modal-dialog-scrollable modal-xl">
                <div class="modal-content">
                    <div class="modal-header">
                        <h3 class="modal-title">New Repair Section</h3>
                        <button type="button" class="close" onclick="@CloseModal"><span aria-hidden="true">X</span></button>
                    </div>
                    <div class="modal-body">
                        <form>
                            <div class="row">
                                <div class="col-lg-1"></div>
                                <div class="col-lg-2">
                                    <label for="sectionLetter" class="control-label">Section: </label>
                                    <input for="sectionLetter" class="form-control" bind="@_newSection.SectionNumber" />
                                </div>
                                <div class="col-lg-1"></div>
    
                                <div class="col-lg-2">
                                    <label><input type="checkbox" bind="@_newSection.Warranty" />   Warranty</label>
                                </div>
                                <div class="col-lg-2">
                                    <label><input type="checkbox" bind="@_newSection.CustomerApproved" />   Repair Approved</label>
                                </div>
                            </div>
                            <div class="row">
                                <div class="col-lg-1"></div>
                                <div class="col-lg-10">
                                    <label for="_failure" class="control-label">Failure: </label>
                                    <input for="_failure" class="form-control" bind="@_newSection.Failure" />
                                </div>
                            </div>
                            <div class="row">
                                <div class="col-lg-1"></div>
                                <div class="col-lg-10">
                                    <label for="_adminComments" class="control-label">Admin Comments: </label>
                                    <input for="_adminComments" class="form-control" bind="@_newSection.AdminComments" />
                                </div>
                            </div>
                            <div class="row">
                                <div class="col-lg-1"></div>
                                <div class="col-lg-10">
                                    <label for="_techComments" class="control-label">Tech Comments: </label>
                                    <input for="_techComments" class="form-control" bind="@_newSection.TechComments" />
                                </div>
                            </div>
                            <br />
                            <button class="btn btn-primary float-left" onclick="AddNewSection()">Add New Section</button>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    }
    
    @functions
    {
    
    
        private RepairOrder ro;
        private RepairOrder incomingRO;
        private RepairOrderDataAccess RoData;
        private string chassis;
        private List<string> Location;
        private List<string> Employee;
        private List<string> Status;
        private FileService fileService;
        private List<RepairSection> sections;
        private bool isAddNew;
    
        //for new repair section modal
        private RepairSection _newSection;
    
        protected override async Task OnInitAsync()
        {
            ro = new RepairOrder();
            Location = new List<string>();
            Employee = new List<string>();
            Status = new List<string>();
            sections = new List<RepairSection>();
            isAddNew = false;
            fileService = new FileService();
            RoData = new RepairOrderDataAccess(context);
            await LoadData();
    
        }
    
        private async Task LoadData()
        {
            Location = await Task.Run(() => fileService.ReadLocation());
            Employee = await Task.Run(() => fileService.ReadEmployees());
            Status = await Task.Run(() => fileService.ReadStatus());
    
        }
    
        public string IsCApprovedChecked(RepairSection sc)
        {
            if (sc.CustomerApproved == true)
            {
                return "checked";
            }
            else
            {
                return "";
            }
        }
    
        public string IsWarrantyChecked(RepairSection sc)
        {
            if (sc.Warranty == true)
            {
                return "checked";
            }
            else
            {
                return "";
            }
        }
    
        protected void AddSectionCalled()
        {
            _newSection = new RepairSection();
            this.isAddNew = true;
        }
    
        private void AddNewSection()
        {
            sections.Add(_newSection);
            this.StateHasChanged();            
            this.isAddNew = false;
    
        }
    
    
    
        private void CloseModal()
        {
            this.isAddNew = false;
        }
    
    • Henk Holterman
      Henk Holterman almost 5 years
      I think you should show the flow of data (_newSection) a little better. Also, what library or example did you use for the Modal comp?
    • dani herrera
      dani herrera almost 5 years
      Can you rewrite question as a minimal reproducible example? I mean, without modal and with minimal html and minimal RepairSection fields.
    • Mister Magoo
      Mister Magoo almost 5 years
      Which component contains the method AddNewSection?
    • Dwayne Barsotta
      Dwayne Barsotta almost 5 years
      @MisterMagoo the AddNewSection() method is in the page's functions section.
    • Mister Magoo
      Mister Magoo almost 5 years
      Change your onclick on the Add New Section button to onclick="@AddNewSection"
  • Mister Magoo
    Mister Magoo almost 5 years
    You should not be using form elements in Blazor without at least a null method to prevent submit behaviour - if you really need form elements (I don't think you do) then add a null method like onsubmit="@(()=>{})" or onsubmit="@DoNothing" where DoNothing() does nothing - this will prevent default form submit behaviour.
  • Dwayne Barsotta
    Dwayne Barsotta almost 5 years
    At first i left the "()" in the onclick="@AddNewSection" - once I removed it things worked better. Now when I hit the modal goes away and all the text (even the text in the fields for the RepairOrder disappears. I commented out the StateHasChanged() in the AddNewSection method. Now when I click "AddNewSection" the page shows the new section for a split second and then refresh's - clearign out all the data on the page. --Just read above after I saved! I think this is my issue!!
  • Mister Magoo
    Mister Magoo almost 5 years
    Please update your question with specific version numbers for .NETCore SDK , Visual Studio and the Blazor extension for VS - also include what PackageReferences you have in the csproj
  • Mister Magoo
    Mister Magoo almost 5 years
    Remove the form elements - see my comment above - they are likely causing a full page refresh
  • Dwayne Barsotta
    Dwayne Barsotta almost 5 years
    Removing the form tags form the page did the trick!!! Thank you very much. I am accepting this as the correct answer!
  • Henk Holterman
    Henk Holterman almost 5 years
    From preview 6 onward, it should now be @onclick="@AddNewSection"