使用 Livewire 线时,完整日历消失:民意调查

问题描述 投票:0回答:1

我正在开发一个使用 fullcalendar 进行约会的项目。我想要完成的任务是使日历中的事件保持最新。

我决定使用 Livewire,这让事情变得简单。 一切正常。但因为我在 livewire 组件中使用了wire:poll,所以组件的内容会被刷新以保持内容始终更新。

问题是,组件一刷新,fullcalendar就从页面上完全消失了。

当然,页面上的其他数据会毫无问题地更新。 我该如何解决这个问题。我究竟做错了什么。或者有更好的方法来处理这个问题吗?

这是我的代码:

Livewire 组件类:

<?php

namespace Modules\Visitor\Livewire;

use Livewire\Component;
use Illuminate\Support\Carbon;
use Modules\Visitor\app\Models\Appointment;

class FrontendCalendar extends Component
{
  public $events;

  public function render()
  {
    $today_appointments = Appointment::where('status', 0)->whereDate('created_at','>=', Carbon::today())->latest()->get();
    $pending_appointments = Appointment::where('status', 0)->whereDate('created_at','<', Carbon::today())->latest()->get();
    $appointments_events = Appointment::where('status', 0)->latest()->get()->map(function($item){
      return [
        'id' => $item->id,
        'title' => $item->name,
        'start' => format_date($item->start_date),
        'end' => format_date($item->end_date),
        'extendedProps' => [
          'calendar' => $item->color ?? 'primary',
          'fullname' => $item->name,
          'phone' => $item->phone,
          'email' => $item->email,
          'address' => $item->address,
          'gender' => $item->gender,
          'purpose' => $item->purpose,
          'status' => $item->status,
          'start_date' => $item->start_date,
          'end_date' => $item->end_date,
          'color' => $item->color?? 'primary',
        ]
      ];
    });
    $this->dispatch('refreshCalender', ($appointments_events));
    return view('visitor::livewire.frontend-calendar',compact(
      'today_appointments','pending_appointments','appointments_events'
    ));
  }
}

Livewire 视图: livewire.frontend-calendar


<div wire:poll.keep-alive>

  <div class="card app-calendar-wrapper">
    <div class="row g-0">
    <!-- Calendar -->
    <div class="col app-calendar-content">
      <div class="card shadow-none border-0 border-start rounded-0">
        <div class="card-body pb-0">
          <!-- FullCalendar -->
          <div id="calendar"></div>
        </div>
      </div>
      <div class="app-overlay"></div>
      <!-- FullCalendar Offcanvas -->
      @include('visitor::offcanvas')
    </div>
    <!-- /Calendar -->
    <!-- Calendar Sidebar -->
    <div class="col app-calendar-sidebar pt-1" id="app-calendar-sidebar">
      {{-- <div class="p-3 pb-2 my-sm-0 mb-3">
        <div class="d-grid">
          <button class="btn btn-primary btn-toggle-sidebar" data-bs-toggle="offcanvas" data-bs-target="#addEventSidebar" aria-controls="addEventSidebar">
            <i class="mdi mdi-plus me-1"></i>
            <span class="align-middle">Add Appointment</span>
          </button>
        </div>
      </div> --}}
      <div class="p-4">
        @if (!empty($today_appointments) && ($today_appointments->count() > 0))
        <h4>Today</h4>
        <hr class="container-m-nx my-4">
        <ul style="overflow-y: scroll;height: 200px;" class="p-0 m-0">
          @foreach ($today_appointments as $item)
          <li class="d-flex shadow-sm p-1 rounded mb-4">
            <div class="avatar flex-shrink-0 me-3">
              @if (substr($item->gender,0,1) == 'M')
              <img src="{{asset('assets/img/avatars/1.png')}}" alt="avatar" class="rounded">
              @else
              <img src="{{asset('assets/img/avatars/8.png')}}" alt="avatar" class="rounded">
              @endif
            </div>
            <div class="d-flex w-100 flex-wrap align-items-center justify-content-between gap-2">
              <div class="me-2">
                <h6 class="mb-0 fw-semibold text-nowrap"><small><span class="badge bg-label-success rounded-pill"><i class="tf-icons mdi mdi-circle mdi-14px"></i></span> <span>{{$item->name}}</span></small></h6>
                <small class="text-muted">
                  <i class="mdi mdi-calendar-blank-outline mdi-14px"></i>
                  <span>{{$item->start_date}} |{{$item->end_date}}</span>
                </small>
                <p>{{$item->purpose}}</p>
              </div>
            </div>
          </li>
          <hr>
          @endforeach
        </ul>
        <hr class="container-m-nx my-4">
        @endif
        @if (!empty($pending_appointments) && ($pending_appointments->count() > 0))

        <h4>Upcoming</h4>
        <hr class="container-m-nx my-4">
        <ul style="overflow-y: scroll;height: 300px; overflow-x:hidden" class="p-0 m-0">
          @foreach ($pending_appointments as $item)
          <li class="d-flex shadow-sm p-1 rounded mb-4">
            <div class="avatar flex-shrink-0 me-3">
              @if (substr($item->gender,0,1) == 'M')
              <img src="{{asset('assets/img/avatars/1.png')}}" alt="avatar" class="rounded">
              @else
              <img src="{{asset('assets/img/avatars/8.png')}}" alt="avatar" class="rounded">
              @endif
            </div>
            <div class="d-flex w-100 flex-wrap align-items-center justify-content-between gap-2">
              <div class="me-2">
                <h6 class="mb-0 fw-semibold text-nowrap"><small><span class="badge bg-label-success rounded-pill"><i class="tf-icons mdi mdi-circle mdi-14px"></i></span> <span>{{$item->name}}</span></small></h6>
                <small class="text-muted">
                  <i class="mdi mdi-calendar-blank-outline mdi-14px"></i>
                  <span>{{$item->start_date}} |{{$item->end_date}}</span>
                </small>
                <p>{{$item->purpose}}</p>
              </div>
            </div>
          </li>
          <hr>
          @endforeach
        </ul>
        @endif
      </div>
    </div>
    <!-- /Calendar Sidebar -->
    </div>
  </div>

</div>

@push('page-script')
<script>
  'use strict';
  document.addEventListener('DOMContentLoaded', function () {
    (function () {
      let calendarEl = document.getElementById('calendar'),
        appCalendarSidebar = document.querySelector('.app-calendar-sidebar'),
        offcanvasAddAppointment = document.getElementById('addEventSidebar'),
        appOverlay = document.querySelector('.app-overlay'),
        offcanvasTitle = document.querySelector('.offcanvas-title'),
        btnToggleSidebar = document.querySelector('.btn-toggle-sidebar'),
        btnSubmit = document.querySelector('button[type="submit"]'),
        btnCancel = document.querySelector('.btn-cancel'),
        selectAll = document.querySelector('.select-all'),
        inlineCalendar = document.querySelector('.inline-calendar');

      let eventToUpdate, inlineCalInstance;
      const bsoffcanvasAddAppointment = new bootstrap.Offcanvas(offcanvasAddAppointment);

      // Inline sidebar calendar (flatpicker)
      if (inlineCalendar) {
        inlineCalInstance = inlineCalendar.flatpickr({
          monthSelectorType: 'static',
          inline: true
        });
      }
      function eventClick(info) {
        eventToUpdate = info.event;
        var appointment_id = appointment_id;

        bsoffcanvasAddAppointment.show();
        if (offcanvasTitle) {
          offcanvasTitle.innerHTML = 'Update Appointment';
        }
        btnSubmit.innerHTML = 'Update';
        btnSubmit.classList.add('btn-update-event');
        btnSubmit.classList.remove('btn-add-event');

        var data = eventToUpdate.extendedProps;
        $('#appointment_id').val(eventToUpdate.id);
        $('#fullname').val(data.fullname);
        $('#phone').val(data.phone);
        $('#email').val(data.email);
        $('#address').val(data.address);
        $('#gender').val(data.gender);
        $('#purpose').val(data.purpose);
        $('#startDate').val(data.start_date);
        $('#endDate').val(data.end_date);
        $('#status').val(data.status).trigger('change');

      }

      function modifyToggler() {
        const fcSidebarToggleButton = document.querySelector('.fc-sidebarToggle-button');
        if (fcSidebarToggleButton) {
          fcSidebarToggleButton.classList.remove('fc-button-primary');
          fcSidebarToggleButton.classList.add('d-lg-none', 'd-inline-block', 'ps-0');
          while (fcSidebarToggleButton.firstChild) {
            fcSidebarToggleButton.firstChild.remove();
          }
          fcSidebarToggleButton.setAttribute('data-bs-toggle', 'sidebar');
          fcSidebarToggleButton.setAttribute('data-overlay', '');
          fcSidebarToggleButton.setAttribute('data-target', '#app-calendar-sidebar');
          fcSidebarToggleButton.insertAdjacentHTML('beforeend', '<i class="mdi mdi-menu mdi-24px text-body"></i>');
        }
      }

      let eventsData = @json($appointments_events)

      Livewire.on('refreshCalender', (e) => {
        eventsData = { ...e }[0]
        console.log(eventsData);
      })
      let calendar = new Calendar(calendarEl, {
        initialView: 'dayGridMonth',
        events: eventsData,
        plugins: [dayGridPlugin, interactionPlugin, listPlugin, timegridPlugin],
        editable: true,
        dragScroll: true,
        eventResizableFromStart: true,
        customButtons: {
          sidebarToggle: {
            text: 'Sidebar'
          }
        },
        headerToolbar: {
          start: 'sidebarToggle, prev,next, title',
          end: 'dayGridMonth,timeGridWeek,timeGridDay,listMonth'
        },
        loading: function(isLoading) {
          if (!isLoading) {
              this.getEvents().forEach(function(e){
                if (e.source === null) {
                    e.remove();
                }
              });
          }
        },
        initialDate: new Date(),
        navLinks: true, // can click day/week names to navigate views
        eventClassNames: function ({ event: calendarEvent }) {
          const colorName = calendarEvent._def.extendedProps.color;
          // Background Color
          return ['fc-event-' + colorName];
        },
        dateClick: function (info) {
          let date = moment(info.date).format('YYYY-MM-DD');
          bsoffcanvasAddAppointment.show();

          if (offcanvasTitle) {
            offcanvasTitle.innerHTML = 'Add Appointment';
          }
          btnSubmit.innerHTML = 'Add';
          btnSubmit.classList.remove('btn-update-event');
          btnSubmit.classList.add('btn-add-event');
        },
        eventClick: function (info) {
          eventClick(info);
        },
        datesSet: function () {
          modifyToggler();
        },
        viewDidMount: function () {
          modifyToggler();
        }
      });
      calendar.render();



      // Modify sidebar toggler
      modifyToggler();

      // Hide left sidebar if the right sidebar is open
      if (btnToggleSidebar) {
        btnToggleSidebar.addEventListener('click', e => {
          if (offcanvasTitle) {
            offcanvasTitle.innerHTML = 'Add Appointment';
          }
          btnSubmit.innerHTML = 'Add';
          btnSubmit.classList.remove('btn-update-event');
          btnSubmit.classList.add('btn-add-event');
          appCalendarSidebar.classList.remove('show');
          appOverlay.classList.remove('show');
        });
      }

      if(inlineCalInstance){
        inlineCalInstance.config.onChange.push(function (date) {
          calendar.changeView(calendar.view.type, moment(date[0]).format('YYYY-MM-DD'));
          modifyToggler();
          appCalendarSidebar.classList.remove('show');
          appOverlay.classList.remove('show');
        });

      }
    })();
  });
</script>
@endpush

显示日历的主页


@extends('layouts.layoutMaster')

@section('title', 'Appointments - Calendar View')

@section('vendor-style')
<link rel="stylesheet" href="{{asset('assets/vendor/libs/fullcalendar/fullcalendar.css')}}" />
<link rel="stylesheet" href="{{asset('assets/vendor/libs/flatpickr/flatpickr.css')}}" />
@endsection

@section('page-style')
<link rel="stylesheet" href="{{asset('assets/vendor/css/pages/app-calendar.css')}}" />
@endsection


@section('content')
<livewire:visitor::frontend-calendar />
@endsection


@section('vendor-script')
<script src="{{asset('assets/vendor/libs/fullcalendar/fullcalendar.js')}}"></script>
<script src="{{asset('assets/vendor/libs/flatpickr/flatpickr.js')}}"></script>
<script src="{{asset('assets/vendor/libs/moment/moment.js')}}"></script>
@endsection

我应该提到的是, @push('page-script') 在页面中的 @section('vendor-script') 下呈现。 预先感谢

我希望日历能够随着新事件一起呈现,而不会在我身上消失。

我也尝试过使用here 提到的答案,但没有成功。

fullcalendar laravel-livewire
1个回答
0
投票

这个问题似乎是双重的。首先,您的脚本被多次推送到 'page-script' 堆栈中。这意味着每次刷新组件时,相同的脚本都会被推入堆栈。其次,如果您无法使用 wire:ignore,则每当刷新组件时,您可能需要重新初始化 FullCalendar。您可以借助 Livewire Events 来实现这一目标。

© www.soinside.com 2019 - 2024. All rights reserved.