Quantcast
Channel: Active questions tagged blazor - Stack Overflow
Viewing all articles
Browse latest Browse all 4839

Why is my code not refreshing properly when calling StateHasChanged?

$
0
0

I've got a page that stores key value pairs and allows you to add new key value pairs to the existing list. You can't delete or modify existing pairs, but you can update the values. In order to make this visually obvious, disabled input boxes show in a darker shade of grey to editable boxes. Screenshot of the boxes, those which cannot be edited or deleted are a darker grey, those which can be are white

This is my current code, it checks if the prompt is part of the existing list, and if it is, then the prompt is disabled:

@foreach (var prompt in editablePrompts){    var isNew = string.IsNullOrWhiteSpace(prompt.Key) || prompt.Key.StartsWith("new__");    var isDisabled = !isNew;    var bgColor = isDisabled ? AdminPortalColors.Gray : AdminPortalColors.LightGray;<div class="flex gap-5 align-center"><div class="flex flex-column box box-50"><Text SizeSmall="true"  Value="@prompt.Key" OnChangeText="@(newKey => OnPromptKeyChanged(prompt, newKey))" Disabled="@isDisabled" BackgroundColor="@bgColor" /></div><div class="flex flex-column box box-50"><Text SizeSmall="true"Value="@prompt.Value"            OnChangeText="@(newValue => OnPromptValueChanged(prompt, newValue))" /></div><div class="box box-10">            @if (isNew)            {<button class="btn-2 btn-l" @onclick="@(() => DeletePrompt(prompt))"><i class="fa-solid fa-trash-can"></i></button><button class="btn-7 btn-m" @onclick="SaveNewPrompt"><i class="fa-solid fa-floppy-disk"></i>Save</button></div>

This is then updated using the logic behind the onclick for save:

 private void SaveNewPrompt() {     if (editablePrompts == null) return;     var latestSet = promptSets         .Where(p => p.InstanceId.Equals(promptId, StringComparison.OrdinalIgnoreCase))         .OrderByDescending(p => p.Version)         .FirstOrDefault();     if (latestSet == null)     {         latestSet = new PromptSet             {                 InstanceId = promptId ?? "unknown",                 Version = 1,                 DateCreated = DateTime.UtcNow,                 Prompts = new Dictionary<string, string>()             };         promptSets.Add(latestSet);     }     latestSet.Prompts.Clear();     var keys = new HashSet<string>(StringComparer.OrdinalIgnoreCase);     foreach (var prompt in editablePrompts)     {         var key = prompt.Key?.Trim();         var value = prompt.Value;         if (string.IsNullOrWhiteSpace(key))         {             // Skip empty keys             continue;         }         if (!keys.Add(key))         {             // Skip duplicates             continue;         }         latestSet.Prompts[key] = value;     }     promptsDict = new Dictionary<string, string>(latestSet.Prompts);     editablePrompts = promptsDict         .Select(kvp => new EditablePrompt { Key = kvp.Key, Value = kvp.Value })         .ToList();     StateHasChanged(); }

My expectation was that, by calling state has changed, it then makes a call to the Oninitialised method of my Text component behind it? However it seems that it's caling straight to OnChange, which means the colour does not update.

@using System.ComponentModel.DataAnnotations@inject IJSRuntime JsRuntime<div class="@_containerClass"><p class="text-@((int)LabelColor)">@Label</p></div><InputText class="@_inputClass" DisplayName="@Label"           ValueExpression="@(() => Value)"           Value="@Value"           ValueChanged="(string input) => { OnChange(input); }"           @oninput="(e) => OnChange(e.Value.ToString())"           placeholder="@PlaceHolder"           id ="@HtmlId"           disabled="@Disabled"></InputText>@code {    [Parameter]    public Func<string, Task> OnChangeTextAsync { get; set; } = null;    [Parameter]    public Action<string> OnChangeText { get; set; } = null;    [Parameter]     public bool SizeSmall { get; set; } = false;    [Parameter]    [Required]    public string Label { get; set; } = string.Empty;    [Parameter]    public string PlaceHolder { get; set; }    [Parameter]    public string Value { get; set; }     [Parameter]    public string HtmlId { get; set; }    [Parameter]     public LabelColor { get; set; }= LightGray;    [Parameter]     public BackgroundColor { get; set; }= LightGray;    [Parameter] public bool MaintainValue { get; set; } = false;    /// <summary>    /// If true the input will be disabled    /// </summary>    [Parameter] public bool Disabled { get; set; } = false;    private string _inputClass = string.Empty;    private string _containerClass = string.Empty;    protected override void OnInitialized()    {        HtmlId = string.IsNullOrEmpty(HtmlId) ? Label.Replace(" ", "-") +"-input": HtmlId;        if (string.IsNullOrEmpty(PlaceHolder))        {            PlaceHolder = $"Introduce {Label}";        }        if (string.IsNullOrWhiteSpace(Value))        {            Value = string.Empty;        }        if (!Disabled && !MaintainValue && string.IsNullOrWhiteSpace(Value))        {            Value = string.Empty;        }        _containerClass += $"box flex align-left {GetBackgroundClass(BackgroundColor)}";        _inputClass += $"{GetBackgroundClass(BackgroundColor)}";        if (SizeSmall)        {            _inputClass += " small-select-input margin-tb-stage";        }    }    private async Task OnChange(string value)    {        Value = value;         if (OnChangeTextAsync is not null)        {            await OnChangeTextAsync(value);        }        else if (OnChangeText is not null)        {            OnChangeText(value);        }    }}

How do I fix this? Is the only answer to update OnChange to also take a background colour value? Or is there a better way i'm not realising?


Viewing all articles
Browse latest Browse all 4839

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>