问题
I'm using Philipp Frenzel FullCalendar in Yii2 framework and its working perfectly. I want to implement basic filter events on calendar base on option select but my codes still not working. Help would be highly appreciated.
This is inside 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;
}
}
This is event-index :
<?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>
below is screen shot result when i comment 'events'=> $events, inside index.php, (as per your instruction). even I choose via select option, it's not filtering the event
if I un-comment 'events'=> $events, it's showing all events, but when i choose via select option, it's not filtering event. below the screen shot:
回答1:
The extension you are using includes the latest version FullCalendar v3.9.0
. So refer to the latest API version 3 for all the documentation references below.
Approach
To me, if I have to implement it I won't be using the events
option as we need to filter events on runtime base on the option selected from the drop-down a better option would be to use eventSources
option. It provides a way to specify multiple event sources. This option is used instead of the events
option.You can put any number of event arrays, functions, JSON feed URLs, or full-out Event Source Objects into the eventSources
array.
A simple example javascript based
$('#calendar').fullCalendar({
eventSources: [
'/feed1.php',
'/feed2.php'
]
});
If you look into the documentation for Fullcalendar they have events related section with the name Event Data where you can see various options along with the one mentioned.
Start From
We will start by providing eventSources
a URL for our JSON feed for the calendar events, and remove the option events
. I will use a single source you can have multiple too if you like but i will keep it short and simple.
Change the code for the Widget and add the eventSources
option under the clientOptions
option for the widget.
<?=
\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;
});
}",
));
?>
At this point if you will refresh the calendar you will not see any events that you were loading before because previously you were using the 'events'=>$events
to load the events but now we have provided a url source '/schedule/filter-events'
(change it to the relevant controller/action
you want to use I will use the same URL for the example).
Second Part
So the $events
that you were loading before, will now have to load via the new action we are going to create. If you are following the example provided on the GitHub page for the extension and loading your events from the database model and then looping over with a for loop to load all of the events to the \yii2fullcalendar\models\Events()
model and then load that array.
As you have not provided any detail regarding the model you are using for the database to store and load events to the calendar, I assume that your model name is MyEvents
change it accordingly and the field column_name
in the query.
/**
*
* @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;
}
Things to notice above
$choice
parameter inactionFilterEvents
withnull
as the default value for listing all the events when the calendar loads for the first time.- The
loadEvents()
method to load the searched events from the database to\yii2fullcalendar\model\Events
, do change the field names used in theforeach
with the relevant model field names that you will use instead ofMyEvents
.
At this point, if you have done everything correctly as mentioned if you refresh your page you will see the default events loading in the calendar.
Actual part
Now comes the part of filtering the events depending on the choice of the drop-down. For server-side we have already done the work above, the else
part will handle filtering all the events from the database by comparing the selected choice with the desired column column_name
(replace it with the field name you want to compare with).
The part still to be done is the client-side now, we will bind the onchange
event of the dropdown and then use mainly these 3 methods
provided by fullcalendar
- removeEventSource,Dynamically removes an event source.Events from the source will be immediately removed from the calendar.
- addEventSource,Dynamically adds an event source.The source may be an Array/URL/Function just as in the events option. Events will be immediately fetched from this source and placed on the calendar.
- refetchEvents, Refetches events from all sources and rerenders them on the screen.
Every time we select a choice the previous eventSource
is removed and a new eventSource
is added so basically will building the url schedule/filter-events?choice=all
if All Tech
is selected, schedule/filter-events?choice=0
if Hendy Nugraha
is selected and so on.
Add the below javascript on top of your view where you have initialized your widget.
Make sure the selector used below #select_name
is matched with your drop-down's actual 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);
Do everything as told above and it will start working and will show you filtered results as soon as you change options in the drop-down.
Note: I have provided the solution above from a running project, with Yii2.0.15.1
and the latest available extension.
EDIT
I am amazed that you can't differentiate between server-side, HTML and javascript, the code I provided related to javascript that you needed to paste in the view event-index
was inside the heredoc and you had to just copy paste it but somehow you ended up wrapping the javascript inside the <script>
tag and removed the heredoc
? and moreover you are calling the $this->registerJs()
inside the script tag rather than the <?php ?>
tags ? ¯\_(ツ)_/¯.
And you didn't even changed the controller name in the URL for the var eventSource=['/schedule/filter-events'];
javascript code your controller is Event
and not schedule
, i wrote at every point where i assumed a model or controller name to change it accordingly, even your widget code is not updated accordingly it also has the 'eventSources' => ['/schedule/filter-events'],
when it should be 'eventSources' => ['/event/filter-events'],
.
So this time just copy paste the whole view code below and DO NOT CHANGE anything. I won't be spoon feeding you anymore just because you have to mark it correct, although it is the correct answer and should Have been awarded the Bounty.
Troubleshooting and fixing syntax errors are your duties to fix along when you are integrating the code. The solution provided is working and you failing to integrate it does not mean it isnt the correct answer.
'event-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>
来源:https://stackoverflow.com/questions/52076369/yii2-full-calendar-event-filtering-not-working