Yii2 полная фильтрация событий календаря не работает

Я использую Philipp Frenzel FullCalendar в фреймворке Yii2, и он работает отлично. Я хочу реализовать базовый фильтр событий на основе календаря при выборе опции, но мои коды все еще не работают. Помощь будет высоко ценится.

Это внутри EventController:

<?php

namespace app\controllers;

use Yii;
use app\models\Event;
use app\models\EventSearch;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
use yii\filters\VerbFilter;

/**
 * EventController implements the CRUD actions for Event model.
 */
class EventController extends Controller
{
    /**
     * {@inheritdoc}
     */
    public function behaviors()
    {
        return [
            'verbs' => [
                'class' => VerbFilter::className(),
                'actions' => [
                    'delete' => ['POST'],
                ],
            ],
        ];
    }

    /**
     * Lists all Event models.
     * @return mixed
     */
    public function actionIndex()
    {
        /*$searchModel = new EventSearch();
        $dataProvider = $searchModel->search(Yii::$app->request->queryParams);*/

        $events = Event::find()->all();
        $tasks = [];

        foreach ($events as $eve)
        {
              $event = new \yii2fullcalendar\models\Event();
              $event->id = $eve->id;
              $event->backgroundColor = 'green';
              $event->title = $eve->title;
              $event->start = $eve->created_date;
              $tasks[] = $event;
        }

        return $this->render('index', [
            //'searchModel' => $searchModel,
            'events' => $tasks,
        ]);
    }

    /**
     * Displays a single Event model.
     * @param integer $id
     * @return mixed
     * @throws NotFoundHttpException if the model cannot be found
     */
    public function actionView($id)
    {
        return $this->render('view', [
            'model' => $this->findModel($id),
        ]);
    }

    /**
     * Creates a new Event model.
     * If creation is successful, the browser will be redirected to the 'view' page.
     * @return mixed
     */
    public function actionCreate($date)
    {
        $model = new Event();
        $model->created_date = $date;

        if ($model->load(Yii::$app->request->post()) && $model->save()) {
            return $this->redirect(['index']);
        }else{
            return $this->renderAjax('create', [
            'model' => $model,
            ]);
        }
    }

    /**
     * Updates an existing Event model.
     * If update is successful, the browser will be redirected to the 'view' page.
     * @param integer $id
     * @return mixed
     * @throws NotFoundHttpException if the model cannot be found
     */
    public function actionUpdate($id)
    {
        $model = $this->findModel($id);

        if ($model->load(Yii::$app->request->post()) && $model->save()) {
            return $this->redirect(['view', 'id' => $model->id]);
        } else { 
            return $this->renderAjax('update', [
            'model' => $model,
        ]);
        }
    }

    /**
     * Deletes an existing Event model.
     * If deletion is successful, the browser will be redirected to the 'index' page.
     * @param integer $id
     * @return mixed
     * @throws NotFoundHttpException if the model cannot be found
     */
    public function actionDelete($id)
    {
        $this->findModel($id)->delete();

        return $this->redirect(['index']);
    }

    /**
     * Finds the Event model based on its primary key value.
     * If the model is not found, a 404 HTTP exception will be thrown.
     * @param integer $id
     * @return Event the loaded model
     * @throws NotFoundHttpException if the model cannot be found
     */
    protected function findModel($id)
    {
        if (($model = Event::findOne($id)) !== null) {
            return $model;
        }

        throw new NotFoundHttpException('The requested page does not exist.');
    }


    /**
 * 
 * @param type $choice
 * @return type
 */
    public function actionFilterEvents($choice = null) {
        Yii::$app->reponse->format = \yii\web\Response::FORMAT_JSON;
        $query = models\Event::find();

        if( is_null($choice) || $choice=='all'){
            //the function should return the same events that you were loading before
            $dbEvents = $query->all();
            $events = $this->loadEvents($dbEvents);
        } else{
            //here you need to look up into the data base 
            //for the relevant events against your choice
            $dbEvents = $query->where(['=', 'column_name', ':choice'])
                    ->params([':choice' => $choice])
                    ->asArray()
                    ->all();
            $events = $this->loadEvents($dbEvents);
        }
        return $events;
    }

    /**
     * 
     * @param type $dbEvents
     * @return \yii2fullcalendar\models\Event
     */
    private function loadEvents($dbEvents) {
        foreach( $dbEvents AS $event ){
            //Testing
            $Event = new \yii2fullcalendar\models\Event();
            $Event->id = $event->id;
            $Event->title = $event->categoryAsString;
            $Event->description = $event->description;
            $Event->start = date('Y-m-d\TH:i:s\Z', strtotime($event->created_date . ' ' . $event->created_date));
            $Event->end = date('Y-m-d\TH:i:s\Z', strtotime($event->time_out . ' ' . $event->time_out));
            $Event->status = $event->status;
            $Event->remarks = $event->remarks;
            $events[] = $Event;
        }
        return $events;
    }
}

Это событие-индекс:

<?php

use yii\helpers\Html;
use yii\grid\GridView;
use yii\bootstrap\Modal;

$this->title = 'Roster Bul Hanine Project';
$this->params['breadcrumbs'][] = $this->title;

$js=<<< JS
var eventSource=['/event/filter-events'];
$("#select_name").on('change',function() {
    //get current status of our filters into eventSourceNew
    var eventSourceNew=['/event/filter-events?choice=' +  $(this).val()];
    //remove the old eventSources
    $('#event').fullCalendar('removeEventSource', eventSource[0]);
    //attach the new eventSources
    $('#event').fullCalendar('addEventSource', eventSourceNew[0]);
    $('#event').fullCalendar('refetchEvents');
    //copy to current source 
    eventSource = eventSourceNew;
});
JS;
    $this->registerJs($js, \yii\web\View::POS_READY);

?>
<div class="event-index">

    <h1><?= Html::encode($this->title) ?></h1>
    <?php // echo $this->render('_search', ['model' => $searchModel]); ?>

    <p><?= Html::a('Create Roster', ['create'], ['class' => 'btn btn-success']) ?></p>
    <p>
        <select class="model_attribute" id="select_name">
            <option value="all">All Tech</option>
            <option value="0">Hendy Nugraha</option>
            <option value="1">Ginanjar Nurwin</option>
            <option value="2">Rio Andhika</option>
        </select>
    </p>
    <div id="event"></div>

    <?php 
        Modal::begin([
            'header'=>'<h4>Roster</h4>',
            'id' => 'model',
            'size' => 'model-lg',
        ]);
        echo "<div id='modelContent'></div>";
        Modal::end();
    ?>

    <?=\yii2fullcalendar\yii2fullcalendar::widget(array(
      'events'=> $events, 
      'id' => 'event',
      'clientOptions' => [ 
        'editable' => true,
        'eventSources' => ['/event/filter-events'],
        'draggable' => true,
        'droppable' => true,
        ],
      'eventClick' => "function(calEvent, jsEvent, view) {

                $(this).css('border-color', 'red');

                $.get('index.php?r=event/update',{'id':calEvent.id}, function(data){
                    $('.modal').modal('show')
                    .find('#modelContent')
                    .html(data);
                })

                $('#calendar').fullCalendar('removeEvents', function (calEvent) {
                    return true;
                });

           }",

           /*$('#event').fullCalendar({
            eventRender: function(event, element) {
                if(event.status == "on leave") {
                    element.css('background-color', '#131313');
                } else if (event.status == "stand by") {
                    element.css('background-color', '#678768');
                } else if (event.status == "active") {
                    element.css('background-color', '#554455');
                }
            },
        });*/
    ));

    ?>
</div>

ниже приведен скриншот, когда я комментирую 'events'=> $events внутри index.php (согласно вашей инструкции). даже я выбираю через опцию выбора, это не фильтрует событие

введите описание изображения здесь

если я отменяю комментарий 'events'=> $events, он показывает все события, но когда я выбираю опцию select, это не фильтрует событие. ниже снимка экрана:

введите описание изображения здесь

1 ответ

Используемое расширение включает в себя последнюю версию FullCalendar v3.9.0, Так что обратитесь к последней версии API 3 для всех ссылок на документацию ниже.

Подход

Для меня, если мне придется реализовать это, я не буду использовать events вариант, так как нам нужно отфильтровать события во время выполнения на основе параметра, выбранного из раскрывающегося списка, лучше использовать вариант eventSources вариант. Он позволяет указать несколько источников событий. Эта опция используется вместо events Вы можете поместить любое количество массивов событий, функций, URL-адресов фида JSON или полных объектов-источников событий в eventSources массив.

Простой пример на основе JavaScript

$('#calendar').fullCalendar({
  eventSources: [
    '/feed1.php',
    '/feed2.php'
  ]
});

Если вы посмотрите документацию для Fullcalendar, у них есть раздел, связанный с событиями, с именем Event Data где вы можете увидеть различные варианты наряду с упомянутым.

Начать с

Мы начнем с предоставления eventSources URL-адрес нашей ленты JSON для событий календаря и удалите параметр events, Я буду использовать один источник, вы можете иметь несколько, если хотите, но я буду кратким и простым.

Измените код для виджета и добавьте eventSources вариант под clientOptions вариант для виджета.

<?=
\yii2fullcalendar\yii2fullcalendar::widget(array(
    'id' => 'eventFilterCalendar',
    'clientOptions' => [
        'editable' => true,
        'eventSources' => ['/schedule/filter-events'],
        'draggable' => true,
        'droppable' => true,
    ],
    'eventClick' => "function(calEvent, jsEvent, view) {
        $(this).css('border-color', 'red');
        $.get('index.php?r=event/update',{'id':calEvent.id}, function(data){
            $('.modal').modal('show')
            .find('#modelContent')
            .html(data);
        });

        $('#calendar').fullCalendar('removeEvents', function (calEvent) {
            return true;
        });

    }",
));
?>

На этом этапе, если вы обновите календарь, вы не увидите никаких событий, которые вы загружали ранее, потому что ранее вы использовали 'events'=>$events чтобы загрузить события, но теперь мы предоставили источник URL '/schedule/filter-events' (измените его на соответствующий controller/action вы хотите использовать, я буду использовать тот же URL для примера).

Вторая часть

Итак $events то, что вы загружали раньше, теперь будет загружаться через новое действие, которое мы собираемся создать. Если вы следуете примеру, представленному на странице GitHub для расширения, и загружаете ваши события из модели базы данных, а затем зацикливаетесь на цикле for, чтобы загрузить все события в \yii2fullcalendar\models\Events() модель, а затем загрузить этот массив.

Поскольку вы не предоставили никаких сведений о модели, которую вы используете для базы данных для хранения и загрузки событий в календарь, я предполагаю, что название вашей модели MyEvents измените его соответственно и поле column_name в запросе.

/**
 * 
 * @param type $choice
 * @return type
 */
public function actionFilterEvents($choice = null) {
    Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
    $query = MyEvents::find();

    if( is_null($choice) || $choice=='all'){
        //the function should return the same events that you were loading before
        $dbEvents = $query->all();
        $events = $this->loadEvents($dbEvents);
    } else{
        //here you need to look up into the data base 
        //for the relevant events against your choice
        $dbEvents = $query->where(['=', 'column_name', ':choice'])
                ->params([':choice' => $choice])
                ->asArray()
                ->all();
        $events = $this->loadEvents($dbEvents);
    }
    return $events;
}

/**
 * 
 * @param type $dbEvents
 * @return \yii2fullcalendar\models\Event
 */
private function loadEvents($dbEvents) {
    foreach( $dbEvents AS $event ){
        //Testing
        $Event = new \yii2fullcalendar\models\Event();
        $Event->id = $event->id;
        $Event->title = $event->categoryAsString;
        $Event->start = date('Y-m-d\TH:i:s\Z', strtotime($event->date_start . ' ' . $event->time_start));
        $Event->end = date('Y-m-d\TH:i:s\Z', strtotime($event->date_end . ' ' . $event->time_end));
        $events[] = $Event;
    }
    return $events;
}

Вещи, чтобы заметить выше

  • $choice параметр в actionFilterEvents с null в качестве значения по умолчанию для перечисления всех событий, когда календарь загружается в первый раз.
  • loadEvents() способ загрузки искомых событий из базы данных в \yii2fullcalendar\model\Events измените имена полей, используемые в foreach с соответствующими именами полей модели, которые вы будете использовать вместо MyEvents,

На этом этапе, если вы все сделали правильно, как уже упоминалось, если вы обновите страницу, вы увидите загрузку событий по умолчанию в календаре.

Актуальная часть

Теперь наступает момент фильтрации событий в зависимости от выбора раскрывающегося списка. Для серверной стороны мы уже проделали работу выше, else часть будет обрабатывать фильтрацию всех событий из базы данных, сравнивая выбранный выбор с нужным столбцом column_name (замените его именем поля, которое вы хотите сравнить). Часть, которая еще предстоит сделать, теперь на стороне клиента, мы свяжем onchange событие раскрывающегося списка, а затем использовать в основном эти 3 methods предоставлено fullcalendar

  • removeEventSource, Динамически удаляет источник события. События из источника будут немедленно удалены из календаря.
  • addEventSource, Динамически добавляет источник события. Источником может быть массив /URL/ функция, как в опции событий. События будут немедленно получены из этого источника и помещены в календарь.
  • refetchEvents, Получает события из всех источников и отображает их на экране.

Каждый раз, когда мы выбираем выбор предыдущего eventSource удаляется и новый eventSource добавлено так в основном будет строить URL-адрес schedule/filter-events?choice=all если All Tech выбран, schedule/filter-events?choice=0 если Hendy Nugraha выбрано и так далее.

Добавьте приведенный ниже javascript поверх вашего представления, где вы инициализировали свой виджет.

Убедитесь, что селектор используется ниже #select_name соответствует вашему раскрывающемуся id ,

$js = <<< JS

        var eventSource=['/schedule/filter-events'];

        $("#select_name").on('change',function() {

        //get current status of our filters into eventSourceNew
        var eventSourceNew=['/schedule/filter-events?choice=' +  $(this).val()];

        //remove the old eventSources
        $('#eventFilterCalendar').fullCalendar('removeEventSource', eventSource[0]);
        //attach the new eventSources
        $('#eventFilterCalendar').fullCalendar('addEventSource', eventSourceNew[0]);
        $('#eventFilterCalendar').fullCalendar('refetchEvents');

        //copy to current source 
        eventSource = eventSourceNew;
    });
JS;

$this->registerJs($js, \yii\web\View::POS_READY);

Сделайте все, как сказано выше, и он начнет работать и покажет вам отфильтрованные результаты, как только вы измените параметры в раскрывающемся списке.

Примечание: я предоставил решение выше из работающего проекта, с Yii2.0.15.1 и последнее доступное расширение.

РЕДАКТИРОВАТЬ

Я поражен, что вы не можете различить серверную часть, HTML и javascript, код, который я предоставил, относящийся к javascript, который вам нужно было вставить в представление event-index был внутри heredoc и вам нужно было просто скопировать вставить его, но каким-то образом вы завернули Javascript внутри <script> пометить и удалить heredoc? и к тому же вы звоните $this->registerJs() внутри тега сценария, а не <?php ?> теги? ¯ \ _ (ツ) _ / ¯.

И вы даже не изменили имя контроллера в URL для var eventSource=['/schedule/filter-events']; Javascript код вашего контроллера Event и не schedule, я писал в каждой точке, где я предполагал, что имя модели или контроллера изменяет его соответственно, даже ваш код виджета не обновляется соответственно, он также имеет 'eventSources' => ['/schedule/filter-events'], когда это должно быть 'eventSources' => ['/event/filter-events'],,

Так что на этот раз просто скопируйте и вставьте весь код вида ниже, и ничего не меняйте. Я больше не буду кормить тебя ложкой только потому, что ты должен пометить это правильно, хотя это правильный ответ и должен был быть награжден.

Устранение неполадок и исправление синтаксических ошибок - это ваши обязанности, которые необходимо устранить при интеграции кода. Предоставленное решение работает, и если вы не смогли его интегрировать, это не означает, что оно не должно быть помечено правильным ответом.

"Событийно-index.php`

<?php

use yii\helpers\Html;
use yii\grid\GridView;
use yii\bootstrap\Modal;

$this->title = 'Roster Bul Hanine Project';
$this->params['breadcrumbs'][] = $this->title;

$js=<<< JS
var eventSource=['/event/filter-events'];
$("#select_name").on('change',function() {
    //get current status of our filters into eventSourceNew
    var eventSourceNew=['/event/filter-events?choice=' +  $(this).val()];
    //remove the old eventSources
    $('#event').fullCalendar('removeEventSource', eventSource[0]);
    //attach the new eventSources
    $('#event').fullCalendar('addEventSource', eventSourceNew[0]);
    $('#event').fullCalendar('refetchEvents');
    //copy to current source 
    eventSource = eventSourceNew;
});
JS;
    $this->registerJs($js, \yii\web\View::POS_READY);

?>
<div class="event-index">

    <h1><?= Html::encode($this->title) ?></h1>
    <?php // echo $this->render('_search', ['model' => $searchModel]); ?>

    <p><?= Html::a('Create Roster', ['create'], ['class' => 'btn btn-success']) ?></p>
    <p>
        <select class="model_attribute" id="select_name">
            <option value="all">All Tech</option>
            <option value="0">Hendy Nugraha</option>
            <option value="1">Ginanjar Nurwin</option>
            <option value="2">Rio Andhika</option>
        </select>
    </p>
    <div id="event"></div>



    <?php 
        Modal::begin([
            'header'=>'<h4>Roster</h4>',
            'id' => 'model',
            'size' => 'model-lg',
        ]);
        echo "<div id='modelContent'></div>";
        Modal::end();

    ?>

    <?=\yii2fullcalendar\yii2fullcalendar::widget(array(
      //'events'=> $events, 
      'id' => 'event',
      'clientOptions' => [ 
        'editable' => true,
        'eventSources' => ['/event/filter-events'],
        'draggable' => true,
        'droppable' => true,
        ],
      'eventClick' => "function(calEvent, jsEvent, view) {

                $(this).css('border-color', 'red');

                $.get('index.php?r=event/update',{'id':calEvent.id}, function(data){
                    $('.modal').modal('show')
                    .find('#modelContent')
                    .html(data);
                })

                $('#calendar').fullCalendar('removeEvents', function (calEvent) {
                    return true;
                });

           }",

           /*$('#event').fullCalendar({
            eventRender: function(event, element) {
                if(event.status == "on leave") {
                    element.css('background-color', '#131313');
                } else if (event.status == "stand by") {
                    element.css('background-color', '#678768');
                } else if (event.status == "active") {
                    element.css('background-color', '#554455');
                }
            },
        });*/
    ));

    ?>
</div>
Другие вопросы по тегам