Tarkibga o'tish

07 β€” Actions: amallar va hodisalar

⬅️ Oldingi: 06 β€” Data binding Β· 🏠 Kitob boshi Β· Keyingi: 08 β€” Lifecycle ➑️

Bu bobda: foydalanuvchi biror narsa qilganda β€” tugmani bossa, formani yuborsa, klavishani bossa β€” serverdagi PHP metodini chaqirishni o'rganamiz. Bu Livewire'ning ikkinchi yarmi: oldingi bobda ma'lumotni komponentga bog'ladik (wire:model), endi esa o'sha ma'lumot ustida amal bajaramiz. wire:click, parametr uzatish, hodisa turlari, modifikatorlar, "sehrli" (magic) amallar va tasdiqlash oynasi β€” barchasi bitta bobda.


Action nima?

Avvalgi boblarda biz property (xususiyat) bilan tanishdik β€” bu komponentning xotirasi, ma'lumoti. Lekin ma'lumotning o'zi yetarli emas: foydalanuvchi u bilan biror ish qilishi kerak. Tugmani bosadi, formani to'ldirib yuboradi, ro'yxatdan bir elementni o'chiradi. Mana shu "ish bajarish" β€” action (amal) deyiladi.

Hayotiy o'xshatish β€” qo'ng'iroq tugmasi. Eshik oldidagi qo'ng'iroq tugmasini tasavvur qiling. Siz tugmani bosasiz (mijoz tomonida), lekin ovoz uy ichida chiqadi (server tomonida). Tugma β€” bu shunchaki signal yuboruvchi: asl ish boshqa joyda bajariladi. Livewire'da wire:click ham aynan shunday β€” siz brauzerda tugmani bosasiz, lekin metod serverda, PHP'da ishlaydi. Siz hech qanday JavaScript yozmaysiz: Livewire bosishni eshitadi, serverga signal yuboradi, server metodni bajaradi va natijani qaytaradi.

Texnik ta'rif bilan aytganda: action β€” foydalanuvchi hodisasiga (event) javoban komponentingizdagi public metodni chaqirish. Brauzer hodisani aniqlaydi β†’ Livewire serverga AJAX so'rov yuboradi β†’ server metodingizni ishga soladi β†’ komponent qayta render bo'ladi β†’ faqat o'zgargan qism (diff) brauzer DOM'iga qo'llanadi. Sahifa hech qachon to'liq qayta yuklanmaydi.

Action oqimi: tugma bosildi, wire:click serverga AJAX so'rov yuboradi, server metodni bajaradi va qayta render qiladi, faqat o'zgargan diff DOM'ga qo'llanadi

Eslab qoling: action β€” bu oddiy PHP metod. Hech qanday sehr yo'q. Siz public function increment() deb yozasiz, Blade'da wire:click="increment" deysiz β€” tamom. Metod ichida nima yozsangiz, bosilganda server o'sha ishni bajaradi.


wire:click β€” eng asosiy amal

Eng ko'p ishlatiladigan action β€” tugma bosish. Buning uchun wire:click atributiga metod nomini beramiz:

{{-- resources/views/components/⚑counter.blade.php --}}
<?php

use Livewire\Component;

new class extends Component
{
    public int $count = 0;

    public function increment(): void   // public bo'lishi SHART!
    {
        $this->count++;                 // hisobni bittaga oshiramiz
    }
};
?>

<div>
    <h1>Hisob: {{ $count }}</h1>
    <button wire:click="increment">+</button>
</div>

Bu yerda nima bo'ladi: foydalanuvchi + tugmasini bosadi β†’ Livewire serverga increment metodini chaqirishni so'raydi β†’ server $this->count ni 1 ga oshiradi β†’ komponent qayta render qilinadi β†’ ekrandagi raqam yangilanadi. Sahifa qayta yuklanmaydi.

Ehtiyot bo'ling β€” metod public bo'lsin

Livewire faqat public metodlarni frontend'dan chaqira oladi. Agar metodingiz private yoki protected bo'lsa, wire:click uni topa olmaydi va "method not found" xatosi chiqadi. Faqat tashqaridan chaqirilishi kerak bo'lgan metodlarni public qiling, ichki yordamchi metodlarni protected qoldiring.

Maslahat β€” qavs kerak emas (parametrsiz)

Parametrsiz metodni chaqirganda qavs yozmang: wire:click="increment", wire:click="increment()" emas. Ikkinchisi ham ishlaydi, lekin birinchisi toza va odatiy uslub.


Boshqa hodisalar: faqat bosish emas

Tugma bosish β€” eng keng tarqalgani, lekin foydalanuvchi boshqa ham ko'p narsa qiladi: forma yuboradi, klavishani bosadi, sichqonchani element ustiga olib boradi. Livewire'da deyarli har bir DOM hodisasini wire: bilan tinglash mumkin: wire:click, wire:submit, wire:keydown, wire:mouseenter va hokazo.

Turli wire hodisalari jadvali: click tugma bosish, submit forma yuborish, keydown klavisha, mouseenter sichqoncha, change tanlov o'zgardi, blur fokus ketdi

Mana eng ko'p ishlatiladigan hodisalar:

Hodisa Qachon ishlaydi Namuna
wire:click Element bosilganda <button wire:click="save">
wire:submit Forma yuborilganda (avtomatik preventDefault) <form wire:submit="save">
wire:keydown.enter Maydonda Enter bosilganda <input wire:keydown.enter="qidir">
wire:keydown.escape Esc bosilganda <input wire:keydown.escape="bekorQil">
wire:mouseenter Sichqoncha element ustiga kelganda <div wire:mouseenter="korsat">
wire:change Tanlov/qiymat o'zgarib bo'lganda <select wire:change="filtrla">
wire:blur Element fokusdan chiqqanda <input wire:blur="tekshir">

wire:submit β€” formalar uchun

Forma yuborishda alohida ahamiyat bor. Oddiy HTML formasi yuborilganda brauzer sahifani to'liq qayta yuklaydi β€” bu bizga kerak emas. Shuning uchun wire:submit avtomatik ravishda preventDefault qiladi: sahifa qayta yuklanmaydi, faqat metodingiz ishlaydi.

{{-- resources/views/components/⚑fikr-form.blade.php --}}
<?php

use Livewire\Component;

new class extends Component
{
    public string $fikr = '';
    public string $natija = '';

    public function save(): void
    {
        $this->natija = "Saqlandi: {$this->fikr}";
        $this->fikr = '';                 // maydonni tozalaymiz
    }
};
?>

<div>
    <form wire:submit="save">
        <input type="text" wire:model="fikr">
        <button type="submit">Yuborish</button>
    </form>

    <p>{{ $natija }}</p>
</div>

Bu yerda foydalanuvchi maydonni to'ldirib Enter bosadi yoki tugmani bosadi β†’ save metodi ishlaydi β†’ sahifa "sakramaydi". Forma uchun har doim wire:submit ishlating, wire:click ni tugmaga emas.

Klaviatura hodisalari

Klavisha bosilganda biror amal qilish uchun wire:keydown dan keyin klavisha nomini nuqta bilan qo'shamiz. Bu jonli qidiruv yoki tezkor amallar uchun juda qulay:

{{-- Enter bosilsa qidiradi, Esc bosilsa tozalaydi --}}
<input
    type="text"
    wire:model="qidiruv"
    wire:keydown.enter="qidir"
    wire:keydown.escape="$set('qidiruv', '')"
>

Ishlatish mumkin bo'lgan klavishalar: .enter, .escape, .tab, .space, .arrow-up, .arrow-down, .arrow-left, .arrow-right va boshqalar.


Parametr uzatish β€” metodga ma'lumot berish

Ko'pincha metod qaysi element bilan ishlashini bilishi kerak: qaysi postni o'chirish, qaysi filtrni qo'llash. Buning uchun metodga parametr uzatamiz β€” xuddi oddiy PHP funksiyasi kabi, qavs ichida:

{{-- resources/views/components/⚑postlar.blade.php --}}
<?php

use Livewire\Component;

new class extends Component
{
    public array $postlar = [
        ['id' => 1, 'sarlavha' => 'Birinchi post'],
        ['id' => 2, 'sarlavha' => 'Ikkinchi post'],
    ];

    public function delete(int $id): void
    {
        // berilgan id ga teng bo'lmaganlarini qoldiramiz
        $this->postlar = array_values(
            array_filter($this->postlar, fn ($p) => $p['id'] !== $id)
        );
    }
};
?>

<div>
    @foreach ($postlar as $post)
        <div wire:key="post-{{ $post['id'] }}">
            {{ $post['sarlavha'] }}
            <button wire:click="delete({{ $post['id'] }})">O'chir</button>
        </div>
    @endforeach
</div>

Bu yerda har bir tugma o'z postining id sini metodga uzatadi: wire:click="delete(1)", wire:click="delete(2)" va hokazo. Blade {{ $post['id'] }} ni render paytida raqamga aylantiradi.

String (matn) parametr uzatish uchun bir tirnoq ishlating:

{{-- filtrni o'rnatish: matn parametr bir tirnoq ichida --}}
<button wire:click="setFilter('active')">Faol</button>
<button wire:click="setFilter('done')">Bajarilgan</button>
<button wire:click="setFilter('all')">Hammasi</button>
public string $filter = 'all';

public function setFilter(string $name): void
{
    $this->filter = $name;          // 'active', 'done' yoki 'all'
}

Bir nechta parametr ham bemalol uzatiladi, vergul bilan ajratamiz:

<button wire:click="move({{ $task->id }}, 'done')">Bajarildi deb belgila</button>
public function move(int $id, string $status): void { /* ... */ }

Xavfsizlik β€” parametrlar mijozdan keladi, ishonmang!

wire:click="delete({{ $post->id }})" da id qiymati brauzerda turadi. Yomon niyatli foydalanuvchi brauzer konsolida o'zi xohlagan har qanday id bilan delete ni chaqirishi mumkin β€” masalan boshqa odamning postini o'chirishga urinishi. Shuning uchun metod ichida hech qachon parametrga ko'r-ko'rona ishonmang:

public function delete(int $id): void
{
    $post = Post::findOrFail($id);
    $this->authorize('delete', $post);   // bu foydalanuvchi o'chira oladimi?
    $post->delete();
}

Avtorizatsiya ($this->authorize(...)) bilan to'liq 23 β€” Xavfsizlik bobida tanishamiz. Hozircha qoidani eslab qoling: mijozdan kelgan har qanday ma'lumotni tekshiring va ruxsatni nazorat qiling.


Modifikatorlar β€” hodisani nozik sozlash

Hodisalarga modifikator qo'shib, ularning xulqini o'zgartirish mumkin. Modifikator β€” bu hodisa nomidan keyin nuqta bilan qo'shiladigan qo'shimcha buyruq. Mana eng foydalilari:

Modifikator Vazifasi
.prevent Brauzerning standart xatti-harakatini to'xtatadi (preventDefault)
.stop Hodisaning yuqoriga (ota elementga) tarqalishini to'xtatadi (stopPropagation)
.self Faqat aynan shu element bosilganda ishlaydi, bolasi emas
.debounce.300ms Foydalanuvchi to'xtaganidan 300ms keyin bir marta yuboradi
.throttle.500ms Har 500ms da ko'pi bilan bir marta yuboradi
.enter / .escape / .shift.enter Klaviatura: qaysi klavisha (yoki kombinatsiya) bosilganini cheklaydi

Bir nechta misol:

{{-- Havola: brauzer sahifani ochmasin, faqat metod ishlasin --}}
<a href="#" wire:click.prevent="open">Ochish</a>

{{-- Ota element ham wire:click ga ega bo'lsa, bola bosilganda ota ishlamasin --}}
<div wire:click="otaAmal">
    <button wire:click.stop="bolaAmal">Faqat men</button>
</div>

{{-- Faqat fon (overlay) bosilganda yopilsin, ichidagi modal bosilganda emas --}}
<div wire:click.self="close" class="overlay">
    <div class="modal">...</div>
</div>

Hayotiy o'xshatish β€” .debounce. Qidiruv maydonchasini tasavvur qiling. Agar har bir harf bosilganda serverga so'rov yuborsangiz, "olma" so'zi uchun 4 ta so'rov ketadi β€” bu isrof. .debounce.300ms foydalanuvchi yozishni to'xtatguncha kutadi va keyin bir marta yuboradi. Xuddi liftdagi tugma kabi: bir necha kishi bossa ham, lift bir marta keladi.

{{-- Tez-tez bosilishi mumkin bo'lgan tugmani jilovlash --}}
<button wire:click.debounce.500ms="refresh">Yangilash</button>

.shift.enter kabi kombinatsiyalar ham mumkin β€” masalan, chatda "Enter β€” yuborish, Shift+Enter β€” yangi qator":

<textarea wire:keydown.enter.prevent="send"></textarea>

Magic actions β€” yozmasdan ishlatiladigan amallar

Ba'zan oddiygina ishlar uchun (xususiyatni o'zgartirish, ochiq/yopiqni almashtirish) alohida metod yozish ortiqcha. Livewire bunday holatlar uchun magic actions ("sehrli amallar") beradi β€” bular $ belgisi bilan boshlanadigan, metod yozmasdan to'g'ridan-to'g'ri Blade'da ishlatiladigan tayyor amallar.

Magic actions ro'yxati: dollar set xususiyat o'rnatadi, dollar toggle almashtiradi, dollar refresh qayta render, dollar dispatch hodisa yuboradi, dollar parent ota metodi

Eng muhimlari:

$set('property', value) β€” xususiyatni o'rnatish

Metod yozmasdan bevosita biror xususiyatga qiymat beradi:

{{-- Hisobni nolga qaytarish β€” alohida reset() metodi shart emas --}}
<button wire:click="$set('count', 0)">Nollash</button>

{{-- Modal ochish --}}
<button wire:click="$set('modalOchiq', true)">Ochish</button>

$toggle('property') β€” almashtirish

Boolean (true/false) xususiyatni teskarisiga aylantiradi β€” ochiqni yopadi, yopiqni ochadi:

{{-- Menyuni ochish/yopish bitta tugma bilan --}}
<button wire:click="$toggle('showMenu')">Menyu</button>

@if ($showMenu)
    <nav>... menyu ...</nav>
@endif

$refresh β€” qayta render

Hech narsani o'zgartirmasdan komponentni qaytadan render qiladi (so'nggi holatni serverdan oladi):

<button wire:click="$refresh">Yangilash</button>

$dispatch('event') β€” hodisa yuborish

Boshqa komponentlarga yoki brauzerga hodisa (event) yuboradi. To'liq mexanizmni 18 β€” Events bobida o'rganamiz, hozircha shaklini ko'rib qo'ying:

<button wire:click="$dispatch('post-created')">E'lon qil</button>

$parent.metod() β€” ota komponent metodi

Ichma-ich (nested) komponentlarda bola komponentdan ota komponentning metodini chaqiradi. Bu mavzu 17 β€” Nested komponentlar bobida:

<button wire:click="$parent.removeTask({{ $id }})">O'chir</button>

Maslahat β€” qachon magic, qachon metod?

Bitta qatorlik oddiy o'zgarish bo'lsa ($set, $toggle) β€” magic action ishlating, kod toza bo'ladi. Lekin amal ichida validatsiya, avtorizatsiya, bir nechta qadam bo'lsa β€” albatta alohida public metod yozing. Mantiq metodda bo'lsa, uni testlash ham oson.


wire:confirm β€” amal oldidan tasdiqlash

Xavfli amallar (o'chirish, bekor qilish) oldidan foydalanuvchidan "Rostdan ham?" deb so'rash kerak. Livewire buni wire:confirm bilan bir qatorda hal qiladi β€” JavaScript yozish shart emas:

<button
    wire:click="delete({{ $post->id }})"
    wire:confirm="Rostdan o'chirilsinmi? Bu amalni qaytarib bo'lmaydi."
>
    O'chirish
</button>

Foydalanuvchi tugmani bosganda brauzer tasdiqlash oynasi chiqaradi. Agar "OK" bossa β€” delete metodi ishlaydi. "Bekor qilish" bossa β€” hech narsa bo'lmaydi, metod umuman chaqirilmaydi. Oddiy va ishonchli himoya qatlami.

Eslatma

wire:confirm faqat vizual ogohlantirish. Bu xavfsizlik chorasi emas! Yomon niyatli foydalanuvchi konsoldan oynani aylanib o'tib metodni baribir chaqira oladi. Shuning uchun haqiqiy himoya β€” metod ichidagi avtorizatsiya (23-bob). wire:confirm β€” bu tasodifiy bosishdan asraydigan qulaylik.


Loading bilan bog'liqlik

Action serverga borib qaytguncha qisqa vaqt o'tadi (tarmoq kechikishi). Shu vaqt ichida foydalanuvchiga "ishlayapman, kuting" deb ko'rsatish yaxshi tajriba hisoblanadi. Buning uchun wire:loading ishlatamiz β€” u so'rov davom etayotgan paytda ko'rinadi:

<button wire:click="save">
    Saqlash
</button>

{{-- Faqat so'rov ketayotganda ko'rinadi --}}
<span wire:loading>Saqlanmoqda...</span>

Bu yerda foydalanuvchi "Saqlash" ni bossa, server javob qaytarguncha "Saqlanmoqda..." matni ko'rinadi, keyin yo'qoladi. Loading holatlari (skeleton ekran, tugmani o'chirish, wire:target bilan aniq amalni belgilash) to'liq 20 β€” Loading va progress holatlari bobida ko'rib chiqiladi.


Xavfsizlik: har bir public metod ochiq eshik

Bu bobning eng muhim ogohlantirishi β€” uni hech qachon unutmang.

Xavfsizlik β€” har public metod frontend'dan chaqirilishi mumkin

Livewire komponentingizdagi HAR BIR public metod brauzerdan chaqirilishi mumkin β€” siz uni Blade'da wire:click ga qo'ymagan bo'lsangiz ham. Yomon niyatli foydalanuvchi brauzer konsolida $wire.deleteEverything() deb yozib, sizning maxfiy metodingizni ishga tushira oladi.

Bundan kelib chiqadigan qoidalar:

  1. Faqat tashqaridan chaqirilishi kerak bo'lgan metodlarnigina public qiling. Ichki yordamchi mantiqni protected yoki private qiling.
  2. Maxfiy yoki xavfli amalda avtorizatsiyani tekshiring: $this->authorize('update', $post);.
  3. Parametrlarga ishonmang β€” ular mijozdan keladi: validate, findOrFail, ruxsatni tekshirish.

To'liq xavfsizlik amaliyoti β€” #[Locked] xususiyatlar, policy va avtorizatsiya β€” 23 β€” Xavfsizlik bobida.


Hammasi birga β€” kichik amaliy komponent

Quyidagi komponent bu bobning asosiy g'oyalarini bitta joyda jamlaydi: oddiy action, parametrli action, magic action, va wire:confirm. Bu kod jonli Laravel 12 + Livewire 4.3 loyihada render qilinib (HTTP 200) va Livewire test API bilan tekshirilgan.

{{-- resources/views/components/⚑actions-demo.blade.php --}}
<?php

use Livewire\Component;

new class extends Component
{
    public int $count = 0;
    public bool $showMenu = false;
    public string $filter = 'all';
    public array $items = ['Olma', 'Anor', 'Banan'];

    public function increment(): void          // oddiy action
    {
        $this->count++;
    }

    public function setFilter(string $name): void   // parametrli action
    {
        $this->filter = $name;
    }

    public function delete(int $index): void        // parametrli action
    {
        unset($this->items[$index]);
        $this->items = array_values($this->items);  // kalitlarni qayta tartiblash
    }
};
?>

<div>
    <h1>Hisob: {{ $count }}</h1>
    <button wire:click="increment">+</button>
    <button wire:click="$set('count', 0)">Nollash</button>   {{-- magic --}}
    <button wire:click="$toggle('showMenu')">Menyu</button>  {{-- magic --}}

    @if ($showMenu)
        <p>Menyu ochiq</p>
    @endif

    <p>Filtr: {{ $filter }}</p>
    <button wire:click="setFilter('active')">Faol</button>
    <button wire:click="setFilter('all')">Hammasi</button>

    <ul>
        @foreach ($items as $i => $item)
            <li wire:key="item-{{ $i }}">
                {{ $item }}
                <button
                    wire:click="delete({{ $i }})"
                    wire:confirm="Rostdan o'chirilsinmi?"
                >O'chir</button>
            </li>
        @endforeach
    </ul>
</div>

Tekshirib ko'ring

Bu komponentni o'z loyihangizda yarating (php artisan make:livewire actions-demo), routes/web.php ga Route::livewire('/actions-demo', 'actions-demo'); qo'shing va /actions-demo manzilini brauzerda oching. + ni bosing, "Menyu" ni bosib menyuni ochib-yoping, "Faol" tugmasini bosing va filtr matni o'zgarishini kuzating, "O'chir" ni bosib tasdiqlash oynasini ko'ring.


Xulosa

  • Action β€” foydalanuvchi hodisasiga javoban serverdagi public metodni chaqirish. Qo'ng'iroq tugmasi kabi: bosish mijozda, ish serverda.
  • Eng asosiysi β€” wire:click="metodNomi". Metod komponentda public bo'lishi shart.
  • Boshqa hodisalar: wire:submit (forma β€” avtomatik preventDefault), wire:keydown.enter/.escape, wire:mouseenter, wire:change, wire:blur.
  • Parametr uzatish: wire:click="delete({{ $post->id }})" (raqam), wire:click="setFilter('active')" (matn, bir tirnoqda), bir nechta parametr vergul bilan.
  • Modifikatorlar: .prevent, .stop, .self, .debounce.300ms, .throttle, klaviatura modifikatorlari (.enter, .escape, .shift.enter).
  • Magic actions metod yozmasdan ishlatiladi: $set('open', true), $toggle('open'), $refresh, $dispatch('event'), $parent.metod().
  • wire:confirm="..." β€” xavfli amal oldidan tasdiqlash oynasi (vizual himoya, xavfsizlik chorasi emas).
  • wire:loading β€” so'rov davomida "kuting" ko'rsatadi (20-bob).
  • ⚠️ Eng muhimi: har bir public metod frontend'dan chaqirilishi mumkin. Maxfiy/xavfli amalda avtorizatsiya shart ($this->authorize(...), 23-bob), parametrlarga ishonmang.

Amaliy mashqlar

  1. Toggle menyu (oson). showMenu nomli bool xususiyat va bitta tugma yarating. Tugma bosilganda menyu ochilib-yopilsin. Avval alohida toggleMenu() metodi bilan yozing, keyin uni wire:click="$toggle('showMenu')" magic action bilan almashtirib, kodingiz qisqarganini ko'ring.

  2. Filtr tugmalari (oson–o'rta). filter nomli xususiyat va uchta tugma yarating: "Hammasi", "Faol", "Bajarilgan". Har biri setFilter('all'), setFilter('active'), setFilter('done') ni chaqirsin. Joriy tanlangan filtr nomini ekranda ko'rsating. Yo'naltirish: metodga string parametr bir tirnoq ichida uzatiladi.

  3. wire:confirm bilan o'chirish (o'rta). Matnlardan iborat massiv ($items) va har bir element yonida "O'chir" tugmasini ro'yxatda chiqaring. Tugmaga wire:confirm qo'shing β€” foydalanuvchi tasdiqlamaguncha element o'chmasin. Yo'naltirish: wire:key ni unutmang va delete($index) ga to'g'ri indeksni uzating; o'chirgandan keyin array_values() bilan kalitlarni qayta tartiblang.

  4. Klaviatura bilan qidiruv (o'rta–qiyin). Matn maydoni yarating. Enter bosilganda qidir metodi ishlasin, Esc bosilganda maydon $set magic action bilan tozalansin. Yo'naltirish: wire:keydown.enter va wire:keydown.escape.

  5. Himoyalangan o'chirish (qiyin β€” fikrlash uchun). 3-mashqdagi o'chirish metodini xavfsizroq qiling: agar elementlar soni 1 ta bo'lsa, oxirgisini o'chirishga ruxsat bermang (metod ichida tekshiring va hech narsa qilmasdan qaytib chiqing). Nima uchun bu tekshiruvni server metodida qilish kerak, wire:confirm da emas? (Maslahat: bu bobning xavfsizlik bo'limini qayta o'qing.)


⬅️ Oldingi: 06 β€” Data binding Β· 🏠 Kitob boshi Β· Keyingi: 08 β€” Lifecycle ➑️