Skip to content
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

Cannot bind value of element and have onchange event fire. Can only have either or. #15882

Closed
haasey opened this issue Jun 19, 2018 · 7 comments
Labels
area-blazor Includes: Blazor, Razor Components

Comments

@haasey
Copy link

haasey commented Jun 19, 2018

<select id="cboLocations" bind="@uiLocation" onchange="@loadforms">
<option value="A">A_</option>
<option value="B">B_</option>
<option value="C">C_</option>
<option value="D">D_</option>
</select>

@functions {
string uiLocation =""
protected async void LoadForms()
{
// does an async call relying on the value of uiLocation variable
}
}

@chucker
Copy link

chucker commented Jun 19, 2018

Yes, bind is currently always a two-way bind. If you want a more custom scenario, change LoadForms() to also set uiLocation to the new value, and also amend the <option> tags to get the current value, like so:

<option value="A" selected="@(uiLocation == "A")">A_</option>

@haasey
Copy link
Author

haasey commented Jun 20, 2018

Appreciate the hint but haven't figured this out yet. How would I access the uiLocation if I can't bind it to the select html control? Seems like a chicken/egg scenario if you can't bind a value and call an event trigger on the same element. I find this to be rather limiting, but i assume I am just missing something.

If I can't have bind and have an onchange for a single dropdown then I need to figure out a way to call an event and reference the selected value of a dropdown within that event. Similar to old school asp webforms where the controls were server side. I haven't seen this ability yet but admittedly I'm still learning it.

@haasey
Copy link
Author

haasey commented Jun 20, 2018

Looking at your suggestion again, it looks like if I set the value of uiLocation, it would then set the selected value of the dropdown without me needing the bind keyword. Clever.
My scenario is the opposite though. I want to read the value of the select, and use it for a parameter in a event fired by the onchange of the select element. I can't figure out how to read the value if it isn't bound and not resulting to some javascript interop. If we are forced to go to javascript / interop, than this project loses some of its steam IMO.

@chucker
Copy link

chucker commented Jun 20, 2018

You don't need JS interop for this, but you do need to store uiLocation yourself.

The way I approached this (well, in my case, it was for radio buttons, not a drop-down, but same difference) was to create a component EnumRadioButtons that gets passed an enum type as a parameter. That way, it can populate the <option> tags itself using Enum.GetValues(), while holding the selected value as a .NET property.

There's no JS involved it (though there might be if I would use, say, visual effects from a JS library), but there's a fair bit of C# boilerplate involved still.

@SteveSandersonMS
Copy link
Member

We are still evolving the "bind" APIs, so over time this might change depending on what people report, but right now there's a better way of achieving your goal.

Instead of using onchange and bind separately, just use bind on its own and then put logic into your property setter to take some action when it changes. This is much clearer than using bind and onchange together because it lets you be totally explicit about what order you want things to run in (e.g., whether you run your logic before the property value is updated, or after that).

This doesn't require resorting to any JS interop.

Example:

<select id="cboLocations" bind="@uiLocation">...</select>

@functions {
    string _uiLocation;
    string uiLocation
    {
        get => _uiLocation;
        set
        {
            // Run some logic before the value is updated here...
            _uiLocation = value;
            // ... or after value is updated here.
        }
    }
}

@Code-Chops
Copy link

I made a workaround for this by creating a method that sets the value of the inputModel:

<input type="number" onchange=@((arg) => OnChange(arg, this.InputModel, inputModel => input.Number) />

@functions
{
    void OnChange<TObject, TValue>(UIChangeEventArgs uIChangeEventArgs, TObject target, Expression<Func<TObject, TValue>> propertyGetter)
    {
        if (uIChangeEventArgs?.Value != null)
        {
            var expression = (MemberExpression)propertyGetter.Body;
            var property = (PropertyInfo)expression.Member;
            property.SetValue(target, uIChangeEventArgs.Value);

            // Do your own stuff here
        }
    }
}

@furoraest
Copy link

I made a workaround for this by creating a method that sets the value of the inputModel:

<input type="number" onchange=@((arg) => OnChange(arg, this.InputModel, inputModel => input.Number) />

@functions
{
    void OnChange<TObject, TValue>(UIChangeEventArgs uIChangeEventArgs, TObject target, Expression<Func<TObject, TValue>> propertyGetter)
    {
        if (uIChangeEventArgs?.Value != null)
        {
            var expression = (MemberExpression)propertyGetter.Body;
            var property = (PropertyInfo)expression.Member;
            property.SetValue(target, uIChangeEventArgs.Value);

            // Do your own stuff here
        }
    }
}

Seems like a function what I am needing... care to elaborate what packages/addons needed to be used for getting those params? If i try to use this i am getting something like that: The type or namespace name 'TValue' could not be found (are you missing a using directive or an assembly reference?)

@mkArtakMSFT mkArtakMSFT transferred this issue from dotnet/blazor Oct 27, 2019
@mkArtakMSFT mkArtakMSFT added the area-blazor Includes: Blazor, Razor Components label Oct 27, 2019
@ghost ghost locked as resolved and limited conversation to collaborators Dec 3, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-blazor Includes: Blazor, Razor Components
Projects
None yet
Development

No branches or pull requests

6 participants