yToxide
yToxide

Reputation: 730

Conditional Attributes that is not boolean in blazor

I am trying to generate my own component with checkbox system to know if I need the attribute or not (of type int / float etc)

<input type="checkbox" @bind="isMinInt" />
@if (isMinInt == true) {
    <input type="number" @bind="MinInt"/>
}

So I would like to replace this @if:

@if(isMinInt == true) {
    <MyComponent @bind-Value="ValueInt" Min="@MinInt"/>
} else {
    <MyComponent @bind-Value="ValueInt"/>
}

by something like

<MyComponent @bind-Value="ValueInt" 
             @if(isMinInt == true ? Min="@MinInt" : String.Empty />

because I will have many attributes on my component and I would like to make it simplier

EDIT + Solution

Now using the @attributes:

<input type="checkbox" @bind="isMinInt" />
@if (isMinInt == true) {
   <input type="number" @bind="MinInt" />
}

<MyComponent @bind-Value="ValueInt" @attributes="GetAttributesInt()" />

@code {
    private bool isMinInt = false;
    private int MinInt;

    private IDictionary<string, object> GetAttributesInt() {
       var dict = new Dictionary<string, object>() { };
       if (isMinInt)
         dict.Add("Min", MinInt);
       return dict;
    }
}

EDIT + Solution 2

Now using the @attributes:

<input type="checkbox" @bind="isMinInt" />
@if (isMinInt == true) {
   <input type="number" @bind="MinInt" />
}

<MyComponent @bind-Value="ValueInt" @attributes="GetAttributesInt()" />

@code {
    private bool isMinInt = false;
    private int MinInt;

    private IDictionary<string, object> GetAttributesInt() {
       var dict = new Dictionary<string, object>() { };
       dict["Min"] = this.isMinInt ? MinInt : Int32.MinValue;
       return dict;
    }
}

The reason why I'm using Int32.MinValue it's because MyComponent correspond to an <input type="number"> where his min is bind to my MinInt, so if I use 0 in the place of Int32.MinValue it won't allow me to go for negative numbers.

Upvotes: 5

Views: 4364

Answers (2)

Zoha Shobbar
Zoha Shobbar

Reputation: 528

I used this simple solution and it work, hope this help you too:

<input id="@InputId"  aria-labelledby="@(!string.IsNullOrWhiteSpace(InputId) ? "this is test" : null)">

Upvotes: 2

itminus
itminus

Reputation: 25350

I will have many attributes on my component and I would like to make it simplier

You can't do that directly. However, as a walkaround, you can use the @attributes to bind attributes dynamically. For example:

<MyComponent @bind-Value="ValueInt" @attributes="@a_dictionary_expression"  />

Where @a_dictionary_expression is a C# expression that can be evaluated at runtime. What's more, you can even create a custom function to calculate the dictionary:

<MyComponent @bind-Value="ValueInt" @attributes="getAttributes()"  /gt;

@code {
    ... 
    private IDictionary getAttributes()
    {
        var dict = new Dictionary(){};
        if(isMinInt) {
            dict.Add("Min", $"{MinInt}");
        }   // this will introduce a bug, see Edit2 for more details
        return dict ;
    }
}

[Edit]: Here's a way to render the attributes within a single line

<input @bind-Value="ValueInt" @attributes="@(isMinInt? new Dictionary<string,object>{ Min= @Min} : new Dictionary<string,object>{})" />

[Edit2]

The above code will introduce a bug that the MyComponent is not updated correctly. The reason is the parameters of <MyComponent> received from previous @attributes is not automatically cleared when a new @attributes received.

For example,

  1. the first time @attributes is {Min=1}, and it results in a statement:
    MyComponent.Min=1;
    
  2. The second time @attributes is {}, because there's no attribute inside it, it won't assign parameters for it, thus the MyComponent.Min remains the same.

To fix that, change the above code as below:

private IDictionary<string, object> GetAttributesInt() {
    var dict = new Dictionary<string, object>() { };
    dict["Min"] = this.isMinInt ? MinInt : 0 ;
    return dict;
}

Upvotes: 2

Related Questions