New to yii2 and PHP, ran into a break here.
Based on this and this post, I tried recreating the AJAX call.
Right now, using the Kartik SwitchInput widget, I'm at least trying to get the value into the controller and then return it to another place on the index page.
Here's what's in the view
...
<?= GridView::widget([
'dataProvider' => $customers,
'columns' => [
...
[
'label' => 'Status',
'format' => 'raw',
'attribute' => 'status',
'value' => function($models){
return SwitchInput::widget([
'name' => $models->id,
'value' => $models->status,
'pluginEvents' => [
'switchChange.bootstrapSwitch' => 'function(e) {
$.ajax({
method: "POST",
url: "'.Url::to(['update-status']).'",
data: { "status": e.currentTarget.checked, "id": e.currentTarget.name },
error:function(res){
console.log(res.responseText);
}
})
console.log(`${e.currentTarget.checked} ${e.currentTarget.name}`);
}'
]
...
Here's the controller:
class CustomerController extends Controller{
public function actionIndex(){
$customers = new ActiveDataProvider([
'query' => Customer::find()
]);
$models = $customers->getModels();
return $this->render('index', [
'customers' => $customers,
'models' => $models
]);
}
public function actionUpdateStatus(){
$status = Yii::$app->request->post('status');
$id = Yii::$app->request->post('id');
return $this->renderPartial('index', [
'status' => $status,
'id' => $id
]);
}
}
Whenever I flip the switch, it returns a 500 Internal error. Console.logging it revealed: $customers is undefined.
From what I realised, whenever I make an actionUpdateStatus call, Yii re-renders the view completely anyway, and tries to find the $customers, which isn't in the UpdateStatus.
How do I return the switch data, separately, back into the same view, then?
I posted one of the answers you mentioned, and i havent specified one thing there which is reloading of the gridview which wasnt the requirement there, but can be done using $.pjax.
A few things you need to look at
You dont need any view for the updateStatus action as per your requirement.
You just need to return some status code to the ajax call that you are using inside the gridView for the switch input, and refresh your gridview to load the new updated status.
In ajax success callback function check if that status code is ok then you should refresh the gridview rather than using render partial.
And you are not updating anything in the updateStatus? you need to switch the status
So change your action to the following
public function actionUpdateStatus()
{
try {
$status = Yii::$app->request->post('status');
$id = Yii::$app->request->post('id');
$model = Customer::findOne($id);
$model->status=$status;
if(!$model->save()){
throw new Exception(implode("\n",\yii\helpers\ArrayHelper::getColumn($model->errors,'0'));
}
return $this->asJson(['success' => true]);
} catch (Exception $e) {
return $this->asJson(['success' => false, 'message' => $e->getMessage()]);
}
}
Make sure you have wrapped the GridView inside Pjax start and end and add an id to the Pjax widget
<?php
Pjax::begin(['id'=>'pjax-container']);
echo GridView::widget([
'dataProvider' => $customers,
'columns' => [
.......
]);
Pjax::end();
?>
And your ajax call to the following
'switchChange.bootstrapSwitch' => 'function(e) {
$.ajax({
method: "POST",
url: "'.Url::to(['update-status']).'",
dataType:'json',
data: { "status": e.currentTarget.checked, "id": e.currentTarget.name },
success:function(data){
if(data.success){
$.pjax({container: "#pjax-container"});
}else{
console.log(data.message);
}
},
error:function(res){
console.log(res.responseText);
}
});
}'
Related
I'm trying to use the select option to create an event with a Modal with the selected date using Full Calendar - Philippfrenzel but I don't know how.
I already have an event Click which works but that it's not what I really want.
Controller:
public function actionRequisitar(){
$searchModel= new RequisicaoSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
$events = [];
foreach(Requisicao::find()->all() as $requisicao){
$event = new \yii2fullcalendar\models\Event();
$event->id = $requisicao->id;
$event->title = $requisicao->motivo_requisicao;
$event->start = $requisicao->data_inicio_req;
$events[] = $event;
}
return $this->render('requisitar',[
'events'=>$events,
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
]);
}
public function actionCreate()
{
$model = new Requisicao();
//$model->data_inicio_req=$date;
if ($model->load(Yii::$app->request->post()) && $model->save()) {
return $this->redirect(['view', 'id' => $model->id, 'utilizador_id' => $model->utilizador_id, 'sala_id' => $model->sala_id]);
}
return $this->renderAjax('create', [
'model' => $model,
]);
}
Index:
<?= \yii2fullcalendar\yii2fullcalendar::widget(array(
'events' => $events,
'id' => 'calendar',
));
?>
Main.js
$(function () {
$('#modalButton').click(function () {
$('#modal').modal('show')
.find('#modalContent')
.load($(this).attr('value'));
});
$(document).on('click', '.fc-day', function () {
var date = $(this).attr('data-date');
$.get('index.php?r=requisicao/create', {'date': date}, function (data) {
$('#modal').modal('show')
.find('#modalContent')
.load(data);
});
});
});
Inside the configuration of Index where you setup the fullcalendar widget:
<?= \yii2fullcalendar\yii2fullcalendar::widget(array(
'events' => $events,
'id' => 'calendar',
));
?>
You must add the property eventClick that triggers an JS function once an event is clicked.
You can do it like this:
<?= \yii2fullcalendar\yii2fullcalendar::widget(array(
'events' => $events,
'id' => 'calendar',
'eventClick' => new JsExpression('(event) => handleClick(event)'),
));
?>
Notice that handleClick has to be a real function that is declared in your javascript, you could change handleClick(event) for console.log(event) to check if it is working as you expect before creating the function.
I'm working on a program that is a reservation service for lab systems using Yii2.0. I've been using Yii for a little while but for some reason this one is stumping me
I have all of the systems listed in a gridview and I'd like to have a button in the actionColumn that will run the 'reserve' action and then show the view for the individual system.
I have the button added and it brings the user to the view page but I don't know what I need to do to have it run the reserve action first...or if it's even possible. I've tried pointing it to the reserve action in the controller but of course that looks for a view page rather than an action.
Here's some of the code from what I've been trying after looking through many pages of suggestions:
On the index page
['class' => 'yii\grid\ActionColumn',
'template' => '{reserve}',
'buttons' => [
'reserve' => function ($url, $model) {
return Html::a('<span class="glyphicon glyphicon-ok-circle"></span>',
$url,
[
'title' => 'Reserve',
'data-method' => 'post',
'data-pjax' => 0,
]);
}
],
'urlCreator' => function ($action, $model, $key, $index) {
return Url::toRoute(['cml/view', 'id' => $key]);
}
Function in Controller
public function actionReserve($id)
{
$model = $this->findModel($id);
if ($model->fkReservedTo == 1)
{
$model->fkReservedTo = Yii::$app->user->id;
// shouldn't you call save here
$model->save();
return $this->redirect(['view','id'=>$id]);
}
else
{
Yii::$app->session->setFlash('error', 'This system is not available to be reserved');
return $this->showAlert();
}
}
Any suggestions would be appreciated.
Change
return Url::toRoute(['cml/view', 'id' => $key]);
to
return Url::toRoute(['cml/reserve', 'id' => $key]);
in your urlCreator function.
I have a problem with my advanced template when I try to change page using internationalization.
I try to explain. To use the internationalization on my site I have follow this steps:
In params.php, I have added this:
<?php
return [
'adminEmail' => 'admin#example.com',
'languages' => [
'en' => 'English',
'it' => 'Italian',
],
];
I have added this in my frontend\views\layouts\main.php to call on my website the languages insert above:
<?php
foreach(Yii::$app->params['languages'] as $key => $language){
echo '<span class="language" id ="'.$key.'">'.$language.' | </span>';
}
?>
after I have created a new file named main.js. To permit to yii2 to see the main.js file I added this in the AppAsset.php (is it correct?). In this file I insert this:
$(function(){
$(document).on('click','.language', function(){
var lang = $(this).attr('id');
$.post('index.php?r=site/language', {'lang':lang},function(data){
location.reload();
});
});
$(document).on('click','.fc-day', function(){
var date = $(this).attr('data-date');
$get('index.php?r=event/create',{'date':date},function(data){
$('#modal').modal(show)
.find('#modalContent')
.html(data);
});
});
$('#modalButton').click(function(){
$('#modal').modal(show)
.find('#modalContent')
.load($(this).attr('value'));
});
});
after that in the sitecontroller.php I have added this:
public function actionLanguage()
{
if(isset($_POST['lang'])){
Yii::$app->language = $_POST['lang'];
$cookie = new Yii\web\cookie([
'name'=>'lang',
'value'=>$_POST['lang']
]);
Yii::$app->getResponse()->getCookies()->add($cookie);
}
}
after in config\main.php I have added this in components:
'components' => [
'i18n' => [
'translations' => [
'app' => [
'class' => 'yii\i18n\PhpMessageSource',
//'basepath' => #app/messages,
'sourceLanguage' => 'it',
'fileMap' => [
'app' => 'app.php',
'app/error' => 'error.php',
],
],
],
],
finally i have create on the root a folder called messages\it and messages\en and inside two files (one per folder) called app.php I have insert this text:
<?php
return [
'Benvenuto' => 'Welcome'
];
that's all...but after load my home page (correctly) when i click on one of the languages (Italian or English) I see the following messages:
jquery.js?ver=1.11.3:4 POST http://localhost/mdf/frontend/web/index.php?r=site/language 400 (Bad Request)
And If I try to paste directly this url, I obtain only a blank page:
http://localhost/mdf/frontend/web/index.php?r=site/language
This is only a partial response to your question
The blank page when you invoke using browser could be related to the fact that you don't render nothings in this case.
try manage the ajax this way
public function actionLanguage()
{
if (Yii::$app->request->isAjax) {
$data = Yii::$app->request->post();
if(isset($data['lang'])) {
Yii::$app->language = $data['lang'];
$cookie = new Yii\web\cookie([
'name'=>'lang',
'value'=>$_POST['lang']
]);
Yii::$app->getResponse()->getCookies()->add($cookie);
return;
}
} else {
return $this->render('index', []);
}
}
I am trying to access a variable on view file into Gridview but it is throwing error that it should be array but null given i am declaring $totalDays on top of my view file and i am using it in Gridview like below
[
'attribute' => 'class_id',
'format' => 'raw',
'label' => "Class Date",
'value' => function ($model) {
array_push($totalDays,$model->class->date);
return $model->class->date;
},
'footer'=> '<span>Total Days</span>',
],
But it throws following error
array_push() expects parameter 1 to be array, null given
To explain, $totalDays is not available in the widget because the whole function only gets run when the widget is rendered, $totalDays is no longer declared. As #arogachev hinted above, you will need to make $totalDays in your model, then you can access it. Try this in your model;
public function getTotalDays(){
//Your logic here to generate totalDays
return $totalDays;
}
Then you can use it in your view like this;
[
'attribute' => 'class_id',
'format' => 'raw',
'label' => "Class Date",
'value' => function ($model) {
array_push($model->totalDays, totalDays,$model->class->date);
return $model->class->date;
},
'footer'=> '<span>Total Days</span>',
],
Insert use after function signature in value callable function:
[
'attribute' => 'class_id',
'format' => 'raw',
'label' => "Class Date",
'value' => function ($model) use($totaleDays) {
array_push($totalDays,$model->class->date);
return $model->class->date;
},
'footer'=> '<span>Total Days</span>',
],
As #Fabrizio said. Insert use after function signature in value callable function:
'value' => function ($model) use($totaleDays) {
array_push($totalDays,$model->class->date);
return $model->class->date;
},
For multiple value to pass in to value function you can use as below.
'value' => function ($model) use($var1, $var2....., $varN) {
array_push($totalDays,$model->class->date);
return $model->class->date;
},
Like this use($var1, $var2....., $varN)
While you can definetely pass this variable through use section of closure, it's wrong in your code. MVC principle is violated, because view it's only for display, and you exposing logic such as array_push.
I'd recommend to refactor it and place data calculation in model, so you can simply call return $model->yourMethod(); and it will return desired data.
After an ajax request i got one array from my controller as response, how can I use this array values in my dropdown list?
Answer
in my view I have
echo CHtml::dropDownList('client_id', '',CHtml::listData($model,'client_id','client_name'), array(
'ajax'=> array(
'type'=>'POST',
'url'=>Yii::app()->baseUrl.'/index.php?r=page/dynamicDropdownList',
'update'=>'#program_id',
'empty'=>'-Select a Client-')));
// I need to populate the response array in this dropdownlist
echo CHtml::dropDownList('program_id','', CHtml::listData($result,'program_id', 'program_name'));
in my controller
public function actionDynamicDropdownList()
{
if($_POST['client_id'] > '0') {
$result = Yii::app()->db->createCommand()->select('program_id, program_name')->from('program')->where('client_id='.$_POST['client_id'].'')->order('program_name')->queryAll();
$this->render('admin', array(
'result' => $result,
));
}
}
Another Problem
Now I got everything working except the second drop downlist is also showing the values of 1st dropdown list with the result.
solution:- I have parse the response and show it in the dropdownlist
This is how your controller should look like:
public function actionIndex() {
$model = new SearchForm();
if ($_GET['SearchForm']) {
$model->attributes = $_GET['SearchForm'];
}
//here is where you put your criteria or query commands
if ($_GET['ajax']) {
$this->renderPartial('index', array(
'model' => $model,
));
} else {
$this->render('index', array(
'model' => $model,
));
}
}
You catch the data from ajax or GET and you do something with it, then you pas the data to the view;
And this should be what the vies contains:
<? echo $form->dropDownList($model, 'position_type', CHtml::listData(PositionType::model()->findAll(array('condition' => 'status=1')), 'id', 'name'), array('class' => 'postdropdown2', 'empty' => array(-1 => 'All'), 'onchange' => 'showDiv(this.value,1);')); ?>
You have to work with data received using ajax in the controller, as it is not visible in the view, if it was not passed using render or renderpartial