پرش به مطلب اصلی

Table

این کامپوننت‌های جدول (x-table, x-table-header, x-table-column) مبتنی بر Laravel Livewire طراحی شده‌اند و برای نمایش داده‌های جدولی با امکانات پیشرفته در صفحات Blade به کار می‌روند. با استفاده از Livewire، قابلیت‌هایی مانند مرتب‌سازی، جستجو و صفحه‌بندی به صورت تعاملی و بدون نیاز به رفرش صفحه فراهم می‌شود.


ویژگی‌ها

  • پشتیبانی از صفحه‌بندی (pagination) و تعیین تعداد آیتم در هر صفحه (perPage)
  • امکان مرتب‌سازی (sort) بر اساس هر ستون (با تعیین sortable)
  • قابلیت جستجو در ستون‌های مشخص (با تعیین searchable)
  • پشتیبانی از ادغام ستون‌ها (merge) و نمایش چندین مقدار در یک سلول
  • امکان نمایش بج (Badge) برای مقادیر خاص هر ستون (با badgeMap)
  • امکان فعالسازی چک باکس برای هر سطر از جدول و دریافت مقادیر انتخاب شده
  • شخصی‌سازی کلاس CSS برای هدر و بدنه هر ستون
  • قابلیت تعیین اسلات سفارشی برای هدر جدول
  • امکان پردازش و تغییر داده‌های هر ردیف با استفاده از Closure (modifierClosure)
  • کاملاً واکنش‌گرا و قابل استفاده در هر جای قالب Blade

ورودی‌های کامپوننت

x-table

نام پراپنوع دادهمقدار پیش‌فرضتوضیحات
idstringاجباریشناسه یکتا برای جدول
dataSourcecallable | stringاجباریمنبع داده جدول؛ می‌تواند نام کلاس مدل، کوئری SQL یا Closure/کالبل بازگرداننده Query Builder باشد
dataSourceCallbackClosure | stringnullتابع تکمیلی برای سفارشی‌سازی Query Builder (امضای function (Builder $query, array $parameters): Builder)
perPageint5تعداد آیتم در هر صفحه
containerClassstringnullکلاس CSS اضافی برای ظرف جدول
headerSlotstringnullاسلات سفارشی برای هدر جدول
defaultSortFieldstringnullنام ستون پیش‌فرض برای مرتب‌سازی
defaultSortDirectionstringnullجهت پیش‌فرض مرتب‌سازی (asc یا desc)
modifierClosureClosurenullتابع پردازش هر ردیف (باید دقیقا یک آرایه بگیرد و آرایه برگرداند)
parametersarray[]مقادیر ورودی برای فیلتر کردن داده‌ها که به dataSourceCallback و متدهای کمکی jQuery پاس داده می‌شود
showRecordCountbooleanfalseنمایش تعداد کل رکوردها در پایین جدول
showIndexbooleanfalseنمایش شمارنده ردیف در ابتدای هر سطر
selectablebooleanfalseفعال شدن حالت چک باکسی برای جدول
selectionFieldstringnullنام فیلدی که در مقادیر آن به عنوان مقدار چک باکس هر سطر انتخاب می‌شود
selectedValuesarray[]آرایه‌ای از مقادیر انتخاب‌شده از selectionField که در لود اولیه چک شده باشند
selectionFilterComponentstringnullسلکتور المان مورد نظر برای فیلتر کردن موارد انتخاب شده (switch-input)
alignstringnullجهت چیدمان کلی جدول (left, right, center)

x-table-header

نام پراپنوع دادهمقدار پیش‌فرضتوضیحات
rowSpanint1تعداد ردیف‌هایی که هدر ادغام می‌شود
colSpanint1تعداد ستون‌هایی که هدر ادغام می‌شود
levelint1سطح هدر (برای هدرهای چندسطحی)
labelstring''عنوان هدر
namestringnullنام ستون (برای مرتب‌سازی)
sortColumnstringnullنام ستون برای مرتب‌سازی
classstring''کلاس CSS برای هدر
widthstringnullعرض ستون

x-table-column

نام پراپنوع دادهمقدار پیش‌فرضتوضیحات
namestringاجبارینام کلید داده (برای مقداردهی سلول)
labelstringاجباریعنوان ستون
searchableboolfalseفعال‌سازی جستجو در این ستون
sortableboolfalseفعال‌سازی مرتب‌سازی این ستون
headerClassstring''کلاس CSS برای هدر
headerTooltipstring''تولتیپ برای هدر
bodyClassstring''کلاس CSS برای سلول
bodyTooltipstring''تولتیپ برای سلول
widthstringnullعرض ستون
badgeMaparray[]نگاشت مقادیر به بج (badge) برای نمایش مقدار خاص با رنگ و متن سفارشی
theadSeparatorstring''جداکننده برای هدر در حالت ادغام
tbodySeparatorstring''جداکننده برای بدنه در حالت ادغام
mergeWithstring''نام ستون‌هایی که باید با این ستون ادغام شوند (با کاما جدا شود)
mergeOrientationstring'horizontal'جهت چیدمان هدر و بدنه برای ستون‌های ادغام شده (horizontal, vertical)
alignstringnullجهت چیدمان ستون (left, right, center)
slotstring''اسلات سفارشی برای نمایش مقدار سلول (با پشتیبانی از جایگزینی متغیرها)
groupBreakLineboolfalseآیا ستون های ادغام شده در خط جدید نمایش داده شوند؟ اگر true باشد، ستون های ادغام شده در خط جدید نمایش داده می‌شوند. این مورد بر روی نحوه نمایش ستون ها در جدول تاثیر گذار است. ستونی که این مورد را دارد، باعث میشود ستون های بعدی در خط بعد نمایش داده شوند.
groupBreakLineSectionstringnullدر صورتی که میخواهید قابلیت groupBreakLine فقط در header یا body اعمال شود یکی از این دو مقدار را برای آن آن تعیین کنید

پراپ های align , theadSeparator , tbodySeparator با کلیدهای thead-separator , tbody-separator و align در فایل config قابل تنظیم میباشند.


نکات مهم
  • در صورتی که از dropdown-item به همراه confirmation=true استفاده میکنید نیاز است برای کامپوننت dropdown-item اتریبیوت confirmation-id که یک مقدار یکتا(مثلا آیدی سطر)است قرار گیرد.
  • پراپ modifierClosure باید یک Closure با دقیقا یک پارامتر (آرایه) و خروجی آرایه باشد. در غیر این صورت خطا رخ می‌دهد.
  • اگر منبع داده Query Builder یا Eloquent باشد، به صورت خودکار SQL با Bindings استخراج می‌شود.
  • برای ادغام ستون‌ها، پراپ mergeWith را با نام ستون‌های هدف (جداشده با کاما) مقداردهی کنید.
  • برای نمایش بج، پراپ badgeMap را به صورت آرایه‌ای از مقدار به آرایه‌ای شامل text، variant و appearance مقداردهی کنید.
  • اگر پراپ slot مقداردهی شود، مقدار سلول با جایگزینی متغیرهای $row[key] رندر می‌شود.
  • امکان تغییر align ملی جدول از طریق کانفیگ برای کامپوننت table وجود دارد
فیلتر / جستجو در جدول با استفاده از کامپوننت‌های فرم

برای استفاده از این قابلیت باید اتریبیوت data-table-target را به فرم بدهید تا جدول مورد نظر برای جستجو را بشناسد

<form
id="table-admins-sample-search"
class="row g-4 mb-10"
data-table-target="table-admins-sample"
action="{{ route('admin.samples.banks.store') }}"
method="post"
>
<x-text-input containerClass="col-md-6" name="first_name" label="نام" />

<x-text-input containerClass="col-md-6" name="last_name" label="نام خانوادگی" />

<x-select
containerClass="col-md-6"
name="job_title"
:items="[['id' => 'Web Developer', 'name' => 'Web Developer']]"
/>

<x-button containerClass="text-end" title="جستجو" button-type="submit" />
</form>

<x-table id="table-admins-sample" :data-source="App\Models\Admin::class" :per-page="5">
<x-table.column name="id" label="شناسه" :sortable="true" />

<x-table.column name="first_name" label="نام" searchable />

<x-table.column name="last_name" label="نام خانوادگی" searchable />

<x-table.column name="mobile" label="شماره موبایل" />

<x-table.column name="job_title" label="عنوان" searchable />
</x-table>

در خصوص فیلدهایی که نیاز به OR برای جستجو دارند می‌توانید با کاما نام فیلد را جداسازی کنید. به عنوان مثال اگر نیاز هست که اینپوتی عمل جستجو را روی دو فیلد نام و نام خانوادگی انجام دهد، می‌توانید مشابه زیر عمل کنید

<x-text-input containerClass="col-md-6" name="first_name,last_name" label="نام" />
تغییر operator در component های فیلتر

اگر می خواهید برای یک ستون خاص مقدار operator فیلتر مربوط به آن ستون را از مقدار پیش فرض که like می باشد به مقدار دیگری مانند = تغییر دهید باید از ویژگی data-table-filter-operator استفاده کنید مانند مثال زیر :

<x-select
containerClass="col-md-6"
id="product_name"
name="product_id"
data-table-filter-operator="="
:label="محصولات"
:items="$products"
/>
تغییر تعداد آیتم‌های نمایشی در هر صفحه

برای استفاده از این قابلیت باید اتریبیوت data-table-target را به کامپوننت سلکت بدهید تا جدول مورد نظر برای جستجو را بشناسد

<x-select
name="perPage"
data-table-target="table-admins-sample"
:clearable="false"
:items="[
['id' => 5, 'name' => 5, 'value' => 5, 'selected' => true],
['id' => 10, 'name' => 10, 'value' => 10, 'selected' => false],
['id' => 25, 'name' => 25, 'value' => 25, 'selected' => false],
['id' => 50, 'name' => 50, 'value' => 50, 'selected' => false],
]"
/>
<x-table id="table-admins-sample" :data-source="App\Models\Admin::class">
<x-table.column name="id" label="شناسه" :sortable="true" />

<x-table.column name="first_name" label="نام" searchable />

<x-table.column name="last_name" label="نام خانوادگی" searchable />

<x-table.column name="mobile" label="شماره موبایل" />

<x-table.column name="job_title" label="عنوان" searchable />
</x-table>

به روزرسانی پارامترهای Query Builder

متدهای کمکی jQuery برای جدول‌های Livewire

  • refreshComponent(resetParams = true): کامپوننت Livewire مرتبط با جدول را بر اساس wire:id پیدا می‌کند. در حالت پیش‌فرض، ابتدا پراپ parameters را ریست می‌کند و سپس جدول را دوباره بارگذاری می‌کند. اگر مقدار false ارسال شود، تنها $refresh() اجرا می‌شود و پارامترهای فعلی حفظ می‌شوند.
  • setComponentParams(params): پارامترهای فعلی جدول را دریافت می‌کند، با آرگومان جدید ادغام می‌کند و نتیجه را روی پراپ parameters تنظیم می‌کند. در صورت نبودن wire:id یا کامپوننت مرتبط، پیام خطا در کنسول توسعه‌دهنده (devConsoleLog) ثبت می‌شود.
// بروزرسانی پارامترها و رفرش جدول
$("#table-1").setComponentParams({
min_id: 40,
max_id: 70,
});

$("#table-1").refreshComponent(false);

نمونه کامل استفاده

@php
$modifierClosure = function (array $row): array {
$row['created_at'] = verta($row['created_at'])->formatJalaliDatetime();
return $row;
};
@endphp

@php
$dataSourceCallback = function (
\Illuminate\Database\Eloquent\Builder $queryBuilder,
array $parameters,
): \Illuminate\Database\Eloquent\Builder {
$minId = $parameters['min_id'] ?? 50;
$maxId = $parameters['max_id'] ?? 60;

return $queryBuilder
->where('id', '>', $minId)
->where('id', '<=', $maxId);
};
@endphp
<x-table
container-class="mb-10"
:show-record-count="true"
id="table-1"
:data-source="\App\Models\Admin::class"
:data-source-callback="$dataSourceCallback"
:modifier-closure="$modifierClosure"
:parameters="['min_id' => 20]"
>
...
</x-table>
$("#table-1").setComponentParams({
max_id: 70,
});

$("#table-1").refreshComponent();

فعال‌سازی حالت انتخابی (Selectable) با چک‌باکس در جدول

قابلیت انتخاب سطرهای جدول با چک‌باکس، با اضافه شدن چند پراپ جدید به کامپوننت x-table فراهم شده است. با فعال‌سازی این حالت، برای هر سطر جدول یک چک‌باکس نمایش داده می‌شود و می‌توانید مقادیر انتخاب‌شده را کنترل کنید.

پراپ‌های جدید برای انتخاب سطری:

  • selectable: اگر true باشد، حالت انتخابی با چک‌باکس برای جدول فعال می‌شود.
  • selectionField (الزامی) : نام فیلدی که مقدار آن به عنوان مقدار چک‌باکس هر سطر شناخته می‌شود (معمولا id سطر).
  • selectedValues: آرایه‌ای از مقادیری که در هنگام لود، انتخاب شده باشند (مقادیر این فیلد مطابق با selectionField است).
  • selectionFilterComponent: سلکتور عنصری که با تغییر آن، تنها سطرهای انتخاب شده نمایش داده می‌شوند (کامپوننت switch-input).

با فعال‌سازی و تنظیم این پراپ‌ها، جدول به‌طور خودکار دارای چک‌باکس انتخاب برای هر سطر می‌شود.

متدهای jQuery در کامپوننت جدول برای مدیریت انتخاب‌ها

پس از ایجاد جدول، می‌توانید به این متدهای کمکی روی instance کامپوننت دسترسی داشته باشید:

  • getCurrentSelectedValues():
    آرایه فعلی از مقادیر انتخاب‌شده (با در نظر گرفتن تغییرات کاربر نسبت به مقدار اولیه) را برمی‌گرداند.

    $("#table-1").getInstance().getCurrentSelectedValues();
  • getAddedValues():
    فقط مقادیر جدیدی که کاربر نسبت به مقدار اولیه اضافه کرده است را برمی‌گرداند.

    $("#table-1").getInstance().getAddedValues();
  • getRemovedValues():
    فقط مقادیری که کاربر نسبت به مقدار اولیه حذف کرده است را برمی‌گرداند.

    $("#table-1").getInstance().getRemovedValues();
  • getChangedValues():
    هر آنچه نسبت به مقدار اولیه تغییر کرده در قالب یک آبجکت برمی‌گرداند.

    $("#table-1").getInstance().getChangedValues();
    // خروجی:
    // { added: [...], removed: [...] }

این متدها به شما کمک می‌کنند مقادیر انتخاب‌شده جاری یا تغییر یافته را در هر نقطه از برنامه دریافت و مدیریت نمایید.

همچنین، شما می‌توانید با استفاده از event اختصاصی table:changed بر روی جدول، از تغییرات انتخاب سطرها مطلع شوید و هر عملیات دلخواهی انجام دهید. این رویداد هر بار که مقدار انتخاب‌شده یک چک‌باکس تغییر کند، بر روی جدول trigger می‌شود و داده‌هایی مانند مقدار سطر و وضعیت تیک (انتخاب/عدم انتخاب) را ارسال می‌کند.

نمونه استفاده:

$("#table-1").on("table:changed", function (e, data) {
// data.value: مقدار فیلد (مثلاً id سطر)
// data.checked: وضعیت تیک زدن (true/false)
// اینجا می‌توانید به‌صورت لحظه‌ای انتخاب‌ها را پردازش کنید
console.log("selected value:", data.value, "checked:", data.checked);
});
مقداردهی با JS

در صورت نیاز به انتخاب/عدم انتخاب سطرهای جدول می‌توانید از متد زیر استفاده کنید

$("#table-1").getInstance().setValue(["14", "11"]);

مثال‌ها

جدول نمایشی

نمونه پایه

<x-table container-class="mb-10" id="table-2" :data-source="App\Models\Bank::class" :per-page="5">
<x-table.column
name="code"
label="کد"
:sortable="true"
mergeWith="name,website"
theadSeparator="/"
tbodySeparator="|"
/>

<x-table.column name="name" label="نام" :searchable="true" :sortable="true" />

<x-table.column name="website" label="وبسایت" />

<x-table.column name="iban_url" label="لینک استعلام شماره شبا" />

<x-table.column name="sort" label="ترتیب" :sortable="true">
$row[sort]

<div condition="$row[sort] === 1">
<x-badge variant="success" value="اولین بانک" size="xs" />
</div>
</x-table.column>
</x-table>

جدول پیشرفته با امکان انتخاب / فیلتر / جستجو و نمایش موارد انتخاب شده در مودال

<div class="mb-5">
<x-button
title="نمونه ادغام"
data-bs-target="#advanced-table-example-modal"
data-bs-toggle="modal"
/>

<x-modal
title="نمونه ادغام"
size="xl"
id="advanced-table-example-modal"
:closable="false"
>
<x-slot:title_badges>
<x-badge
value="در حال بررسی"
variant="info"
appearance="light"
/>
</x-slot:title_badges>

<x-slot:header_bottom>
این مودال برای <b>
<a href="#">
ادغام یا ترکیب
</a>
</b> کاربران طراحی شده است.
</x-slot>

@php
$modifierClosure = function (array $row): array {
$row['created_at'] = verta($row['created_at'])->formatJalaliDatetime();
return $row;
};
@endphp

<form
id="advanced-concat-table-search"
class="row g-4 mb-10"
data-table-target="advanced-concat-table"
>
<x-text-input
containerClass="col-md-4"
name="first_name"
label="نام"
/>
<x-text-input
containerClass="col-md-4"
name="last_name"
label="نام خانوادگی"
/>
<x-text-input
containerClass="col-md-4"
label="شناسه"
name="id"
/>

<x-button
containerClass="text-end"
title="جستجو"
button-type="submit"
/>
</form>

<div class="mb-3 d-flex justify-content-end align-items-center gap-5">
<x-switch-input
id="filter-selected-items"
name="show-selected"
label="نمایش موارد انتخاب شده"
orientation="horizontal"
/>
<x-search-input
target-id="advanced-concat-table"
mode="livewire"
/>
</div>

<x-table
id="advanced-concat-table"
:show-record-count="true"
:data-source="\Dornica\AccessHub\Authentication\Models\User::class"
:modifier-closure="$modifierClosure"
:selectable="true"
:selected-values="['1', '3']"
selection-field="id"
selection-filter-component="#filter-selected-items"
>

<x-table.column
name="id"
label="شناسه"
:sortable="true"
>
<a
href="/"
target="_blank"
>
$row[id]
</a>
</x-table.column>

<x-table.column
name="first_name"
label="نام"
:searchable="true"
:sortable="true"
mergeWith="last_name"
bodyClass="d-flex align-items-center gap-2 justify-content-center"
theadSeparator="/"
>
</x-table.column>

<x-table.column
name="last_name"
label="نام خانوادگی"
:sortable="true"
:searchable="true"
/>

<x-table.column
name="created_at"
label="تاریخ ثبت نام"
bodyClass="dir-ltr"
/>
</x-table>

<x-slot:footer>
<x-button
variant="primary"
appearance="light"
title="دریافت تغییرات"
id="get-table-changes"
/>

<x-button
variant="info"
appearance="light"
title="دریافت موارد انتخاب شده"
id="get-table-selected"
/>

<x-button
variant="success"
appearance="light"
title="دریافت موارد اضافه شده"
id="get-table-added"
/>

<x-button
variant="danger"
appearance="light"
title="دریافت موارد حذف شده"
id="get-table-removed"
/>
</x-slot>
</x-modal>
</div>

@push('scripts')
<script>
const instance = $("#advanced-concat-table").getInstance()

$("#get-table-changes").on("click", () => {
console.log(instance.getChangedValues())
})
$("#get-table-selected").on("click", () => {
console.log(instance.getCurrentSelectedValues())
})
$("#get-table-added").on("click", () => {
console.log(instance.getAddedValues())
})
$("#get-table-removed").on("click", () => {
console.log(instance.getRemovedValues())
})
</script>
@endpush