اشتراک‌ها
پروژه River Trail

River Trail is a JavaScript library and a Firefox add-on that together provide support for data-parallel programming in JavaScript, targeting multi-core CPUs, GPUs and vector SSE/AVX instructions. 

پروژه  River Trail
نظرات مطالب
ایجاد alert,confirm,prompt هایی متفاوت با jQuery Impromptu
سلام
با تشکر از راهنمایی شما برای کنترل‌ها من از این کنترل می‌خواستم استفاده کنم ولی اجرا نشد اگه راهنماییم کنید ممنون میشم .
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">

<head>
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
<title></title>

<link href="jquery-impromptu.css" media="all" rel="stylesheet" type="text/css" />
<script src="jquery-1.8.3.min.js" type="text/javascript"></script>
<script src="jquery-impromptu.js" type="text/javascript"></script>
<script type="text/javascript">

$(function(){
$show.click(function(e){
$.prompt("Hello World!");
});
});
});

</script>
</head>

<body>
<button class="show">ShowPrompt</button>
</body>
</html>
ممنون
مطالب
نمایش ای‌جکسی یک partial view در popover بوت استرپ 3
فرض کنید بخواهیم نمایش رای دهنده‌های یک مطلب را با popover بوت استرپ 3 نمایش دهیم:

Popover بوت استرپ برای کار با منابع remote طراحی نشده‌است و نیاز است توابع API آن‌را به همراه jQuery Ajax ترکیب کرد تا به تصویر فوق رسید.


مرحله‌ی اول: اکشن متدی که یک partial view را باز می‌گرداند

فرض کنید اکشن متدی که لیست کاربران رای داده‌ی به یک مطلب را باز می‌گرداند، چنین شکلی را دارد:
        public ActionResult RenderResults(string param1)
        {
            var users = new[]
            {
                new User{ Id = 1, Name = "Test 1", Rating = 3},
                new User{ Id = 2, Name = "Test 2", Rating = 4},
                new User{ Id = 3, Name = "Test 3", Rating = 5}
            };
            return PartialView("_RenderResults", model: users);
        }
در اینجا لیستی دریافت و سپس به partial view ارسال می‌شود. در ادامه این Partial view نیز به صورت ذیل اطلاعات را رندر می‌کند:
@using RemotePopOver.Models
@model IList<User>

<ul id="ratings1" data-title="Ratings" class="list-unstyled">
    @foreach (var user in Model)
    {
        <li>
            @user.Name
            <span class="badge pull-right">@user.Rating</span>
        </li>
    }
</ul>
در اینجا از یک ویژگی سفارشی data-* به نام data-title نیز استفاده کرده‌ایم. متنی که در آن قرار می‌گیرد، به صورت عنوان popover ظاهر خواهد شد.


مرحله‌ی دوم: دریافت اطلاعات partial view با استفاده از jQuery Ajax و سپس درج آن در یک popover

می‌خواهیم با حرکت ماوس بر روی دکمه‌ی سفارشی ذیل، یک popover ظاهر شده و محتوای خودش را از اکشن متد فوق تامین کند.
<span id="remotePopover1"
      aria-hidden="true"
      data-param1="test"
      data-popover-content-url="@Url.Action("RenderResults", "Home")"
      class="glyphicon glyphicon-info-sign btn btn-info"></span>
در این مثال، چند ویژگی سفارشی data-* دیگر را نیز تعریف کرده‌ایم تا نیازی به تعریف سراسری متغیرهای جاوا اسکریپتی نباشد. برای مثال data-param1 یک پارامتر دلخواه است و data-popover-content-url به آدرس اکشن متدی اشاره می‌کند که قرار است partial view مدنظر را رندر کند.
در ادامه نحوه‌ی استفاده‌ی از این ویژگی‌ها را در jQuery Ajax مشاهده می‌کنید:
@section Scripts
{
    <script type="text/javascript">
        $(document).ready(function () {
            $('body').on('mouseenter', 'span[data-popover-content-url]', function () {
                var el = $(this);
                $.ajax({
                    type: "POST",
                    url: $(this).data("popover-content-url"),
                    data: JSON.stringify({ param1: $(this).data("param1") }),
                    contentType: "application/json; charset=utf-8",
                    dataType: "json",
                    // controller is returning a simple text, not json
                    complete: function (xhr, status) {
                        var data = xhr.responseText;
                        if (status === 'error' || !data) {
                            el.popover({
                                content: 'Error connecting server!',
                                trigger: 'focus',
                                html: true,
                                container: 'body',
                                placement: 'auto',
                                title: 'Error!'
                            }).popover('show');
                        }
                        else {
                            el.popover({
                                content: data,
                                trigger: 'focus',
                                html: true,
                                container: 'body',
                                placement: 'auto',
                                title: $('<html />').html(data).find('#ratings1:first').data('title')
                            }).popover('show');
                        }
                    }
                });
            }).on('mouseleave', 'span[data-popover-content-url]', function () {
                $(this).popover('hide');
            });
        });
    </script>
}
در این مثال تمام المان‌هایی که دارای data-popover-content-url هستند، تحت نظر قرار می‌گیرند. سپس اگر ماوس به محدوده‌ی آن‌ها وارد شد، مقدار ("this).data("popover-content-url)$ مساوی آدرسی است که قرار است اطلاعات را از سرور دریافت کند. به همین جهت از آن برای استفاده‌ی در متد ajax کمک گرفته شده‌است.
خروجی partial view به صورت json نیست. بنابراین باید اطلاعات نهایی آن‌را در callback ویژه‌ی complete دریافت کرد. مقدار data دریافتی، معادل اطلاعات رندر شده‌ی partial view است. به همین جهت آن‌را به خاصیت content متد popver ارسال می‌کنیم. همچنین چون خروجی patrtial view به همراه html است، نیاز است خاصیت html متد popover نیز به true تنظیم شود. در خاصیت title، نحوه‌ی دسترسی به مقدار data-title تنظیم شده‌ی در partial view را مشاهده می‌کنید.


کدهای کامل این مثال را از اینجا می‌توانید دریافت کنید:
RemotePopOver.zip
نظرات مطالب
ایجاد alert,confirm,prompt هایی متفاوت با jQuery Impromptu
سلام؛

طبق مطلب ارائه شده در مقاله:

تابع submit :
 function(event, value, message, formVals){}
value مقدار دکمه ای است که بروی آن کلیک شده ، message مقدار html تعریف شده برای state است ، formVals هم در صورتی که در html تعریف شده برای state ، المنت‌های فرم وجود داشته باشد ، شامل نام/مقادیر آنها می‌باشد . ( برای دریافت مقادیر فرم ، باید از نام المنت استفاده نمایید . )


خب حالا مشابه مثال زیر عمل کنید:
<div class="prompt-content" style="display: none;">
    <span>ایمیل خود را وارد نمایید : </span>
    <span>
        <input type="text" name="user_email" />
    </span>
</div>

$.prompt(
    $(".prompt-content").html(),
    {
        submit: function (e, v, m, f) {
            var userEmail = f["user_email"];
            console.log(userEmail);
        }
    });


مطالب
آپلود فایل‌های Excel در ASP.NET MVC توسط ExcelDataReader

در برنامه‌های تحت وب، در بعضی موارد نیاز داریم تا برای کاربر، امکان ثبت داده‌هایش را با آپلود فایل‌های Excel فراهم کنیم. برای مثال در مطلب خواندن اطلاعات از فایل اکسل با استفاده از LinqToExcel ، امکان خواندن از Excel توضیح داده شده، اما نقطه ضعف این روش‌ها، وابستگی به Providerهای مایکروسافت است که در صورت عدم نصب آن ها:

Microsoft.Jet.OLEDB.4.0 provider --> Excel 97-2003 format (.xls)
Microsoft.ACE.OLEDB.12.0 provider --> Excel 2007+ format (.xlsx)
با خطاهای زیر روبرو می‌شویم:
The ‘Microsoft.Jet.OLEDB.4.0’ provider is not registered on the local machine
The ‘Microsoft.ACE.OLEDB.12.0’ provider is not registered on the local machine

البته راه حل، نصب  Office 2007 Data Connectivity Components یا Office 2010 Database Engine بر روی سرور می‌باشد. اما اگر هاست اشتراکی بوده و اجازه نصب نداشته باشیم؟

در این مقاله به بررسی کتابخانه ExcelDataReader می‌پردازیم که امکان خواندن فایل‌های اکسل را بدون نیاز به نصب هرگونه پیش نیازی بر روی سرور، برای ما فراهم می‌کند.

برای این کار:

1-  ابتدا یک پروژه خالی Asp.Net MVC  را ایجاد می‌کنیم.
2-  با استفاده از دستورات زیر در Package Manager Console بسته‌های ExcelDataReader و ExcelDataReader.DataSet را نصب می‌کنیم:

PM> Install-Package ExcelDataReader
PM> Install-Package ExcelDataReader.DataSet
توجه: دو روش برای خواندن از فایل‌های اکسل در این کتابخانه وجود دارد که نصب بسته دوم مربوط به روش دوم آن است.


3-  سپس کنترلر مورد نظر (در اینجا HomeController) را ایجاد نموده و اکشن Upload را بصورت زیر در آن قرار می‌دهیم:

public ActionResult Upload()
{
      return View();
}

4- برای آپلود فایل، اکشن دیگری را با نام Upload نیاز داریم که آن را بصورت زیر ایجاد می‌کنیم:

توجه: در قطعه کد زیر سعی شده از حداقل کانفیگ کتابخانه استفاده شود. کانفیگ بیشتر

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Upload(HttpPostedFileBase upload)
{  
           // اعتبار سنجی فایل آپلود شده
            if (upload != null && upload.ContentLength > 0 && (upload.FileName.EndsWith(".xls") || upload.FileName.EndsWith(".xlsx")))
            {
                // با خواندن فایل به صورت باینری، این کتابخانه نیازی به نصب پیش نیازهای آفیس ندارد
                Stream stream = upload.InputStream;

                //  نیازی به نگرانی در مورد پسوند فایل نیست
                // کتابخانه به صورت خودکار کلاس مورد نظر برای پسوند مربوطه را استفاده می‌کند
                // ExcelDataReader.ExcelBinaryReader یا ExcelDataReader.ExcelOpenXmlReader
                IExcelDataReader reader = ExcelReaderFactory.CreateReader(stream);

                // روش ذکر شده در قسمت دوم برای خواندن کل اطلاعات بصورت یکجا
                DataSet result = reader.AsDataSet(new ExcelDataSetConfiguration()
               {
                    ConfigureDataTable = (tableReader) => new ExcelDataTableConfiguration()
                    {
                        // true: ردیف اول از فایل را به عنوان هدر در نظر می‌گیرد
                        // مقدار پیش فرض: false
                        UseHeaderRow = true
                    }
                });

                reader.Close();
                return View(result.Tables[0]);
            }
      ModelState.AddModelError("File", "Please upload Excel file ...");
      return View();
 }  

  روش دیگر خواندن اطلاعات:
do {
        while (reader.Read()) {
       // reader.GetDouble(0);
        }
    } while (reader.NextResult());


5-  خب حالا از یک View (با نام Upload) هم برای ارسال فایل و همچنین نمایش محتویات آپلود شده بصورت زیر استفاده می‌کنیم:
@model System.Data.DataTable
@using System.Data;

<h2>Upload File</h2>

@using (Html.BeginForm("Upload", "Home", null, FormMethod.Post, new { enctype = "multipart/form-data" }))
{
    @Html.AntiForgeryToken()
    @Html.ValidationSummary()

    <div>
        <input type="file" id="dataFile" name="upload" />
    </div>

    <div>
        <input type="submit" value="Upload" />
    </div>

    if (Model != null)
    {
        <table>
            <thead>
                <tr>
                    @foreach (DataColumn col in Model.Columns)
                    {
                        <th>@col.ColumnName</th>
                    }
                </tr>
            </thead>
            <tbody>
                @foreach (DataRow row in Model.Rows)
                {
                    <tr>
                        @foreach (DataColumn col in Model.Columns)
                        {
                            <td>@row[col.ColumnName]</td>
                        }
                    </tr>
                }
            </tbody>
        </table>
    }
}
توجه داشته باشید که این مثال آموزشی است و در پروژه واقعی، قطعا روش‌های بهتری برای پردازش، پیمایش و نمایش محتوا وجود دارد.


6-  حالا پروژه را اجرا می‌کنیم تا خروجی را مشاهده کنیم.

ابتدا فایل مورد نظر را انتخاب و آپلود می‌کنیم:


انتخا فایل اکسل

و خروجی به صورت زیر خواهد بود:

خروجی

کدهای کامل این مثال را از اینجا می‌توانید دریافت کنید: UploadExcelFiles.rar

منابع: ^ و ^

مطالب
مدیریت طول عمر DbContext در برنامه‌های Blazor SSR

فرض کنید یک صفحه‌ی Blazor SSR، از سه کامپوننت منوی سمت راست، محتوای اصلی صفحه و فوتر سایت که به همراه متنی است، تشکیل شده‌است. منوی سمت راست، به همراه لینک‌هایی‌است که آمار آن‌ها را نیز نمایش می‌دهد و این اطلاعات را از بانک اطلاعاتی، به کمک EF-Core دریافت می‌کند. فوتر صفحه، سال شروع به کار و نام برنامه را از بانک اطلاعاتی دریافت می‌کند و محتوای اصلی صفحه نیز از بانک اطلاعاتی دریافت می‌شود. پس از تکمیل این سه کامپوننت مجزا، اگر برنامه را اجرا کنید، بلافاصله با خطای زیر مواجه می‌شوید:

A second operation started on this context before a previous operation completed

مشکل کجاست؟! مشکل اینجاست که تنها یک نمونه از DbContext، در طول درخواست جاری رسیده، بین سه کامپوننت جاری برنامه به اشتراک گذاشته می‌شود (به سازنده‌ی سرویس‌های مرتبط تزریق می‌شود) و ... در Blazor SSR، پردازش کامپوننت‌های یک صفحه، به صورت موازی و همزمان انجام می‌شوند؛ یعنی ترتیبی نیست. اگر ابتدا کامپوننت منو، بعد محتوای صفحه و در آخر فوتر، رندر می‌شدند، هیچگاه پیام فوق را مشاهده نمی‌کردیم؛ اما ... هر سه کامپوننت، با هم و همزمان رندر می‌شوند و سپس نتیجه‌ی نهایی در Response درج خواهد شد. یعنی یک DbContext بین چندین ترد به اشتراک گذاشته می‌شود که چنین حالتی توسط EF-Core پشتیبانی نمی‌شود و مجاز نیست.

روش مواجه شدن با یک چنین حالت‌هایی، نمونه سازی مجزای DbContext به ازای هر کامپوننت است که نمونه‌ای از آن‌را پیشتر در مطلب «نکات ویژه‌ی کار با EF-Core در برنامه‌های Blazor Server» مشاهده کرده‌اید. در این مطلب، راه‌حل دیگری برای اینکار ارائه می‌شود که ساده‌تر است و نیازی به تغییرات آنچنانی در کدهای کامپوننت‌ها و کل برنامه ندارد.

استفاده از کلاس پایه‌ی OwningComponentBase برای نمونه سازی مجدد DbContext به‌ازای هر کامپوننت

زمانیکه در برنامه‌های Blazor SSR از روش استاندارد زیر برای دسترسی به سرویس‌های مختلف برنامه استفاده می‌کنیم:

@inject IHotelRoomService HotelRoomService

طول عمر دریافتی سرویس، دقیقا بر اساس طول عمر اصلی تعریف شده‌ی آن عمل می‌کند (شبیه به برنامه‌های ASP.NET Core). یعنی برای مثال اگر Scoped باشد، DbContext تزریق شده‌ی در آن هم Scoped است و این DbContext، بین تمام کامپوننت‌های در حال پردازش موازی در طول یک درخواست، به‌اشتراک گذاشته می‌شود که مطلوب ما نیست. ما می‌خواهیم بتوانیم به ازای هر کامپوننت مجزای صفحه، یک DbContext جدید داشته باشیم. یعنی باید بتوانیم خودمان این سرویس Scoped را نمونه سازی کنیم و نه اینکه آن‌را مستقیما از سیستم تزریق وابستگی‌ها دریافت کنیم.

بنابراین اگر بخواهیم قسمت‌های مختلف برنامه را تغییر ندهیم و همان تعاریف ابتدایی services.AddDbContext و Scoped تعریف کردن سرویس‌های برنامه بدون تغییر باقی بمانند (و از IDbContextFactory و موارد مشابه دیگر مطلب «نکات ویژه‌ی کار با EF-Core در برنامه‌های Blazor Server» هم استفاده نکنیم)، باید جایگزینی را برای نمونه سازی سرویس‌ها ارائه دهیم. به همین جهت در ابتدا، یک ویژگی جدیدی را به صورت زیر تعریف می‌کنیم:

[AttributeUsage(AttributeTargets.Property)]
public sealed class InjectComponentScopedAttribute : Attribute
{
}

تا بتوانیم بجای:

@inject IHotelRoomService HotelRoomService

بنویسیم:

[InjectComponentScoped] internal IHotelRoomService HotelRoomService { set; get; } = null!;

مرحله‌ی بعد، نوبت به نمونه سازی خودکار این سرویس‌های درخواستی علامتگذاری شده‌ی با InjectComponentScoped است. برای این منظور، تمام کامپوننت‌های برنامه را از کلاس پایه و استاندارد OwningComponentBase ارث‌بری می‌کنیم. مزیت اینکار، امکان دسترسی به خاصیتی به نام ScopedServices در تمام کامپوننت‌های برنامه است که توسط آن می‌توان به متد ScopedServices.GetRequiredService آن دسترسی یافت. یعنی با ارث‌بری از کلاس پایه‌ی OwningComponentBase به ازای هر کامپوننت، به صورت خودکار Scope جدیدی شروع می‌شود که توسط آن می‌توان به نمونه‌ی جدیدی از سرویس مدنظر دسترسی یافت و نه به نمونه‌ی اشتراکی در طی درخواست جاری.

اکنون اگر از این مزیت به صورت زیر استفاده کنیم، می‌توان تمام سرویس‌های درخواستی مزین به InjectComponentScopedAttribute یک کامپوننت را به صورت خودکار یافته و با استفاده از ScopedServices.GetRequiredService، مقدار دهی کرد:

public class BlazorScopedComponentBase : OwningComponentBase
{
    private static readonly ConcurrentDictionary<Type, Lazy<List<PropertyInfo>>> CachedProperties = new();

    private List<PropertyInfo> InjectComponentScopedPropertiesList => CachedProperties.GetOrAdd(GetType(),
            type => new Lazy<List<PropertyInfo>>(
                () => type.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance |
                                         BindingFlags.NonPublic | BindingFlags.Public)
                    .Where(p => p.GetCustomAttribute<InjectComponentScopedAttribute>() is not null)
                    .ToList(), LazyThreadSafetyMode.ExecutionAndPublication)).Value;

    protected override void OnInitialized()
    {
        foreach (var propertyInfo in InjectComponentScopedPropertiesList)
        {
            propertyInfo.SetValue(this, ScopedServices.GetRequiredService(propertyInfo.PropertyType));
        }
    }
}

این سرویس، اینبار طول عمری، محدود به کامپوننت جاری را خواهد داشت و بین سایر کامپوننت‌های درحال پردازش درخواست جاری، به اشتراک گذاشته نمی‌شود و همچنین به صورت خودکار هم در پایان درخواست، Dispose می‌شود.

فعالسازی ارث‌بری خودکار در تمام کامپوننت‌های برنامه

مرحله‌ی بعد، ارث‌بری خودکار تمام کامپوننت‌های برنامه از OwningComponentBase سفارشی فوق است و در اینجا قصد نداریم تمام کامپوننت‌ها را جهت معرفی آن، به صورت دستی تغییر دهیم. برای اینکار فقط کافی است به فایل Imports.razor_ مراجعه و یک سطر زیر را در آن درج کنیم:

@inherits BlazorScopedComponentBase

با اینکار یک ارث‌بری سراسری در کل برنامه رخ می‌دهد و تمام کامپوننت‌ها، از BlazorScopedComponentBase مشتق خواهند شد. یعنی پس از این تغییر، اگر سرویسی را به صورت زیر معرفی و با ویژگی InjectComponentScoped علامتگذاری کردیم:

[InjectComponentScoped] internal IHotelRoomService HotelRoomService { set; get; } = null!;

به صورت خودکار یافت شده و نمونه سازی Scoped محدود به طول عمر همان کامپوننت می‌شود که بین سایر کامپوننت‌ها، به اشتراک گذاشته نخواهد شد.

یک نکته: اگر کامپوننت شما متد OnInitialized را بازنویسی می‌کند، ‌فراموش نکنید که در ابتدای آن باید ()base.OnInitialized را هم فراخوانی کنید تا متد OnInitialized کامپوننت پایه‌ی BlazorScopedComponentBase نیز فراخوانی شود. البته این مورد در حین بازنویسی نمونه‌ی async آن مهم نیست؛ چون همیشه OnInitialized غیر async در ابتدا فراخوانی می‌شود و سپس نمونه‌ی async آن اجرا خواهد شد.

مطالب
تغییرات بوجود آمده در Razor -MVC4
همانطوری که میدونید نسخه    MVC 4 RC   در دسترس قرار گرفته و خالی از لطف نیست که یک بررسی درباره امکانات جدیدش انجام بشه.ابتدا سعی میکنم یک لیست کلی از امکانان این تکنولوژی داشته باشیم و بعد نگاهی هم به Razor  و تغییراتش خواهیم داشت.
 
ASP.NET Web API
Refreshed and modernized default project templates
New mobile project template
Many new features to support mobile apps
Recipes to customize code generation
Enhanced support for asynchronous methods 
لیست فوق شامل برترین ویژگی‌های این نسخه است که در پستهای آینده هر کدام از این‌ها بررسی خواهند شد.

تغییرات Razor
Razor از نسخه MVC4 Beta شاهد تغییرات و بهبود هایی بود که این تغییرات بنیادی و رادیکالی نبودند و فقط درجهت بهبود حس کاربری آن صورت گرفت. این حس از آن جهت است که شما نیاز به نوشتن کد کمتری دارید.

استفاده نکردن از  Url.Content@ 
در نسخه قبلی از امکان ذکر شده برای مشخص کرده مسیر‌های CSS و فایلهای .JS هم استفاده میشد حالا بجای استفاده از آن میشود:
در نسخه‌های قبلی:
<script src="@Url.Content("~/Scripts/Site.js")"></script>
 در نسخه 4:
<script src="~/Scripts/Site.js"></script> 
زمانی که Razor  حرف را ~/   تشخیص می‌دهد خروجی یکسانی با حالت قبلی برای ما درست می‌کند.

شرط ها(Conditions)
در نسخه قبلی برای استفاده از attribute ها که ممکن بود Null باشند مجبور به چک کردن آنها بودیم:
<div @{if (myClass != null) { <text>class="@myClass"</text> } }>Content</div>
اما حالا با خیال راحت می‌توان نوشت:
<div class="@myClass">Content</div>
که اگر attribute ما null باشد به صورت اتوماتیک تشخیص داده میشود و کد زیر رندر میشود
<div>Content</div>
در ضمناً کد بالا فقط مربوط به چک کردن Nullable نیست و از آن می‌توان در Boolean‌ها هم استفاده کرد.
<input checked="@ViewBag.Checked" type="checkbox"/>
که اگر مقدار True نباشد:
<input type="checkbox"/>
بطور خلاصه میشه گفت MVC4 تغییراتش نسبت به نسخه قبلی تو خیلی از زمینه‌ها مربوط میشه بهبود ابزارهای موجود در کل کار با این ایزار بسیار برای من لذت بخشه.
ادامه دارد...
نظرات مطالب
شروع به کار با AngularJS 2.0 و TypeScript - قسمت یازدهم - کار با فرم‌ها - قسمت دوم
- data binding یعنی دقیقا به روز شدن اطلاعات با تغییرات کاربر. اگر مدنظر شما نیست، به صورت دستی آن‌را مدیریت کنید. ابتدا کار اتصال به رخداد blur را انجام دهید:
<input type="text" [(ngModel)]="myModel" (blur)="onBlurMethod()">
و بعد تعریف متد معادل آن در کلاس کامپوننت:
export class AppComponent {  
   myModel: any;  

   constructor(){
          this.myModel = '123';  
   }

   onBlurMethod(){  
     alert(this.myModel);   
   }
}

+ Observableها دارای متدی هستند به نام debounceTime که برای همین منظور طراحی شده‌است. یک مثال:
export class AppComponent {
    searchForm: ControlGroup;
    results: Observable<any[]>;

    constructor(private http: Http) {
        let searchField = new Control();
        this.searchForm = new ControlGroup({searchField});
        this.results = searchField.valueChanges
                  .debounceTime(500)
                  .switchMap((val:string) => {
                         return this.search(val);
                  });
    }
البته این مورد بر روی async validation تاثیری ندارد. برای رفع این مشکل می‌توان از راه حلی مانند «Debouncing Angular 2 Input Component» و یا «How to add debounce time to an async validator in angular 2» استفاده کرد (فعلا؛ در زمان نگارش این مطلب).
نظرات مطالب
Blazor 5x - قسمت هشتم - مبانی Blazor - بخش 5 - تامین محتوای نمایشی کامپوننت‌های فرزند توسط کامپوننت والد
یک نکته‌ی تکمیلی: امکان داشتن متدهایی با خروجی تگ‌دار در برنامه‌های Blazor (یا تعریف کامپوننت‌های پویا)

اگر با React کار کرده باشید، یک چنین کدهایی اساس آن‌را تشکیل می‌دهند:
import React from "react";

const Rentals = () => {
  return <h1>Rentals</h1>;
};

export default Rentals;
در اینجا کامپوننتی به نام Rentals تعریف شده‌است که خروجی آن ... یک تگ HTML ای است و برای تشکیل آن نیازی به استفاده از "" و چسباندن رشته‌ها نبوده‌است. دقیقا شبیه به یک چنین کاری را می‌توان در برنامه‌های Blazor نیز انجام داد که به آن «Razor template syntax» و یا «templated components» هم گفته می‌شود:
@page "/razor"

@template
@ItemTemplate(emp)

@code {

    RenderFragment template = @<p>The time is @DateTime.Now.</p>;
    RenderFragment<Employee> ItemTemplate = (item) => @<p>Employee name is @item.Name.</p>;

    Employee emp = new Employee { Name = "Test" };

    public class Employee
    {
        public string Name;
    }
}
در اینجا همانطور که مشاهده می‌کنید، امکان انتساب یک قالب HTML ای شروع شده‌ی با @ به یک RenderFragment وجود دارد که حتی می‌تواند جنریک هم باشد و وهله‌ای از این شیء جنریک را به صورت یک lambda expression دریافت کند. روش درج آن‌ها را در صفحه نیز مشاهده می‌کنید که همانند فراخوانی متدها است و برای نمونه ItemTemplate جنریک، وهله‌ای از فیلد emp تعریف شده‌ی در قسمت code را دریافت کرده و در صفحه نمایش می‌دهد.
یا حتی می‌توان از RenderFragment برای وهله سازی پویای یک کامپوننت مانند SurveyPrompt، مقدار دهی خاصیت Title آن و درج آن در صفحه به صورت زیر هم استفاده کرد:
 @page "/"
  
 @CreateDynamicComponent()

 @code {
     RenderFragment CreateDynamicComponent() => builder =>
     {
         builder.OpenComponent(0, typeof(SurveyPrompt));
         builder.AddAttribute(1, "Title", "Some title");
         builder.CloseComponent();
     };
 }