Yii2 полная фильтрация событий календаря не работает - PullRequest
0 голосов
/ 29 августа 2018

Я использую 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 (согласно вашей инструкции). даже если я выбрал через опцию выбора, это не фильтрует событие

enter image description here

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

enter image description here

1 Ответ

0 голосов
/ 07 сентября 2018

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

подход

Для меня, если мне придется реализовать его, я не буду использовать опцию events, поскольку нам нужно фильтровать события на основе времени выполнения по опции, выбранной из раскрывающегося списка, лучшим вариантом будет использование * 1007. * вариант. Он позволяет указать несколько источников событий. Эта опция используется вместо опции 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();

    } 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();
    }

    return $this->loadEvents($dbEvents);
}

/**
 * 
 * @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 и последним доступным расширением.

EDIT

Я поражен тем, что вы не можете различить серверную часть, HTML и javascript, предоставленный мною код, связанный с javascript, который вам нужно было вставить в представление event-index, был внутри heredoc и вам нужно было просто скопировать и вставить его, но каким-то образом вы завернули завершение javascript в тег <script> и удалили heredoc? и, кроме того, вы вызываете $this->registerJs() внутри тега script, а не <?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>
...