ساخت کامپوننت سفارشی با InputBase در Blazor

توی این مقاله یاد میگیریم چطور با استفاده از <InputBase<T در Blazor یه کامپوننت ورودی کاملاً سفارشی بسازیم که قبل از ذخیره، مقدار ورودی رو بررسی یا حتی اصلاح کنه. با یه مثال واقعی، قدم‌ به‌ قدم نشون میدم چطور میتونیم کنترل کامل روی داده‌ های ورودی داشته باشیم، از Validation داخلی Blazor استفاده کنیم، و در نهایت یه ورودی تمیز، هوشمند و قابل استفاده‌ ی مجدد بسازیم.


اگه تا حالا با فرم‌ ها و ورودی‌ ها توی Blazor کار کرده باشی، احتمالاً اسم <InputBase<T به گوشت خورده. یه کلاس پایه‌ ست که میتونی باهاش هر نوع ورودی خاص خودت رو بسازی؛ مثلاً یه input که خودش یه سری کار خاص انجام بده یا قبل از ذخیره، مقدار رو تغییر بده.

من توی یکی از پروژه‌هام یه کامپوننت ساختم به اسم AutoReplacer که موقع تایپ، یه سری کلمات رو به‌صورت خودکار جایگزین میکنه. مثلاً اگه یکی بنویسه salam، خودش میشه سلام 😄
توی این پست میخوام بگم چجوری اینو با InputBase ساختم.


ایده‌ ی AutoReplacer

فکرش این بود که یه کامپوننت بسازم که هر وقت کاربر یه کلمه خاص تایپ کرد، خودش اون رو با یه مقدار دیگه عوض کنه.
مثلاً:

قبل بعد از جایگزینی
salam سلام
khodahafez خداحافظ

خیلی وقتا همچین چیزی توی فرم‌ها لازمه، مخصوصاً اگه بخوای ورودی تمیزتر یا استانداردتر ذخیره بشه.


کد اصلی کامپوننت

کامپوننت از InputBase<string> ارث‌ بری می‌کنه. این یعنی خودش به صورت خودکار با EditForm، Validation، و @bind-Value سازگاره.

 
 

@inherits InputBase<string>

@using System.Linq.Expressions

@if (IsTextArea)
{
    <textarea class="@Class"
              @bind="CurrentValueAsString"
              @bind:event="oninput"
              maxlength="@MaxLength"
              disabled="@IsDisabled"
              placeholder="@Placeholder"></textarea>
}
else
{
    <input class="@Class"
           @bind="CurrentValueAsString"
           @bind:event="oninput"
           maxlength="@MaxLength"
           disabled="@IsDisabled"
           placeholder="@Placeholder" />
}

<span><ValidationMessage For="ValidationFor" /></span>

@code {
    [Parameter, EditorRequired] public Expression<Func<string>> ValidationFor { get; set; } = default!;
    [Parameter, EditorRequired] public Dictionary<string, string> ReplacementsItems { get; set; } = new();
    [Parameter] public bool IgnoreCase { get; set; } = true;
    [Parameter] public string Placeholder { get; set; } = "Enter your text";
    [Parameter] public string Class { get; set; } = "form-control";
    [Parameter] public int MaxLength { get; set; } = 1000;
    [Parameter] public bool IsDisabled { get; set; }
    [Parameter] public bool IsTextArea { get; set; }

    protected override bool TryParseValueFromString(string? value, out string result, out string validationErrorMessage)
    {
        var input = value ?? string.Empty;

        foreach (var (key, replacement) in ReplacementsItems)
        {
            input = input.Replace(key, replacement, IgnoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal);
        }

        if (input.Length > MaxLength)
            input = input.Substring(0, MaxLength);

        result = input;
        validationErrorMessage = null;
        return true;
    }
}


نقش متد TryParseValueFromString

اینجا قسمت مهم ماجراست!
هر بار که کاربر چیزی تایپ می‌کنه، Blazor مقدار رو از HTML می‌گیره و از طریق این متد سعی می‌کنه اون رو به نوع مورد نظر (string در اینجا) تبدیل کنه.

من داخل این متد گفتم:

  1. مقدار ورودی رو بگیر.

  2. همه‌ی کلیدهای ReplacementsItems رو بگرد و با مقدار جایگزینش عوض کن.

  3. اگه طول متن از MaxLength بیشتر بود، کوتاهش کن.

  4. خروجی نهایی رو برگردون.

TryParseValueFromString یه جورایی محل کنترل کامل ورودی کاربره؛ قبل از اینکه مقدار واقعاً به مدل فرم برسه.


چرا از InputBase استفاده کنیم؟

چون وقتی از InputBase ارث‌بری می‌کنی:

  • کامپوننتت با EditForm و Validation کاملاً یکی میشه.

  • لازم نیست نگران @bind-Value باشی، خودش هندل میکنه.

  • میتونی هر منطقی بخوای روی ورودی اجرا کنی (مثل Replace، Trim، یا حتی Validation سفارشی).


مثال از استفاده در فرم

<EditForm Model="@model">
    <AutoReplacerInput 
        @bind-Value="@model.Text"
        ValidationFor="() => model.Text"
        ReplacementsItems="new() { ["salam"] = "سلام", ["khodahafez"] = "خداحافظ" }"
        Placeholder="متن خودت رو بنویس..." />
    <button type="submit">ارسال</button>
</EditForm>

@code {
    private MyModel model = new();
    public class MyModel { public string Text { get; set; } = string.Empty; }
}

اینجوری هر بار که کاربر salam تایپ کنه، خودکار تبدیل میشه به سلام.


جمع‌بندی

به کمک InputBase<T> می‌تونی هر نوع کنترل ورودی مخصوص خودت رو بسازی.
در کامپوننت BlazorAutoReplacer این قابلیت رو اضافه کردم تا ورودی‌ ها به صورت خودکار تمیز و جایگزین بشن.
میتونی خود کامپوننت آماده‌شده رو هم از اینجا ببینی:
🔗 GitHub Repository:

https://github.com/MohammadSajjadian/BlazorAutoReplacer


🔗 NuGet Package:

MSJD.AutoReplacer