I have a list, in which I have a delete button for each entry, which works flawlessly, as do the create function. I'm trying to add an edit button, and can manage to create the popup that requests the new name.
When I create a new entry and try to edit it, it shows me the create form again. When I try to edit an older entry, it tells me that
Oh snap! Change a few things up and try submitting again.
The category.name field is required.
My full code is here, for completion:
namespace App\Orchid\Screens;
use Orchid\Screen\Screen;
use Orchid\Screen\Fields\Input;
use Orchid\Support\Facades\Layout;
use Orchid\Screen\TD;
use Orchid\Screen\Actions\ModalToggle;
use App\Models\Category;
use Illuminate\Http\Request;
use Orchid\Screen\Actions\Button;
class CategoryScreen extends Screen
{
/**
* Fetch data to be displayed on the screen.
*
* #return array
*/
public function query(): iterable
{
return [
'categories' => Category::latest()->get(),
];
}
/**
* The name of the screen displayed in the header.
*
* #return string|null
*/
public function name(): ?string
{
return 'Category Screen';
}
/**
* The screen's action buttons.
*
* #return \Orchid\Screen\Action[]
*/
public function commandBar(): iterable
{
return [
ModalToggle::make('category')
->icon('plus')
->method('create')
->modal('createCategory'),
];
}
/**
* The screen's layout elements.
*
* #return \Orchid\Screen\Layout[]|string[]
*/
public function layout(): iterable
{
return [
Layout::table('categories', [
TD::make('name'),
// Create a delete button
TD::make('Actions')
->alignRight()
->render(function (Category $category) {
return Button::make('')
->icon('trash')
->confirm(
'After deleting, the category will be gone forever.'
)
->method('delete', [
'category' => $category->id,
]);
}),
TD::make('Actions')
->alignRight()
->render(function (Category $category) {
return Button::make('')
->icon('pencil')
->modal('editCategoryModal', [
'category' => $category,
])
->method('edit', [
'category' => $category->id,
]);
}),
]),
Layout::modal('createCategory', [
Layout::rows([
Input::make('category.name')
->title('Name')
->placeholder('Enter category name'),
]),
])
->title('Create category')
->applyButton('Create'),
];
}
// Make a create method that validates name field
public function create(Request $request)
{
$request->validate([
'category.name' => 'required|max:255',
]);
// Create a new category
$category = new Category();
$category->organisation_id = auth()->user()->organisation_id;
$category->name = $request->category['name'];
$category->save();
}
// Make a delete method that deletes the category
public function delete(Request $request)
{
$category = Category::find($request->category);
$category->delete();
}
// Make an edit method that validates name field
public function edit(Request $request)
{
$request->validate([
'category.name' => 'required|max:255',
]);
// Update the category
$category = Category::find($request->category->id);
$category->name = $request->category['name'];
$category->save();
}
public function editCategoryModal(): iterable
{
return [
Layout::modal('editCategory', [
Layout::rows([
Input::make('category.name')
->title('Name')
->placeholder('Enter category name'),
]),
])
->title('Edit category')
->applyButton('Save')
];
}
}
And my site, as it looks:
And the form, when I press the edit button (the pencil):
I am quite new to Laravel Orchid, so I admit that I might be going about this the totally wrong way, but the documentation does not include an example on how to do this.
Thank you.
You should use async functions to edit a Model on the same page (with modal)
Link : https://orchid.software/en/docs/modals/#asynchronous-data-loading
and you should also define all modals in the layouts section, not in a separate function.
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 months ago.
Improve this question
I am submitting a form thorugh ajax, form values are saving in the database and errors are showing without page reload, which is a good thing. As I am a beginner so i cannot make sense of this error. This error is not disturbing or impacting the flow of the application in any way. Thanks.
**Here's the error's image: **
**Here's the code of the controller: **
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Products;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Validator;
class ProductController extends Controller
{
//Search Products
public function search(Request $request)
{
$products = Products::where('name','like', '%'.$request->search.'%')
->orWhere('id','like', '%'.$request->search.'%')->get();
$output = "";
foreach($products as $products)
{
$output.=
'<tr class="border-bottom border-dark p-3">
<td>'.$products->name.'</td>
<td>'.$products->s_description.'</td>
<td>'.$products->l_description.'</td>
<td class="align-center p-5"><img class="img-fluid" src='.asset('images')."/".$products->image_src.'></td>
<td>'.$products->category.'</td>
<td>'.$products->quantity.'</td>
<td>'.$products->price.'</td>
<td>'.'
<form action='.route('delete_product', $products->id).' method="POST" id="deleteBtn">
z
<input type="hidden" name="_method" value="delete">
<button class="btn btn-danger" type="submit">'.'Delete</button>
</form>
'.'
</td>
</tr>
';
}
return response($output);
}
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function viewProducts()
{
$p_details = Products::all();
return view('admin.products.view_products', compact('p_details'));
}
public function productVerify(Request $request)
{
$val = $request->validate
(
[
'name' => 'required',
's_description' => 'required',
'l_description' => 'required',
'image_src' => 'required|mimes:jpg,png,jpeg',
'category' => 'required',
'quantity' => 'required|integer|not_in:0|regex:^[1-9][0-9]+^',
'price' => 'required|integer|not_in:0|regex:^[1-9][0-9]+^',
],
[
'required' => 'The :attribute field is required',
'mimes' => 'Image should be a JPG, JPEG, or PNG',
'integer' => 'The :attribute field should be an integer.',
]
);
if ($val)
{
return response()->json(['errors'=>($val)->errors()->all()]);
}
else
{
// return redirect()->to('view_products')->with('success','Product added successfully');
return response()->json(['errors'=>'Product added successfully, head to view products to inspect it. Thanks!']);
}
}
//Uploading Images
public function validImg(Request $request)
{
if ($request->hasFile('image_src'))
{
$filename = $request->file('image_src');
$filename->getClientOriginalName();
$filename = time().$filename->getClientOriginalName();
$destinationPath = base_path("/public/images");
$request->file('image_src')->move($destinationPath, $filename);
$data['image_src'] = $filename;
}
return $data['image_src'];
}
/**
* Show the form for creating a new resource.
*
* #return \Illuminate\Http\Response
*/
public function create()
{
return view('admin.products.add_products');
}
//Creating and Adding Products
public function createProduct(Request $request)
{
//Product Validation
$validation = $this->productVerify($request);
$data = $request->all();
$image_src = $this->validImg($request);
Products::create
([
'name' => $data['name'],
's_description' => $data['s_description'],
'l_description' => $data['l_description'],
'category' => $data['category'],
'quantity' => $data['quantity'],
'price' => $data['price'],
'image_src' => $image_src
]);
}
/**
* Show the form for editing the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function edit($id)
{
$product_edit = Products::findOrFail($id);
return view('admin.products.edit_products', compact('product_edit'));
}
/**
* Update the specified resource in storage.
*
* #param \Illuminate\Http\Request $request
* #param int $id
* #return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
//Product Validation
$validatedData = $this->productValidation($request);
$this->validImg($request);
Products::whereId($id)->update($validatedData);
return redirect('view_products')->with('success', 'Product details successfully updated');
}
/**
* Remove the specified resource from storage.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function destroy($id)
{
$products = Products::findOrFail($id);
$destinationPath = base_path("/public/images").'/'.$products->image_src;
if(File::exists($destinationPath))
{
File::delete($destinationPath); //for deleting only file try this
$products->delete(); //for deleting record and file try both
}
// $products->delete();
return redirect('view_products')->with('error', 'Product successfully deleted');
}
}
The validate() method on the $request object returns an array (see API docs) containing the data that passed validation. If validation fails, a JSON response (which includes validation errors) is generated and returned to the client that made the request.
The code statement you're highlighting in your question is informing you that the variable $val is an array, however, you're attempting to access some data within $val using the object operator (->) as though it were an object.
If that code statement were to actually be executed, you'd see an exception message because of this (there is no errors() method on the $val array).
For example, I have two tables. One called "PedidoReservaQuarto" and another "PedidoReserva". What I want to do is this, I want to save the data in both tables when I click the button. But first I need to enter data in the table "PedidoReservaQuarto" because of the id.
My action controller
public function actionCreate($id)
{
$modelPedidoReservaQuarto = new PedidoReservaQuarto();
$modelPedidoReserva = new PedidoReserva();
$modelPedidoReservaQuarto->quartoId = $id;
$modelPedidoReservaQuarto->save();
if ($modelPedidoReserva->load(Yii::$app->request->post()) && $modelPedidoReserva->save()) {
return $this->redirect(['create', 'id' => $modelPedidoReserva->id]);
}
return $this->render('../pedido-reserva/create', [
'model' => $modelPedidoReserva,
]);
}
Model PedidoReservaQuarto
public function getPedidoReservas()
{
return $this->hasMany(PedidoReserva::className(), ['reservaQuartoId' => 'id']);
}
/**
* Gets query for [[Quarto]].
*
* #return \yii\db\ActiveQuery
*/
public function getQuarto()
{
return $this->hasOne(Quarto::className(), ['id' => 'quartoId']);
}
Model PedidoReserva
public function getReservaQuarto()
{
return $this->hasOne(PedidoReservaQuarto::className(), ['id' => 'reservaQuartoId']);
}
Assuming in you form you have the data you need for both the model and send these data using method post (click submit button)
and you must obtain the id from modelPedidoReserva for assign to model modelPedidoReservaQuarto you could try
public function actionCreate()
{
$modelPedidoReservaQuarto = new PedidoReservaQuarto();
$modelPedidoReserva = new PedidoReserva();
$modelPedidoReservaQuarto->quartoId = $id;
$modelPedidoReservaQuarto->save();
if ($modelPedidoReserva->load(Yii::$app->request->post()) && $modelPedidoReserva->save()) {
$modelPedidoReservaQuarto->load(Yii::$app->request->post());
$modelPedidoReservaQuarto->quartoId = $modelPedidoReserva->id;
$modelPedidoReservaQuarto-save();
}
return $this->render('../pedido-reserva/create', [
'model' => $modelPedidoReserva,
]);
}
once you have saved the $modelPedidoReserva the related id is already available ..
I have a notes model. Which has a polymorphic 'noteable' method that ideally anything can use. Probably up to 5 different models such as Customers, Staff, Users etc can use.
I'm looking for the best possible solution for creating the note against these, as dynamically as possible.
At the moment, i'm adding on a query string in the routes. I.e. when viewing a customer there's an "Add Note" button like so:
route('note.create', ['customer_id' => $customer->id])
In my form then i'm checking for any query string's and adding them to the post request (in VueJS) which works.
Then in my controller i'm checking for each possible query string i.e.:
if($request->has('individual_id'))
{
$individual = Individual::findOrFail($request->individual_id_id);
// store against individual
// return note
}elseif($request->has('customer_id'))
{
$customer = Customer::findOrFail($request->customer_id);
// store against the customer
// return note
}
I'm pretty sure this is not the best way to do this. But, i cannot think of another way at the moment.
I'm sure someone else has come across this in the past too!
Thank you
In order to optimize your code, dont add too many if else in your code, say for example if you have tons of polymorphic relationship then will you add tons of if else ? will you ?,it will rapidly increase your code base.
Try instead the follwing tip.
when making a call to backend do a maping e.g
$identifier_map = [1,2,3,4];
// 1 for Customer
// 2 for Staff
// 3 for Users
// 4 for Individual
and so on
then make call to note controller with noteable_id and noteable_identifier
route('note.create', ['noteable_id' => $id, 'noteable_identifier' => $identifier_map[0]])
then on backend in your controller you can do something like
if($request->has('noteable_id') && $request->has('noteable_identifier'))
{
$noteables = [ 'Customers', 'Staff', 'Users','Individual']; // mapper for models,add more models.
$noteable_model = app('App\\'.$noteables[$request->noteable_identifier]);
$noteable_model::findOrFail($request->noteable_id);
}
so with these lines of code your can handle tons of polymorphic relationship.
Not sure about the best way but I have a similar scenario to yours and this is the code that I use.
my form actions looks like this
action="{{ route('notes.store', ['model' => 'Customer', 'id' => $customer->id]) }}"
action="{{ route('notes.store', ['model' => 'User', 'id' => $user->id]) }}"
etc..
And my controller looks this
public function store(Request $request)
{
// Build up the model string
$model = '\App\Models\\'.$request->model;
// Get the requester id
$id = $request->id;
if ($id) {
// get the parent
$parent = $model::find($id);
// validate the data and create the note
$parent->notes()->create($this->validatedData());
// redirect back to the requester
return Redirect::back()->withErrors(['msg', 'message']);
} else {
// validate the data and create the note without parent association
Note::create($this->validatedData());
// Redirect to index view
return redirect()->route('notes.index');
}
}
protected function validatedData()
{
// validate form fields
return request()->validate([
'name' => 'required|string',
'body' => 'required|min:3',
]);
}
The scenario as I understand is:
-You submit noteable_id from the create-form
-You want to remove if statements on the store function.
You could do that by sending another key in the request FROM the create_form "noteable_type". So, your store route will be
route('note.store',['noteableClass'=>'App\User','id'=>$user->id])
And on the Notes Controller:
public function store(Request $request)
{
return Note::storeData($request->noteable_type,$request->id);
}
Your Note model will look like this:
class Note extends Model
{
public function noteable()
{
return $this->morphTo();
}
public static function storeData($noteableClass,$id){
$noteableObject = $noteableClass::find($id);
$noteableObject->notes()->create([
'note' => 'test note'
]);
return $noteableObject->notes;
}
}
This works for get method on store. For post, form submission will work.
/**
* Store a newly created resource in storage.
*
* #param \Illuminate\Http\Requests\NoteStoreRequest $request
* #return \Illuminate\Http\Response
*/
public function store(NoteStoreRequest $request) {
// REF: NoteStoreRequest does the validation
// TODO: Customize this suffix on your own
$suffix = '_id';
/**
* Resolve model class name.
*
* #param string $name
* #return string
*/
function modelNameResolver(string $name) {
// TODO: Customize this function on your own
return 'App\\Models\\'.Str::ucfirst($name);
}
foreach ($request->all() as $key => $value) {
if (Str::endsWith($key, $suffix)) {
$class = modelNameResolver(Str::beforeLast($key, $suffix));
$noteable = $class::findOrFail($value);
return $noteable->notes()->create($request->validated());
}
}
// TODO: Customize this exception response
throw new InternalServerException;
}
I've an update form that contains an image and other data to be updated I changed the default route key to use the name instead of the default key which is the ID and I made a separate form request to validate my requests It works fine when posting new record unfortunately it keeps failing with the name field which is unique field; I've checked all threads on github and in stackoverflow with no use although I have the same project in laravel 5.5 and it works fine and now I'm stuck with laravel 6
hereis my form
let data = new FormData();
data.append('name', this.channel.name);
data.append('base_color', this.channel.baseColor);
data.append('complementary_color', this.channel.complementaryColor);
if (this.file){
data.append('avatar', this.file);
}
data.append('_method', 'PUT');
axios.post(`/dashboard/channels/${this.channel.name}`, data).then(resp => {
this.$parent.$emit('channel_updated', resp.data);
}).catch(error => {
flash(error.response.data, 'danger', 'backEndStyle');
});
and here is my route
Route::resource('/dashboard/channels', 'ChannelController');
and here is my form request
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class ChannelRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'name' => 'required|unique:channels,name,'. $this->id,
'base_color' => 'required',
'complementary_color' => 'required',
];
}
}
here is my controller for update method
public function update(Channel $channel, ChannelRequest $request)
{
$channel->update([
'name' => $request->name,
'bg_base_color' => $request->base_color,
'bg_complementary_color' => $request->complementary_color,
]);
return response($channel->fresh(), 200);
}
Use the ignore constraint to ignore the current model when validating unique
public function rules()
{
return [
'name' => ['required', Rule::unique('channels')->ignore($this->route('channel'))],
'base_color' => 'required',
'complementary_color' => 'required',
];
}
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:
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 in actionFilterEvents with null 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 the foreach with the relevant model field names that you will use instead of MyEvents.
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>