Я хочу запустить метод javascript под названием makeFinalAdjustments()
, но это должно произойти после того, как страница завершит повторную отрисовку содержимого после события щелчка внутри этого компонента livewire:
//CHILD LIVEWIRE COMPONENT
//Child.blade.php
<div>
<div wire:click = "updateContent($id)">Click here</div>
<div>{{ $content }}</div>
....
</div>
//Child.php
public $content;
public $id;
public function updateContent()
{
$this->dispatch('updateContent');
}
//PARENT LIVEWIRE COMPONENT
//Parent.php
protected $listeners = [
'updateContent' => 'handleUpdateContent',
];
public function handleUpdateContent($child_id): void
{
$this->content[$child_id] = $this->getSomeContent($child_id);
}
//parent.blade.php
<div>
@foreach(child in list)
<livewire:child :content=content[child->id]>
@endforeach
...
</div>
Я попробовал добавить прослушиватель событий на основе документации здесь....
document.addEventListener('livewire:init', function () {
Livewire.on('updateContent', () => {
Livewire.hook('commit', ({ component, commit, respond, succeed, fail }) => {
succeed(({ snapshot, effect }) => {
queueMicrotask(() => {
makeFinalAdjustments();
})
})
})
});
});
...но это не работает, потому что makeFinalAdjustments()
срабатывает слишком рано, до того, как новый контент завершит рендеринг.
Проблема не совсем ясна, надо понять, что выполняется в функции makeFinalAdjustments().
В любом случае я попытался сымитировать ситуацию, реконструируя неполные части запроса.
Родительский класс
class ParentTest extends Component
{
public array $content = [];
public array $children = [];
protected $listeners = [
'updateContent' => 'handleUpdateContent',
];
public function mount() {
$this->children = [
(object)['id' => 1],
(object)['id' => 2],
(object)['id' => 3],
];
$this->content = [
1 => Str::random(),
2 => Str::random(),
3 => Str::random()
];
}
public function handleUpdateContent($child_id): void
{
// for this test we use a value of convenience
// $this->content[$child_id] = $this->getSomeContent($child_id);
$this->content[$child_id] = Str::random();
}
}
Родительский вид
<div>
@foreach($children as $child)
<livewire:child-test :content = "$content[$child->id]"
:id = "$child->id"
:key = "$child->id"
>
<br>
<hr>
<br>
@endforeach
</div>
Дочерний класс
namespace App\Livewire;
use Livewire\Attributes\Reactive;
use Livewire\Component;
class ChildTest extends Component
{
public $id;
#[Reactive]
public $content;
// --- since the event is now dispatched from the frontend this is no longer needed
//
// public function updateContent($id)
// {
// $this->dispatch('updateContent', child_id: $id);
// }
}
Детский вид
<div>
{{--<div wire:click = "updateContent({{ $id }})">--}}
<div wire:click = "$dispatch('updateContent', {child_id: {{ $id }} })"> {{-- <~~~ now the event is dispatched from the frontend --}}
[Click here]
</div>
<div x-init = "$watch('$wire.content', () => $nextTick(() => makeFinalAdjustments({{ $id }})))">
<span id = "content-{{ $id }}">
{{ $content }}
</span>
<span id = "revContent-{{ $id }}">
</span>
</div>
</div>
<script>
function makeFinalAdjustments(id)
{
const content = document.getElementById(`content-${id}`).textContent;
const revContent = content.split("").reverse().join("");
document.getElementById(`revContent-${id}`).textContent = revContent;
}
</script>
В родительском классе я эмулировал исходное содержимое общедоступных переменных, используя для содержимого несколько случайных строк.
В обработчике событий handleUpdateContent() я заменил getSomeContent() новой случайной строкой.
В родительском представлении я указал содержимое и параметры идентификатора, а также добавил уникальный ключ
Свойство $content дочернего класса имеет атрибут #[Reactive], поэтому изменение родительского класса отражается на связанном дочернем классе.
Я отправил событие дочернего компонента из представления, поэтому сохранил вызов бэкэнда, и дочерний метод updateContent() больше не нужен.
В дочернем представлении я добавил $watch для переменной $wire.content с помощью Alpine, поэтому при ее изменении в $nextTick вызывается функция makeFinalAdjustments().
функция makeFinalAdjustments() в этом тесте считывает содержимое из DOM и обновляет элемент revContent, используя обратную версию оригинала: как вы можете видеть, с помощью $nextTick функция makeFinalAdjustments() вызывается, когда обновление компонента завершается. сторона Livewire. Вы увидите, что Livewire восстанавливает все содержимое revContent как пустое, но затем содержимое revContent, связанное с нажатой кнопкой, заполняется.
Решением было добавление уникального ключа. Спасибо.