1

Currently I have:

<InputText @oninput="@SomeHandler" />

Now I need to inherit from InputText using a class-only component and I want to the set event handler automatically in this new component, so then I would use the new component like this:

<CustomInputText />

How can I set the event handler in the custom component?

6
  • Create a Parameter of Type EventCallback in your CustomInputText. This Parameter can you bind to your base.oninput inside of CustomInputText Commented Feb 28, 2021 at 12:46
  • And how would I do that exactly? Commented Feb 28, 2021 at 14:21
  • What do you expect exactly? Do you want to pass something to the compοnent or do you want to get something from it back to the razor page which uses this custom component? Commented Feb 28, 2021 at 15:27
  • I would like to set òninput=SomeHandler (or an equivalent) directly in the ctor or OnAfterRender of the custom component. Commented Feb 28, 2021 at 16:04
  • The answer seems to be here (and check the others). I'll tag duplicate Commented Feb 28, 2021 at 19:46

1 Answer 1

1
<InputText @oninput="@SomeHandler" />

The @oninput is a compiler attribute directive intended to be used with Html tags, not with components. InputText is a component tag, not Html tag. In the past, such application was ignored or raised compilation error; currently, however, compiler attribute directives may be added by the compiler silently, but often may cause subtle issues that may be hard to discern. You should avoid this by all means.

If you want to subclass InputText and use it like this: <CustomInputText />,

you simply have to derive from the InputText, like this:

public partial class CustomInputText : InputText
{
   // Add here the internal work...
}

and use it on the EditForm (Note: it must be embedded in EditForm component) , like this:

<EditForm>
   <CustomInputText />
</EditForm>

I would like to set òninput=SomeHandler (or an equivalent) directly in the ctor or OnAfterRender of the custom component

It is important to understand that though a component is a C# class, it is a special case of a class, and you shouldn't try to use it as ordinary C# class. As for instance, you shouldn't instantiate a component like this:

CustomInputText MyCustomInputText = new CustomInputText();

And then call its methods and properties as if it was an ordinary C# class object. You should instantiate it as a component element like this:

<CustomInputText @bind-Value="myValue" /> 

This is because the rendering engine of the component model do the instantiation correctly... Now, if you instantiate your component as though it was an ordinary C# class object, you'll skip the handling of the rendering engine, which in the best cases render your component useless. I'm telling you this because you should forget the ides of constructor. No constructor...

Blazor has life cycles methods which you should override when your component is being initialized.

Below is a code sample describing how to subclass the InputText component...copy test and learn:

NumericInputText.razor.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.AspNetCore.Components.Web;


 public partial class NumericInputText : InputText
    {
        protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder)
        {
            __builder.OpenElement(0, "input");
            __builder.AddAttribute(1, "type", "number");
            __builder.AddMultipleAttributes(2, AdditionalAttributes);
            __builder.AddAttribute(3, "class", CssClass);
            __builder.AddAttribute(4, "value", CurrentValueAsString);
            __builder.AddEventPreventDefaultAttribute(5, "onkeypress", true);
            __builder.AddAttribute(6, "onblur", Microsoft.AspNetCore.Components.EventCallback.Factory.Create<Microsoft.AspNetCore.Components.Web.FocusEventArgs>(this, OnBlurEventHandler));
            __builder.AddAttribute(7, "onkeydown", Microsoft.AspNetCore.Components.EventCallback.Factory.Create<Microsoft.AspNetCore.Components.Web.KeyboardEventArgs>(this, OnKeyDown));
            __builder.AddAttribute(8, "oninput", Microsoft.AspNetCore.Components.EventCallback.Factory.Create<Microsoft.AspNetCore.Components.ChangeEventArgs>(this, OnInput));
            __builder.CloseElement();
        }

        protected override void OnInitialized()
        {
            CurrentValueAsString = "0";
        }

        private void OnInput(ChangeEventArgs args)
        {
         
            if (args.Value.ToString() == "")
            {
                CurrentValueAsString = "0";
            }
            else
            {
                CurrentValueAsString = args.Value.ToString();

            }
        }

        private void OnKeyDown(KeyboardEventArgs e)
        {
            if (e.Key == "Backspace" && CurrentValueAsString.Length == 1)
            {
                CurrentValueAsString = "";
            }


            if (e.Key == "+")
            {
                var value = int.Parse(CurrentValueAsString);
                value++;
                CurrentValueAsString = value.ToString();
            }
            else if (e.Key == "-")
            {
                var value = int.Parse(CurrentValueAsString);
                value--;
                CurrentValueAsString = value.ToString();
            }


            if (Regex.IsMatch(e.Key, "[0-9]"))
            {
                CurrentValueAsString += int.Parse($"{e.Key}").ToString();

            }

        }

        protected void OnBlurEventHandler(Microsoft.AspNetCore.Components.Web.FocusEventArgs e)
        {
            if (string.IsNullOrWhiteSpace(CurrentValueAsString))
            {
                CurrentValueAsString = "0";
            }

        }

    }  

Usage

<EditForm Model="@Model" OnValidSubmit="@HandleValidSubmit" OnInvalidSubmit="@HandleInvalidSubmit">
    <div class="alert @StatusClass">@StatusMessage</div>
    <DataAnnotationsValidator />
    <ValidationSummary />

    <div class="form-group">
        <label for="name">Name: </label>
        <NumericInputText Id="name" Class="form-control" @bind-Value="@Model.NumberSelection" />
        <ValidationMessage For="@(() => Model.NumberSelection)" />
    </div>


    <button type="submit">Ok</button>

</EditForm>

@code {

    private string StatusMessage;
    private string StatusClass;

    private Comment Model = new Comment();

    protected void HandleValidSubmit()
    {
        StatusClass = "alert-info";
        StatusMessage = DateTime.Now + " Handle valid submit";
    }

    protected void HandleInvalidSubmit()
    {
        StatusClass = "alert-danger";
        StatusMessage = DateTime.Now + " Handle invalid submit";
    }


    public class Comment
    {
        public string NumberSelection { get; set; }

    }

}
Sign up to request clarification or add additional context in comments.

2 Comments

I had to add base.BuildRenderTree(builder); at start of the method. The component is rendered but the input event is not being raised. If there is an alternative way to do it using razor instead, then it would be ok too.
"I had to add base.BuildRenderTree(builder); at start of the method" Which method ? "The component is rendered but the input event is not being raised" Do you mean that when you type a numeric value nothing happens ? No way... Do this: 1. Run the app 2. Select the zero number and type 5 instead 3. Now click on the Up icon located at the right end of the text box... now you'll see the value 6. This means that the input event was previously fired to set the value of the component to 5. You can also debug the code...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.