This is a viewer only at the moment see the article on how this works.
To update the preview hit Ctrl-Alt-R (or ⌘-Alt-R on Mac) or Enter to refresh. The Save icon lets you save the markdown file to disk
This is a preview from the server running through my markdig pipeline
لذا أثناء بناء مشروع بنيت أصلاً مُنْفِض مُنْفِف لـ أنا أيضاً أُراقبُ أيضاً خلال حاجة أخرى. طريقة لبناء خاصية الفرز بسهولة لجدول النتائج مع دعم HtMX.
إذاً... أقدم لكِ عنوان بطاقة (فليبي) المساعدة. هذه مجرد مقالة سريعة مع الكثير من الشفرة يمكنك أن ترى دائماً المعاينة هنا/ / / / والرمز المصدري كما هو دائماً هو هنا.
أنا في غاية الفظاعة أمثلة بناء (إنها عبارة عن عبارة (slog init)) لكنني سأحاول إضافة المزيد والمزيد كلما مضيت قدماً. إلى تثبيت:
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>
يمكنك أن ترى هنا أنك تحدد اسم العمود، اختبار الترويج، و المكان الذي يجب أن تُسند إليه (شكراً إلى 2 - البيانات الصادرة عن الهيئات الحكومية الدولية من بين العديد من الأشياء الأخرى، التي بالكاد خدشتها على سطح إعطاء المعلوماتية لأسماء المراقب المالي و Action.
هذا سيولّد رابطاً سيرجع إلى PageSortTagHelperNoHtmx
اللجنة الدائمة Home
متحكم مع اسم العمود واسم العمود والترتيب الحالي للنوع الترتيب وأي بارامترات أخرى في الواجهة (مراقب مع الـ auto-append-querystring
........... ،.............................................................................................................. هذا سوف يحصل بسهولة على وصلة خلفية مفيدة ، سوف ترونها في الأسفل ، لقد جعلتها مرنة جداً حيث يمكنك تحديد href/ action & controller و الحصول على وصلة إلى الخلف مع معاملات الإقتراح المُرفقة.
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);
}
هذه هي الطريقة التي تُذيّل مُؤَمِّرات الإشارَة إلى العنوان. إنها بسيطة جداً، إنها تولد عنواناً مبنياً على Controller
وقد عقد مؤتمراً بشأن Action
أو إذا كنت قد وضعت href
واصفتها أنها ستستخدم ذلك. إذا كنت قد وضعت AutoAppend
إلى زوال سيستخدم فقط href
صفة هو (معنى أنك يمكن أن لفة الخاصة بك لاستخدام حالات محددة).
لجعل هذا مفيد بقدر الإمكان مع/بدون HTMX. مع / بدون Tayilwind & DizeUI وما إلى ذلك لقد أعطيتك مجموعة من الخصائص لتستخدمها لضبط هذه السيطرة البسيطة نسبياً
[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; }
يمكنكم أن تروا هنا أن لدي خصائص لكل شيء في السيطرة (لن أمر بها جميعاً هنا يجب أن تكون تفسيرية ذاتية جداً).
الآن كما قد تكون تعلمت أنا HTMX NUT لذا كالمعتاد هذا يدعم HTMX بشكل سلس جداً:
يُؤكّد إلى: use-htmx
الحقيقية التي تملأ في hx-vals
........... ،.............................................................................................................. مع هذا أنا استخدم مسهلات دعم و لجعل الرمز بسيطاً قدر الإمكان
<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 المراقب المالي الذي يولد بعض البيانات العينة:
[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
ألف مُنْت مُنْ مُنْ مُنْ مُنْ مُنْ مُنْ مُنْ مُنْ مُنْ مُنْمْتِلْمْ مِلْمِمْ مِنْ مِلْمِتْلِمْتِم مِلْمِلْتِمولدي طريقة تمديد صغيرة معبأة فيها تطبق حقل طلبية مسمّى على البيانات (أو) IQueryable
وما إلى ذلك). وترد أدناه طريقة امتداد Tushhe Comple traditional orther. يمكنك أن ترى أن هذا له 3 طرق، واحد لأسماء الأعمدة المُحَبَّبة القوية، واحد لأسماء الأعمدة المتميِّزة، وواحد لأسماء الأعمدة المتسلسلة القابلة للقياس، وواحد لـ IEncommensions.
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";
}
هذا هو في الواقع عليه. إنه مجرد شيء كنت أحتاجه لذا بنيته وعلقته في حزمة النواة