Почему в элементеchartjs приложения livewire теряются свойства холста при обновлении данных?

В приложении laravel 10 / livewire 3 я создаю отчетchartjs на основе данных из базы данных и 4 фильтров. У меня все работает с блейд-файлом:

    <div class = "editor_field_block_wrapper">
        <div class = "editor_field_block_device_splitter">
            <div class = "w-4/12 pb-0 pl-2 md:pt-3 ">
                <label for = "filterModelType" class = "editor_field_block_device_label">Model type: <span
                        class = "editor_form_aria_required" aria-required = "true"> * </span></label>
            </div>
            <div class = "p-2 w-full">
                <select wire:model.blur = "filterModelType" class = "editor_form_input" tabindex = "20"
                        id = "filterModelType">
                    <option value = ""> - Select all -</option>
                    @foreach($modelTypeSelectionItems as $key=>$label)
                    <option value = "{{$key}}">{{$label}}</option>
                    @endforeach
                </select>
                @error('filterModelType')
                <span class = "error_text">{{$message}}</span>
                @enderror
            </div>
        </div>
    </div>

    <div class = "editor_field_block_wrapper">
        <div class = "editor_field_block_device_splitter">
            <div class = "w-4/12 pb-0 pl-2 md:pt-3 ">
                <label for = "filterDateFrom" class = "editor_field_block_device_label">From date</label>
            </div>
            <div class = "p-2 w-full">
                <x-inputs.datepicker id = "filterDateFrom" wire:model.lazy = "filterDateFrom" tabindex = "20"/>
                @error('filterDateFrom') <span
                    class = "editor_form_validation_error">{{ $message }}</span> @enderror
            </div>
        </div>
    </div>

    <div class = "editor_field_block_wrapper">
        <div class = "editor_field_block_device_splitter">
            <div class = "w-4/12 pb-0 pl-2 md:pt-3 ">
                <label for = "filterDateTill" class = "editor_field_block_device_label">Till date</label>
            </div>
            <div class = "p-2 w-full">
                <x-inputs.datepicker id = "filterDateTill" wire:model.lazy = "filterDateTill" tabindex = "30"/>
                @error('filterDateTill') <span
                    class = "editor_form_validation_error">{{ $message }}</span> @enderror
            </div>
        </div>
    </div>
</fieldset>

@if ($this->totalReactionCount > 0)
    <div class = "min-w-full">
            <canvas id = "reactionsChartStatisticsChart" style = "background: #000000"></canvas>
        </div>
        @else
        <div class = "m-2 p-2 warning_text">
            {!! AppIconFacade::get(IconEnum::Warning ) !!}
            There are no data found !
        </div>
        @endif

        @assets
        <script src = "https://cdn.jsdelivr.net/npm/chart.js"></script>
        @endassets

        @script
        <script>
            const ctx = document.getElementById('reactionsChartStatisticsChart');
            const reactions = $wire.reactions;
            const labels = reactions.map(item => item.action_label)
            const values = reactions.map(item => item.reaction_count)

            var chartObj = new Chart(ctx, {
                type: 'pie',
                data: {
                    labels: labels,
                    datasets: [{
                        label: '# of Reactions',
                        data: values,
                        borderWidth: 2
                    }]
                },
                options: {
                    scales: {
                        y: {
                            beginAtZero: true
                        }
                    },

                    plugins: {
                        legend: {
                            position: 'top',
                            labels: {
                                font: {
                                    size: 18
                                },
                                fontColor: 'white'
                            }
                        },
                        title: {
                            display: true,
                            text: 'Reactions by type with total quality {{ $totalReactionCount }}'
                        }
                    }
                }
            });

        </script>
        @endscript


        console.info(chartObj)
        // chartObj.update()   // IF TO UNCOMMENT - RAISED ERROR : Uncaught SyntaxError: Unexpected end of input
        // chartObj.refresh()  // IF TO UNCOMMENT - RAISED ERROR : chartObj.refresh is not a function


    </div>
</div>

и когда страница перезагружается в первый раз, у меня есть действительная диаграмма с максимальной шириной в упаковке html-элементов:

Когда я меняю некоторые параметры фильтра, данные перезагружаются, и размер диаграммы становится небольшим:

для третьего фильтра изменен элемент реагированияChartStatisticsChart, потерявший свойства диаграммы, и у меня есть черный блок:

Поискав в сети, я нашел несколько методовchartObj.update(), но они мне не помогли.

Каким образом я могу проверить/исправить график?

Код компонента источника данных:

В классе компонента ReactionsChartStatistics.php у меня есть:

<?php

namespace App\Livewire\Admin;
use App\Enums\ReactionActionEnum;
use App\Models\Reaction;
...
class ReactionsChartStatistics extends Component
{
    public array $reactions = [];
    public int $totalReactionCount = 0;

    public function mount()
    {
        // Get data for filtering block
        $this->usersSelectionItems = User::get()->pluck('name','id')->toArray();
        $this->modelTypeSelectionItems = $this->getModelTypeSelectionItems();

        $statisticsDays = ConfigValueEnum::get(ConfigValueEnum::NEWS_REACTIONS_STATISTICS_DAYS);
        $this->filterDateFrom = Carbon::now()->addDays(-$statisticsDays)->startOfDay();
        $this->filterDateTill = Carbon::now()->endOfDay();
    }
    public function render(): View
    {

        $reactionTb = (new Reaction)->getTable();
        $this->totalReactionCount = 0;
            $this->reactions = Reaction
                ::getByCreatedAt($this->filterDateFrom, '>=')
                ->getByCreatedAt($this->filterDateTill, '<')
                ->groupBy('action')
                ->orderBy('reaction_count', 'desc')
                ->select(
                    $reactionTb . '.action',
                    DB::raw('count(' . $reactionTb . '.id) as reaction_count'))
                ->get()->toArray();
        }

        foreach ($this->reactions as $key => $reaction) {
            $this->reactions[$key]['action_label'] = ReactionActionEnum::getLabel($reaction['action']);
            $this->totalReactionCount += $reaction['reaction_count'];
        }

        return view('livewire.admin.reactions-chart-statistics')->layout('components.layouts.admin');
    }

}
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
0
141
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Добавьте провод:игнорировать в <div>, содержащий график, чтобы Livewire не обновлял его:

@if ($this->totalReactionCount > 0)

    <div wire:ignore class = "min-w-full">  {{--  HERE -- }}

Редактировать

Чтобы обновить диаграмму при обновлении входных данных, мы можем отправить событие из бэкэнда.

Класс

class ReactionsChartStatistics extends Component
{
    public array $reactions = [];
    public int $totalReactionCount = 0;

    public $filterModelType;
    public $filterDateFrom;
    public $filterDateTill;
    public $modelTypeSelectionItems;


    protected function prepareData()
    {
        // This code was previously found in the render() method

        $reactionTb = (new Reaction)->getTable();

        $this->totalReactionCount = 0;

        $this->reactions = Reaction
             ::getByCreatedAt($this->filterDateFrom, '>=')
             ->getByCreatedAt($this->filterDateTill, '<')
             ->groupBy('action')
             ->orderBy('reaction_count', 'desc')
             ->select(
                  $reactionTb . '.action',
                  DB::raw('count(' . $reactionTb . '.id) as reaction_count'))
             ->get()->toArray();
        }

        foreach ($this->reactions as $key => $reaction) {
            $this->reactions[$key]['action_label'] = ReactionActionEnum::getLabel($reaction['action']);
            $this->totalReactionCount += $reaction['reaction_count'];
        }
    }


    public function mount()
    {
        // Get data for filtering block
        $this->usersSelectionItems = User::get()->pluck('name','id')->toArray();
        $this->modelTypeSelectionItems = $this->getModelTypeSelectionItems();

        $statisticsDays = ConfigValueEnum::get(ConfigValueEnum::NEWS_REACTIONS_STATISTICS_DAYS);
        $this->filterDateFrom = Carbon::now()->addDays(-$statisticsDays)->startOfDay();
        $this->filterDateTill = Carbon::now()->endOfDay();

       $this->prepareData(); // <~~~ Added 
    }


    // Raises an event when the parameters are updated
    public function updated($property, $value)
    {
        $this->prepareData();
        $this->dispatch('refresh-chart');
    }


    public function render()
    {
        return view('livewire.admin.reactions-chart-statistics')->layout('components.layouts.admin');
    }
}

Javascript в представлении

@script
<script>

    const ctx = document.getElementById('reactionsChartStatisticsChart');

    const getLabels = () => $wire.reactions.map(item => item.action_label);
    const getValues = () => $wire.reactions.map(item => item.reaction_count);

    let chartObj = new Chart(ctx, {

        type: 'pie',

        data: {
            labels: getLabels(),
            datasets: [{
                label: '# of Reactions',
                data: getValues(),
                borderWidth: 2
            }]
        },

        options: {

            scales: {
                y: { beginAtZero: true }
            },

            plugins: {
                legend: {
                    position: 'top',
                    labels: {
                        font: { size: 18 },
                        fontColor: 'white'
                    }
                },

                title: {
                    display: true,
                    text: 'Reactions by type with total quality {{ $totalReactionCount }}'
                }
            }
        }
    });

    // This event listener updates the chart 
    $wire.on("refresh-chart", () => {

        chartObj.data.labels = getLabels();
        chartObj.data.datasets = [{ data: getValues() }];

        chartObj.update()
    });

</script>
@endscript

В бэкэнде я перенес подготовку данных в специальный метод подготовить данные(), который сначала вызывается в методе mount(), а затем в методе update(). Метод update() вызывается Livewire каждый раз, когда входные данные меняют значение, а также используется для отправки события обновления диаграммы.

Во внешнем интерфейсе я добавил прослушиватель событий $wire.on("refresh-chart", ....), который обновляет данные диаграммы, а затем вызываетchartObj.update() для обновления DOM.

провод:игнорировать в диаграмме <div> все еще требуется

Нет, это не работает. Я заполнил диаграмму данными при загрузке страницы, но любой следующий div диаграммы, изменяющий данные, не ссылается на новый набор данных из базы данных.

mstdmstd 19.04.2024 16:42

Как заполняется переменная $reactions? Пожалуйста, покажите также соответствующий код класса

TUPKAP 19.04.2024 16:54

Пожалуйста, проверьте код компонента источника данных.

mstdmstd 19.04.2024 17:14

Другие вопросы по теме