C# random behaviour in a CRUD edit page.

sblb 1,166 Reputation points
2022-10-14T14:09:47.947+00:00

Hi,
My application has a strange behaviour for a function I put with the help of @AgaveJoe . Definition link to generate a variable ECO [WebApiSqlite][1]

Normally the ECO variable is generated when I validate the checkboxValue1 and then I validate the Edit page.

Now the ECO variable is generated without validating the checkboxValue1 variable. The variable ECO is generated when I validate the Edit page without the checkboxValue1 variable being validated.

Edit.razor

<FormEdit ButtonText="Update" dev="dev"  
  OnValidSubmit="@EditDeveloper" />  
@code {  

    [Parameter] public int developerId { get; set; }  
    Developer dev = new Developer();   

    protected async override Task OnParametersSetAsync()  
    {  
        dev = await http.GetFromJsonAsync<Developer>($"api/developer/{developerId}");  

    }  

    async Task EditDeveloper()  
    {  
       await http.PutAsJsonAsync("api/developer", dev);        
       await http.GetAsync($"api/developer/SelectEcoById/{developerId}");   
       await js.InvokeVoidAsync("alert", $"Updated Successfully!");  
       uriHelper.NavigateTo("developer");          
    }          

}  

as you can see on picture below ECOSelected is false.
![250593-image.png][3]

the uriHelper.NavigateTo("developer");

The fetchData .razor is active to update and fetch the data and ECOSelected become true.
250518-image.png

How to avoid what the variable ECOSelected stay false when checkboxValue is false? and
when if checkboxValue1 = true then ECOSelected = true?

ECOSelected ECO variable is defined in model class

public bool ECOSelected { get; set; }  
        [NotMapped]  
        public string ECO   
        {  
            get  
            {  
                if (ECOSelected)  
                {  
                    return $"{ECOCount.ToString().PadLeft(3, '0')}/{ECOYear}";  
                }  

                return string.Empty;  
            }  
            set { }  
        }  

The controller

  [HttpGet("SelectEcoById/{id}")]  
         public async Task<ActionResult<Developer>> SelectEcoById(int id)  
        {  
            var developer = await _context.Developers.FindAsync(id);  
            if (developer == null)  
            {  
                return NotFound();  
            }  
            if (!developer.ECOSelected)  
            {  
               var values = await GenerateEcoByIdAsync(id);  

                    developer.ECOYear = values.Year;  
                    developer.ECOCount = values.Count;  
                    developer.ECOSelected = true;  


                await _context.SaveChangesAsync();  
            }  

            return developer;  
        }  

[1]: https://github.com/mjgebhard/WebApiSqlite+ [3]: /api/attachments/250593-image.png?platform=QnA

Blazor
Blazor
A free and open-source web framework that enables developers to create web apps using C# and HTML being developed by Microsoft.
1,398 questions
0 comments No comments
{count} votes

11 answers

Sort by: Most helpful
  1. AgaveJoe 26,141 Reputation points
    2022-10-17T18:56:30.91+00:00

    Your code specifically sets ECOSelected to true the first time the record is saved. I think ECOSelected is true the second time because you set it to true.

    I'm wondering if this is another one of your Rube Goldberg designs where the community cannot help you fix the code because the fundamental the design does not work.

    I see you are also implementing the empty setter again which is either a code smell or a very mean joke on the folks reviewing your code.

    Anyway, the best I can do for you is provide a working example of how a checkbox works.

    Model

        public class CheckBoxModel  
        {  
            public bool IsChecked { get; set; }  
        }  
    

    Code

    @page "/"  
    @using BlazorWasm.Models  
    @using BlazorWasm.Options  
    @using Microsoft.Extensions.Logging  
    @inject ILogger<Index> Logger  
      
    <PageTitle>Index</PageTitle>  
      
    <div>  
        <EditForm Model="@model" OnValidSubmit="@HandleValidSubmit">  
            <div>  
                Check: <input type="checkbox" @bind-value="model.IsChecked" />  
            </div>  
      
            <div>  
                <button type="submit">Submit</button>  
            </div>  
        </EditForm>  
    </div>  
      
      
    @code   
    {  
        private CheckBoxModel model = new();  
      
        private void HandleValidSubmit()  
        {  
            Logger.LogInformation(model.IsChecked.ToString());  
            if (model.IsChecked) {  
                Logger.LogInformation("I'm checked");  
            }  
              
        }  
    }  
    

    Lastly, ASP.NET Core Blazor forms and input components are covered in the official documentation. The code example above comes from the docs...


  2. AgaveJoe 26,141 Reputation points
    2022-10-17T20:38:39.527+00:00

    This is another example where you copy and paste code without making an attempt to understand how the code works. ECO is a system generated value and updated after the developer record is inserted. That's all that SelectEcoById does based on your original model. If you require other functionality like editing a system generated value - which I argued is a bad idea - then it is up to you to write this code.


  3. sblb 1,166 Reputation points
    2022-10-18T13:00:59.84+00:00

    Really I don't understand.

    I've put in Edit.razor the condition

      async Task EditDeveloper()  
        {  
            await http.PutAsJsonAsync("api/developer", dev);  
            Console.WriteLine($"Checkbox changed {dev.ECOSelected}");  
            if(dev.ECOSelected)  
            {  
           await http.GetAsync($"api/developer/SelectEcoById/{developerId}");         
            }  
      
           await js.InvokeVoidAsync("alert", $"Updated Successfully!");  
           uriHelper.NavigateTo("developer");          
        }    
    

    The condition dev.ECOSelected is true and the api method doesn't call. Why?
    If I don't put condition the api is called.

    In other EditForm I've put <InputCheckbox @bind-Value=@dev.ECOSelected />


  4. sblb 1,166 Reputation points
    2022-10-19T10:23:42.1+00:00

    I added GenearteEcoById in Edit.razor.

       async Task EditDeveloper()  
        {  
            await http.PutAsJsonAsync("api/developer", dev);  
            await http.GetAsync($"api/developer/GenearteEcoById/{developerId}");     
            //await http.GetAsync($"api/developer/SelectEcoById/{developerId}");    
            await js.InvokeVoidAsync("alert", $"Updated Successfully!");  
            uriHelper.NavigateTo("developer");          
        }    
    

    When I open the edit page and w/o selected ECOSelected I obtained the result :
    251936-image.png

    After that if the user wants to take an ECO (not mapped according to your recommendation) number just validate the checkbox so ECOSelected becomes True.

    You're right, I'm still on ECOSelected, but a simple change changes everything. We learn by doing.
    I thank you for your valuable help.


  5. sblb 1,166 Reputation points
    2022-10-19T13:55:23.74+00:00

    I have just checked and I think there is still a small problem.

    THE problem is that if there are several users updating their Edit page each time it will take an ECOYear and ECOCount.

    Let's imagine that there are 100 update lines without the ECOSelected being taken that means that the ECO number will be 100/22 when it should be 001/22.

    I dare not ask you how to solve this new problem. at least you can give me a lead.

    I think that I have to adapt GenerateEcoByIdAsync

     private async Task<YearCount> GenerateEcoByIdAsync(int id)  
            {  
                if (!await _context.Developers.AnyAsync(d => d.ECOYear == DateTime.Now.Year))  
                {  
                    return new YearCount() { Count = 1, Year = DateTime.Now.Year };  
                }  
      
                int max = await _context.Developers.Where(d => d.ECOYear == DateTime.Now.Year).MaxAsync(d => d.ECOCount) + 1;  
                return new YearCount() { Count = max, Year = DateTime.Now.Year };  
            }  
    
    0 comments No comments