مركبة لرؤية المتصفحات ASP.NET Core Tag Helper (Part 1.1, kinda sortaM SK3A Flippy tag helperMSC4
المقدمة
لذا خلال بناء مشروع قمت ببناء ومساعد البطاقة المرسلة من أجل أنا أيضاً أتخطى حاجة أخرى. طريقة لبناء ببساطة وظائف الفرز لجدول النتائج مع دعم HtMX.
إذن ...أقدم لكم مُساعد تَمَكْلِفِيْبِيِيَيْمَسْرْيْيَمْسْنْيّ هذا مجرد مقال سريع مع الكثير من البرمجة. يمكنك دائماً رؤية العينات هنا. ورمز المصدر كما هو الحال هو هنا.
أنا أحاول أن أضيف المزيد والمزيد وأنا أسير along لتشغيل:
dotnet add package mostlylucid.pagingtaghelper

مساعدة العلامة المتقلبة
إذاً ما هو هذا الشيء؟
عندها ' أبسط ( و بدون إدماج HTMX | ) | يسمح لك بفعل هذا |.
<sortable-header column="@nameof(FakeDataModel.CompanyCity)"
current-order-by="@Model.OrderBy"
descending="@Model.Descending"
controller="Home"
use-htmx="false"
action="PageSortTagHelperNoHtmx"
>@Html.DisplayNameFor(x => x.Data.First().CompanyCity)
</sortable-header>
هنا يمكنكم أن تروا أن تحددوا اسم السطر , الاختبار للكتابة والمكان الذي يجب إرساله مرة أخرى ( شكراً JetBrains.لاحظات التي من بين أشياء كثيرة أخرى , التي أنا ' بالكاد مسحت سطح أعطي كاملاً للمسمات للتحكم والفعل | ).
هذا سينتج رابطاً سيظهر مرة أخرى إلى PageSortTagHelperNoHtmx العمل على Home مع اسم העמוד وترتيب الانتقاء الحالي وجميع العوامل الأخرى في URL (تحكم ب auto-append-querystring attribute. هذا يسمح لك ببساطة بالحصول على link useful postback .
private void AddQueryStringParameters(TagHelperOutput output, bool newDescending)
{
string? href = "";
// If Controller and Action are provided, generate URL dynamically
if (!string.IsNullOrEmpty(Controller) && !string.IsNullOrEmpty(Action))
{
href = Url.ActionLink(Action, Controller);
}
else if (output.Attributes.ContainsName("href")) // If href is manually set, use it
{
href = output.Attributes["href"].Value?.ToString() ?? "";
}
if(string.IsNullOrEmpty(href)) throw new ArgumentException("No href was provided or could be generated");
// If AutoAppend is false or href is still empty, don't modify anything
if (!AutoAppend && !string.IsNullOrWhiteSpace(href))
{
output.Attributes.RemoveAll("href");
output.Attributes.SetAttribute("href", href);
return;
}
// Parse the existing URL to append query parameters
var queryStringBuilder = QueryString.Empty
.Add("orderBy", Column)
.Add("descending", newDescending.ToString().ToLowerInvariant());
// Preserve existing query parameters from the current request
foreach (var key in ViewContext.HttpContext.Request.Query.Keys)
{
var keyLower = key.ToLowerInvariant();
if (keyLower != "orderby" && keyLower != "descending") // Avoid duplicating orderBy params
{
queryStringBuilder= queryStringBuilder.Add(key, ViewContext.HttpContext.Request.Query[key]!);
}
}
href+= queryStringBuilder.ToString();
// Remove old href and set the new one with the appended parameters
output.Attributes.RemoveAll("href");
output.Attributes.SetAttribute("href", href);
}
هذه هي الطريقة التي تضيف مبادئ سطر الاستفسار إلى URL. إنها' بسيطة جداًM SK2 تنتج URL بناء على Controller و Action الخصائص أو إذا كنت قد امست ' href attribute سوف يستخدم ذلك . إذا كنت قد امست AutoAppend للخطأ سيستخدم فقط href attribute as is (meanign you can roll your own for specific use
إختيار الجنون
لجعل هذا مفيداً قدر الإمكان مع / بدون HTMX. مع ♫/ بدون "Tailwind" ♪& DaisyUI وغيره أنا ♫ ' ♫ أعطيتكم مجموعة من الخصائص لإستخدامها لتنظيم هذا التحكم البسيط نسبياً
[HtmlAttributeName("hx-controller")]
[AspMvcController] // Enables IntelliSense for controller names
public string? HXController { get; set; }
[HtmlAttributeName("hx-action")]
[AspMvcAction] // Enables IntelliSense for action names
public string? HXAction { get; set; }
[HtmlAttributeName("action")]
[AspMvcAction]
public string? Action { get; set; }
[HtmlAttributeName("controller")]
[AspMvcController]
public string? Controller { get; set; }
[ViewContext]
[HtmlAttributeNotBound]
public ViewContext ViewContext { get; set; }
/// <summary>
/// The column to sort by
/// </summary>
[HtmlAttributeName("column")] public string Column { get; set; } = string.Empty;
/// <summary>
/// Whether to auto-append any query string parameters
/// </summary>
[HtmlAttributeName("auto-append-querystring")] public bool AutoAppend { get; set; } = true;
// <summary>
/// Whether to use htmx ; specifcally used to set hx-vals
/// </summary>
[HtmlAttributeName("use-htmx")] public bool UseHtmx { get; set; } = true;
/// <summary>
/// The currently set order by column
/// </summary>
[HtmlAttributeName("current-order-by")]
public string? CurrentOrderBy { get; set; }
/// <summary>
/// Sort direction, true for descending, false for ascending
/// </summary>
[HtmlAttributeName("descending")] public bool Descending { get; set; }
/// <summary>
/// CSS class for the chevron up icon
/// </summary>
[HtmlAttributeName("chevron-up-class")]
public string? ChevronUpClass { get; set; }
/// <summary>
/// CSS class for the chevron down icon
/// </summary>
[HtmlAttributeName("chevron-down-class")]
public string? ChevronDownClass { get; set; }
/// <summary>
/// The CSS class for the chevron when unsorted
/// </summary>
[HtmlAttributeName("chevron-unsorted-class")]
public string? ChevronUnsortedClass { get; set; }
/// <summary>
/// The CSS class to use for the tag.
/// </summary>
[HtmlAttributeName("tag-class")] public string? TagClass { get; set; }
يمكنكم أن تروا هنا لدي خصائص للكثير جداً كل شيء في التحكم (I' لن أمر عبرهم جميعاً هنا ينبغي أن يكونوا ذاتيين pretty
مع HTMX
الآن كما تعلمون ربما أنا 'أنا ناقل لـHTMX لذا كما هو الحال فإن هذا يدعم HTMX بشكل سلس
إنه يفشل في use-htmx صحيح الذي يملأ في hx-vals attribute. مع هذا أستخدم مساعدة ملصقات HTMX لجعل الشفرة بسيطة قدر الإمكان.
<sortable-header column="Name"
current-order-by="@Model.OrderBy"
descending="@Model.Descending"
hx-get
hx-route-pagesize="@Model.PageSize"
hx-route-page="@Model.Page"
hx-route-search="@Model.SearchTerm"
hx-controller="Home"
hx-action="PageSortTagHelper"
hx-indicator="#loading-modal"
hx-target="#list"
hx-push-url="true">@Html.DisplayNameFor(x => x.Data.First().Name)
</sortable-header>
حسناً هذا هو ما يحدث الأعمال مع HTMX سلاسة.
متحكم MVC
ثم أرسل هذا مرة أخرى إلى متحكم MVC بسيط الذي ينتج بعض بيانات العينة:
[Route("PageSortTagHelper")]
public async Task<IActionResult> PageSortTagHelper(string? search, int pageSize = 10, int page = 1, string? orderBy = "", bool descending = false)
{
var pagingModel = await SortResults(search, pageSize, page, orderBy, descending);
if (Request.IsHtmxBoosted() || Request.IsHtmx())
{
return PartialView("_PageSortTagHelper", pagingModel);
}
return View("PageSortTagHelper", pagingModel);
}
private async Task<OrderedPagingViewModel> SortResults(string? search, int pageSize, int page, string? orderBy, bool descending)
{
search = search?.Trim().ToLowerInvariant();
var fakeModel = await dataFakerService.GenerateData(1000);
var results = new List<FakeDataModel>();
if (!string.IsNullOrEmpty(search))
results = fakeModel.Where(x => x.Name.ToLowerInvariant().Contains(search)
|| x.Description.ToLowerInvariant().Contains(search) ||
x.CompanyAddress.ToLowerInvariant().Contains(search)
|| x.CompanyEmail.ToLowerInvariant().Contains(search)
|| x.CompanyCity.ToLowerInvariant().Contains(search)
|| x.CompanyCountry.ToLowerInvariant().Contains(search)
|| x.CompanyPhone.ToLowerInvariant().Contains(search)).ToList();
else
{
results = fakeModel.ToList();
}
if (!string.IsNullOrWhiteSpace(orderBy))
{
results = results.OrderByField(orderBy, descending).ToList();
}
var pagingModel = new OrderedPagingViewModel();
pagingModel.TotalItems = results.Count();
pagingModel.Page = page;
pagingModel.SearchTerm = search;
pagingModel.PageSize = pageSize;
pagingModel.Data = results.Skip((page - 1) * pageSize).Take(pageSize).ToList();
pagingModel.OrderBy = orderBy;
pagingModel.Descending = descending;
return pagingModel;
}
الـ OrderByField طريقة التوسع
أوه و لدي ميتود توسيع صغير مدمج الذي يطبق ساحة ترتيب تسمى على البيانات (or IQueryable وغيره). T|منهج التوسع بأكمله هو أسفلM SK2 يمكنكم أن تروا أنه يحتوي على MSC3 أساليب , واحدة ل أسماء السطرات المطبعة القوية , واحدة لأسماء السطر IQueryable و واحدة للأرقام IEnumerables
using System.Linq.Expressions;
using System.Reflection;
namespace mostlylucid.pagingtaghelper.Extensions;
public static class QueryableExtensions
{
public static IQueryable<T> OrderByField<T, TKey>(
this IQueryable<T> source,
Expression<Func<T, TKey>> keySelector,
bool descending = false)
{
return descending ? source.OrderByDescending(keySelector) : source.OrderBy(keySelector);
}
public static IQueryable<T> OrderByField<T>(
this IQueryable<T> source,
string sortBy,
bool descending = false)
{
if (string.IsNullOrWhiteSpace(sortBy))
return source; // No sorting applied
var property =
typeof(T).GetProperty(sortBy, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
if (property == null)
throw new ArgumentException($"Property '{sortBy}' not found on type '{typeof(T)}'.");
var param = Expression.Parameter(typeof(T), "x");
var propertyAccess = Expression.MakeMemberAccess(param, property);
var lambda = Expression.Lambda(propertyAccess, param);
var methodName = descending ? "OrderByDescending" : "OrderBy";
var resultExpression = Expression.Call(
typeof(Queryable),
methodName,
new[] { typeof(T), property.PropertyType },
source.Expression,
Expression.Quote(lambda)
);
return source.Provider.CreateQuery<T>(resultExpression);
}
public static IEnumerable<T> OrderByField<T>(
this IEnumerable<T> source,
string sortBy,
bool descending = false)
{
var property = typeof(T).GetProperty(sortPropertyName(sortBy), BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
if (property == null)
throw new ArgumentException($"Property '{sortBy}' not found on type '{typeof(T)}'.");
return descending
? source.OrderByDescending(x => property.GetValue(x, null))
: source.OrderBy(x => property.GetValue(x, null));
}
// Helper methods for readability (optional)
private static string sortPropertyName(string sortBy) => sortBy.Trim();
private static string methodName(bool descending) => descending ? "OrderByDescending" : "OrderBy";
}
في الختام
ذلك "ماسك0" هو حقا "ماسک1" "ماكس2" هو فقط شيء كنت أحتاجه لذا قمت ببناءه ووضعه في حزمة نوجات" ماسك3