Skip to content

select component renders on first change with null value when inside CascadingValue=this and plain wrapper #41424

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
1 task done
omuleanu opened this issue Apr 28, 2022 · 4 comments
Labels
area-blazor Includes: Blazor, Razor Components ✔️ Resolution: Answered Resolved because the question asked by the original author has been answered. question Status: Resolved

Comments

@omuleanu
Copy link

omuleanu commented Apr 28, 2022

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

using the code below, on first select from the select dropdown the selected value will be set to null

<MyContext>
    <Field>
        <MySelect @bind-Value="model1.Val1"></MySelect>
    </Field>
</MyContext>
@*if I remove from here either `Field` or `MyContext` the problem disappears:*@
<p>
    val1: @model1.Val1
</p>
@code {
    private Model1 model1 = new();
}

Model1:

public class Model1
{
    public string Val1 { get; set; }
}

Field:

@ChildContent
@code {
    [Parameter]
    public RenderFragment ChildContent { get; set; }
}

MyContext:

<CascadingValue Value="this">
    @ChildContent
</CascadingValue>

@code {
    [Parameter]
    public RenderFragment? ChildContent { get; set; }
}

MySelect:

<select class="awe-display" @onchange="async (args) => await onValueChange(args)">
    @foreach (var item in data)
    {
        <option value="@item" selected="@(Equals(item, value))">@item</option>
    }
</select>

@code {
    private string value;
    private string[] data = new[] { null, "aaa", "bbb", "ccc" };

    [Parameter]
    public string Value
    {
        set
        {
            this.value = value;
        }
    }
    
    /// without this the bug is not present
    [CascadingParameter]
    public MyContext? MyContext { get; set; } 

    [Parameter]
    public EventCallback<string> ValueChanged { get; set; }

    private async Task onValueChange(ChangeEventArgs args)
    {
        await changeValue(args.Value);
    }

    private async Task changeValue(object objval)
    {
        BindConverter.TryConvertTo<string>(objval, System.Globalization.CultureInfo.CurrentCulture, out var val);
        if (Equals(value, val)) return;

        value = val;

       // without this the bug is not present
        await ValueChanged.InvokeAsync(value);
    }
}

Expected Behavior

the select dropdown should show the value selected by the user, not null

.NET Version

6

Anything else?

VS 2022

@omuleanu omuleanu changed the title component renders on first change with null value when inside CascadingValue=this and plain wrapper select component renders on first change with null value when inside CascadingValue=this and plain wrapper Apr 28, 2022
@TanayParikh TanayParikh added the area-blazor Includes: Blazor, Razor Components label Apr 28, 2022
@javiercn
Copy link
Member

@omuleanu thanks for contacting us.

I suspect the issue here is that you are not using @bind within the select component and given that you have an async handler, the rendering is "messing" with the results. You can validate this if you put breakpoints within your handler and your render functions. You'll likely see a render happen before the first await and at that point the value updated.

We are working on a feature to enable "async bindings" that will retain the "special sauce" we include in bind to resolve conflicts between values in these situations that can be found here

@danroth27 danroth27 added the ✔️ Resolution: Answered Resolved because the question asked by the original author has been answered. label Apr 28, 2022
@ghost ghost added the Status: Resolved label Apr 28, 2022
@omuleanu
Copy link
Author

@javiercn without async the result exactly is the same ( I replaced all async Task with void )
what helps is removing Field wrapper which does nothing

@omuleanu
Copy link
Author

omuleanu commented Apr 28, 2022

@javiercn version with bind is worse, the value never gets selected, I have to remove both Field and MyContext wrappers in Index.razor for the value to get selected,
here's the bind version of MySelect :

<select @bind="Value">
    @foreach (var item in data)
    {
        <option value="@item" selected="@(Equals(item, value))">@item</option>
    }
</select>

@code {
    private string value;
    private string[] data = new[] { null, "aaa", "bbb", "ccc" };

    [Parameter]
    public string Value
    {
        get { return value; }
        set
        {
            if (this.value == value) return;

            this.value = value;
            
            ValueChanged.InvokeAsync(Value).Wait();
        }
    }
    
    [CascadingParameter]
    public MyContext? MyContext { get; set; }

    [Parameter]
    public EventCallback<string> ValueChanged { get; set; }
}

(before writing this post I was actually expecting you'd mention bind, and I tried it in the bigger/non isolated app, same result)

@ghost
Copy link

ghost commented Apr 29, 2022

This issue has been resolved and has not had any activity for 1 day. It will be closed for housekeeping purposes.

See our Issue Management Policies for more information.

@ghost ghost closed this as completed Apr 29, 2022
@ghost ghost locked as resolved and limited conversation to collaborators May 29, 2022
This issue was closed.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-blazor Includes: Blazor, Razor Components ✔️ Resolution: Answered Resolved because the question asked by the original author has been answered. question Status: Resolved
Projects
None yet
Development

No branches or pull requests

4 participants