Yii: TbEditableColumn how to pass $data->id - php

I am trying to use the TbEditableColumn and the type select to have a pulldown menu.
The pulldown menu I need is filled by a function that I call.
That is working for basic cases. But for a another column, the pulldown values are dependent from the row in which it is (grid-view).
So for example the function I want to call to fill the pulldown and pass the id of the current data is:
$model->getPulldownValues($data->id)
But that throws an error that the variable $data is not defined. The funny part is that outside the editable array, I can use $data as expected.
See example below:
Any ideas?
$this->widget('bootstrap.widgets.TbExtendedGridView', array(
'type' => 'striped bordered',
'id'=>'order-image-grid',
'dataProvider'=>$model->search(),
'ajaxUpdate'=>true,
'template' => "{items}\n{extendedSummary}",
'rowCssClassExpression'=>'"FMDBGridColumn".$data->order_error',
'columns'=>array(
array(
'class' => 'bootstrap.widgets.TbEditableColumn',
'name' => 'streets',
'htmlOptions'=>array('width'=>'150'),
'value' => 'CHtml::value($data, "street")',
'editable' => array(
'type' => 'select',
'source' => CHtml::listData($model->availableStreets($data->id), 'id', 'street'),
'url' => $this->createUrl('cities/editable'),
'placement' => 'right',
)
),
),
));

Try to change method "availableStreets" into getter, e.g.:
public function getAvailableStreets()
{
// we don't need to send id as parameter of method,
// we can get it directly from model
// e.g.: $id = $this->id;
//
// put your code here
}
then, in widget, use property
$model->availableStreets
instead of method
$model->availableStreets($id)
Also you can put
CHtml::listData() into your getter and use
'source' => 'availableStreets',
instead of
'source' => CHtml::listData($model->availableStreets($data->id), 'id', 'street'),

you have to consider that $data in 'value' => 'CHtml::value($data, "street")', is referring to a model object which $model->search() is providing, but $data outside of the grid is different(You haven't shared what that is).

Related

Yii - Pass model ID into a view from CButtonColumn image

Alright, still new to Yii I am attempting to create a button in a column of CGridView. This button, when clicked, will take the user to the "view.php" page and display the information of the node they clicked on by passing in its ID.
I am frustrated that I cannot figure out how to simply add a link to the image that will direct my users. Here are some snippets of the code I have been working on for the past couple of days.
index.php
<?php echo CHtml::beginForm(); ?>
<?php
$pageSize = Yii::app()->user->getState('pageSize', Yii::app()->params['defaultPageSize']);
$this->widget('zii.widgets.grid.CGridView', array(
'id' => 'nodes-grid',
'dataProvider' => $model->search(),
'filter' => $model,
'columns' => array(
array(
'class' => 'CButtonColumn',
'template' => '{restart}',
'buttons' => array
(
'restart' => array
(
'label'=>'Restart this node',
'imageUrl'=>Yii::app()->baseUrl.'/images/refresh.png',
'options'=>array('id'=>'NB_bounce_Button'),
'url'=>array('view', 'id'=>$model->id),
)
),
),
/* 'id', */
'name',
'url',
'description',
'node_type',
'last_bounced',
//..
NodeBouncerController.php (View action)
/**
* Displays a particular model.
* #param integer $id the ID of the model to be displayed
*/
public function actionView($id) {
$this->render('view', array(
'model' => $this->loadModel($id),
));
}
The button is on the left. (Refresh green arrow)
What am I doing wrong? More specifically, am I using the buttons of CButtonColumn incorrectly? If so, how may I fix this?
My company uses: Yii v1.1.8.r3324
EDIT: [8/10/15]
It seems I may have been overcomplicating it. What I needed was to simply have an image-link that when clicked went to the view for that particular node that was clicked. Well, Gii auto-generates the particular view I needed and the code associated with it (as seen above).
My fix was to do away with the over complicated mess that I had and keep it simple. Use the template already provided for "view" and just alter it to my needs.
Like so:
/* 'id', */
array(
'class'=>'CButtonColumn',
'template'=>'{view}',
'buttons' => array
(
'view' => array
(
'label'=>'Restart this node',
'imageUrl'=>Yii::app()->baseUrl.'/images/refresh.png',
'options'=>array
(
'id'=>'NB_bounce_Button'
)
)
),
),
'name',
'url',
'description',
'node_type',
'last_bounced',
//....
It would be nice to know how to do this manually but I needed something to simply work for now and expand on it later for work.
I think the problem is url of the button. Because you did not include controllerID in the url. You should use this:
'url' => 'Yii::app()->createUrl("nodeBouncer/view", "id"=>$model->id)';
For creating url in yii, usually you should follow this pattern:
contollerID/actionID

Yii CGridView renders a new page instead of AJAX

In the index page of my site I have floating div-block with CGridView inside.
I need to use sort, filter, paging etc. options, but only via updating this only div and not refreshing the whole page.
Data rendering as it should, i'm stuck only with updating grid contents - all <a>'s have href, that sending user to specified view.
Here's the view for grid: (it's the only content of my views.users.usersGrid.php)
$this->widget('zii.widgets.grid.CGridView', array(
'dataProvider' => $model->search(),
'filter' => $model,
'ajaxUrl' => 'modules/subcntrl/usersGrid',
'ajaxUpdate' => 'users-grid',
'columns' => array(
array(
'name' => 'name',
'type' => 'raw',
'value' => 'CHtml::encode($data->name)'
),
array(
'class'=>'CButtonColumn',
),
),
));
It's called from views.users.users.php: <?php $this->actionUsersGrid(); ?>
Controller:
public function actionUsers() {
$this->renderPartial('users');
}
public function actionUsersGrid() {
if(!Yii::app()->request->isAjaxRequest) die('Url should be requested via ajax only');
$model = new Users();
$this->renderPartial('usersGrid',array(
'model' => $model,
));
}
Would appreciate any help
please use the third and fouth parameter in renderPartial method like this,
$this->renderPartial('users',array(),false,true);
it will solve your problem (setting the processOutput=true ) in the fourth parameter
please use the third and fouth parameter in renderPartial method like this,
$this->renderPartial('users',array(),false,true);
it will solve your problem (setting the processOutput=true ) in the fourth parameter
this is not working in my code. i am using like this in ma controler
$this->renderPartial('_searchQuote', array('model' => $model, 'month' => $month, 'user' => $user), false, $processOutput=false );

How do I create a CGridView with custom columns from a CArrayDataProvider?

I have an array of models that looks something like this. The models are extensions of the base Yii model class (BazClass), so that's a little bit of a custom solution, but I don't see why it shouldn't work.
$list = array
(
0 => FooClass#1
(
[BazClass:_attributes] => array
(
'FOO_ATTRIBUTE' => '4567'
'BAZ_ATTRIBUTE' => '1234'
'NAME' => 'FOO BAR'
)
[BazClass:_related] => array()
[_md] => null
[CModel:_errors] => array()
[CModel:_validators] => null
[CModel:_scenario] => ''
[CComponent:_e] => null
[CComponent:_m] => null
),
)
I made this a data provider by doing so:
$dataProvider = new CArrayDataProvider($list, array(
'pagination'=>array(
'pageSize'=>10,
),
));
$dataProvider->setData($list);
And try to render it in the view like so. Basically I'm just trying to show a list of the names, with the column named "Name".
$this->widget('zii.widgets.grid.CGridView', array(
'dataProvider'=>$dataProvider,
'columns'=>array(
array(
'header' => 'Name',
'value' => $data->NAME,
),
),
));
The examples in the CGridView documentation make it look like that is possible, but the error I get is:
Either "name" or "value" must be specified for CDataColumn.
Well, I did specify a value, obviously, but it seems to be null. I also tried $data['NAME'] (because I somewhere read that the CArrayDataProvider doesn't return models), but it still evaluates to null.
I also checked that $dataProvider->getData() returns the same list as I passed it.
What gives?
you should place quotes around your value otherwise it gets interpreted in the wrong context
array( 'header' => 'Name', 'value' => '$data->NAME', ),

Retain Checkbox values in Yii gridview pagination

I have a gridview which contains a checkbox column and also uses pagination. When I check some checkboxes in the first page and navigate to the second page and check another one in the second page, the options I checked in the first page is not retained there. Is it posssible to retain the checkbox values during pagination?
Code for Gridview is
$widget = $this->widget('zii.widgets.grid.CGridView', array(
'dataProvider' => $model->search(),
'cssFile' => Yii::app()->baseUrl . '/media/js/admin/css/admingridview.css',
//'filter' => $model,
'ajaxUpdate' => true,
'enablePagination' => true,
'columns' => array(
array(
'name' => 'id',
'header' => '#',
'value' => '$this->grid->dataProvider->pagination->currentPage * $this->grid->dataProvider->pagination->pageSize + ($row+1)',
),
array(
'class' => 'CCheckBoxColumn',
'selectableRows' => '2',
'header' => 'Selected',
),
array(
'name' => 'fb_user_id',
'header' => 'FaceBook Id',
'value' => 'CHtml::encode($data->fb_user_id)',
),
array(
'name' => 'first_name',
'header' => 'Name',
'value' => 'CHtml::encode($data->first_name)',
),
array(
'name' => 'email_id',
'header' => 'Email',
'value' => 'CHtml::encode($data->email_id)',
),
array(
'name' => 'demo',
'type' => 'raw',
'header' => "Select",
'value' => 'CHtml::checkBox("email[]","",array("class"=>"check","value"=>$data->email_id))',
),
),
));
Edit:
Extension for remembering the selected options in gridview,check this link Selgridview
Thanks to bool.dev
You could use sessions/cookies to store the checked values. I'm not very sure how to make cookies work, so i'll tell you how to do it with sessions. Specifically the user session that yii creates.
Now to use sessions we need to pass the checked (and unchecked) ids to the controller, therefore we'll modify the data being sent to the controller on every ajax update(i.e between paginations), to do this we exploit the beforeAjaxUpdate option of CGridView.
I'm also using CCheckBoxColumn instead of the following in your code(of course you can modify the solution to suit your own needs):
array(
'name' => 'demo',
'type'=>'raw',
'header' => "Select",
'value' => 'CHtml::checkBox("email[]","",array("class"=>"check","value"=>$data->email_id))',
),
GridView Changes:
<?php $this->widget('zii.widgets.grid.CGridView', array(
// added id of grid-view for use with $.fn.yiiGridView.getChecked(containerID,columnID)
'id'=>'first-grid',
'dataProvider'=>$model->search(),
'cssFile' => Yii::app()->baseUrl . '/media/js/admin/css/admingridview.css',
// added this piece of code
'beforeAjaxUpdate'=>'function(id,options){options.data={checkedIds:$.fn.yiiGridView.getChecked("first-grid","someChecks").toString(),
uncheckedIds:getUncheckeds()};
return true;}',
'ajaxUpdate'=>true,
'enablePagination' => true,
'columns' => array(
array(
'name' => 'id',
'header' => '#',
'value' => '$this->grid->dataProvider->pagination->currentPage * $this->grid->dataProvider->pagination->pageSize + ($row+1)',
),
array(
'name' => 'fb_user_id',
'header' => 'FaceBook Id',
'value' => 'CHtml::encode($data->fb_user_id)',
),
array(
'name' => 'first_name',
'header' => 'Name',
'value' => 'CHtml::encode($data->first_name)',
),
array(
'name' => 'email_id',
'header' => 'Email',
'value' => 'CHtml::encode($data->email_id)',
),
/* replaced the following with CCheckBoxColumn
array(
'name' => 'demo',
'type'=>'raw',
'header' => "Select",
'value' =>'CHtml::checkBox("email[]","",array("class"=>"check","value"=>$data->email_id))',
),
*/
array(
'class' => 'CCheckBoxColumn',
'selectableRows' => '2',
'header'=>'Selected',
'id'=>'someChecks', // need this id for use with $.fn.yiiGridView.getChecked(containerID,columnID)
'checked'=>'Yii::app()->user->getState($data->email_id)', // we are using the user session variable to store the checked row values, also considering here that email_ids are unique for your app, it would be best to use any field that is unique in the table
),
),
));
?>
Pay special attention to the code for beforeAjaxUpdate and CCheckBoxColumn, in beforeAjaxUpdate we are passing checkedIds as a csv string of all the ids(in this case email_ids) that have been checked and uncheckedIds as a csv string of all the unchecked ids, we get the unchecked boxes by calling a function getUncheckeds(), which follows shortly. Please take note here, that when i was testing i had used an integer id field (of my table) as the unique field, and not an email field.
The getUncheckeds() function can be registered like this anywhere in the view file for gridview:
Yii::app()->clientScript->registerScript('getUnchecked', "
function getUncheckeds(){
var unch = [];
/*corrected typo: $('[name^=someChec]') => $('[name^=someChecks]') */
$('[name^=someChecks]').not(':checked,[name$=all]').each(function(){unch.push($(this).val());});
return unch.toString();
}
"
);
In the above function pay attention to the selectors and each and push function.
With that done, we need to modify the controller/action for this view.
public function actionShowGrid(){
// some code already existing
// additional code follows
if(isset($_GET['checkedIds'])){
$chkArray=explode(",", $_GET['checkedIds']);
foreach ($chkArray as $arow){
Yii::app()->user->setState($arow,1);
}
}
if(isset($_GET['uncheckedIds'])){
$unchkArray=explode(",", $_GET['uncheckedIds']);
foreach ($unchkArray as $arownon){
Yii::app()->user->setState($arownon,0);
}
}
// rest of the code namely render()
}
That's it, it should work now.
For developing that scheme you would need to know working of what happens when you navigate.
When ever you navigate to a pagination page ajax calls are made and new data is received and it is fetched from CActive Record or what ever the data source. New data is in accordance of database records or source records. when you come back to previous page again Ajax call is made and content is updated so same comes as it is in database.
what i feel is you should save data of checked items temporary and make it permanent if action is made.
You can do something like this
<script type="text/javascript">
$("input:checkbox").click(function () {
var thisCheck = $(this);
if (thisCheck.is (':checked')){
// do what you want here, the way to access the text is using the
// $(this) selector. The following code would output pop up message with
// the selected checkbox text
$(this).val());
}
});
</script>
you can save temporary storage somewhere
Also make this work on normal form submit:
I wanted to add this as a comment on bool.dev's answer, but I do not have enough reputation to do that yet. So I had to put it in a separate answer.
bool.dev, your answer is great and it works well, thanx.
However, as intended, it only works when ajax calls update the gridview. I have the gridview forming part of a form, so I wanted it to also work on normal submission of the form, otherwise the checkboxes are not loaded again when there are other validation errors on the form.
So, in ADDITION to what you did, I added hidden fields on my form e.g.:
<input type="hidden" name='checkedBox1' id='checkedBox1' value=''>
<input type="hidden" name='uncheckedBox1' id='uncheckedBox1' value=''>
Then, before submitting the form, my sumbit button runs your getChecked() and getUncheckeds() functions and store their results in the hidden fields:
if ($('#checkedBox1').length >0) {$('[name=checkedBox1]').val(getChecked());}
if ($('#uncheckedBox1').length >0) {$('[name=uncheckedBox1]').val(getUncheckeds());}
In the controller, besides from checking for $_GET['checkedIds'], you also check for $_POST['checkedBox1'] and store its values to session in the same way you do for $_GET['checkedIds'], using the same session variable.
Do the same with $_POST['uncheckedBox1'].
That should work.

Yii - CGridView - add own attribute

$this->widget('zii.widgets.grid.CGridView', array(
'dataProvider'=>$dataProvider,
'columns'=>array(
'title', // display the 'title' attribute
'category.name', // display the 'name' attribute of the 'category' relation
'content:html', // display the 'content' attribute as purified HTML
array( // display 'create_time' using an expression
'name'=>'create_time',
'value'=>'date("M j, Y", $data->create_time)',
),
array( // display 'author.username' using an expression
'name'=>'authorName',
'value'=>'$data->author->username',
//HERE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
'htmlOptions'=>array('class'=>'$data->author->username', 'secondAttribute' => $data->author->id),
//HERE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
),
array( // display a column with "view", "update" and "delete" buttons
'class'=>'CButtonColumn',
),
),
));
In option value i can add variable from PHP, but for option htmlOptions this is not possible. Why?How can i make attribute with PHP variable?
When you add arrays in the columns collection without specifying a class property, the type of column being created is CDataColumn. The property CDataColumn::value is explicitly documented to be
a PHP expression that will be evaluated for every data cell and whose
result will be rendered as the content of the data cells.
Therefore, value has the special property that it gets eval'ed for each row and that's why you can set it "dynamically". This is an exception however, and almost nothing else supports the same functionality.
However, you are in luck because the property cssClassExpression is another special exception that covers exactly this usage case. So you can do it like this:
array(
'name'=>'authorName',
'value'=>'$data->author->username',
'cssClassExpression' => '$data->author->username',
),
Edit: I made a mistake while copy/pasting from your example and did not notice that you were trying to do the same thing for additional attributes inside htmlOptions (I have now deleted the relevant part of the code).
If you need to add more options for dynamic values you have no choice but to subclass CDataColumn and override the renderDataCell method (stock implementation is here).
Don't know if this still applies or not (given that there is an accepted answer), but there is a slightly better solution in the form of "rowHtmlOptionsExpression". This specifies an expression that will be evaluated for every row. If the result of the eval() call is an array, it will be used as the htmlOptions for the <tr> tag. So you can basically now use something like this:
$this->widget('zii.widgets.grid.CGridView', array
(
...
'rowHtmlOptionsExpression' => 'array("id" => $data->id)',
...
All your tags will have an id attribute with the records' PK.
Just modify the jQuery slightly to obtain the id from that tag instead of an extra column and you should be set.
Extend the class CDataColumn
Under protected/components/ create the file DataColumn.php with the following content:
/**
* DataColumn class file.
* Extends {#link CDataColumn}
*/
class DataColumn extends CDataColumn
{
/**
* #var boolean whether the htmlOptions values should be evaluated.
*/
public $evaluateHtmlOptions = false;
/**
* Renders a data cell.
* #param integer $row the row number (zero-based)
* Overrides the method 'renderDataCell()' of the abstract class CGridColumn
*/
public function renderDataCell($row)
{
$data=$this->grid->dataProvider->data[$row];
if($this->evaluateHtmlOptions) {
foreach($this->htmlOptions as $key=>$value) {
$options[$key] = $this->evaluateExpression($value,array('row'=>$row,'data'=>$data));
}
}
else $options=$this->htmlOptions;
if($this->cssClassExpression!==null)
{
$class=$this->evaluateExpression($this->cssClassExpression,array('row'=>$row,'data'=>$data));
if(isset($options['class']))
$options['class'].=' '.$class;
else
$options['class']=$class;
}
echo CHtml::openTag('td',$options);
$this->renderDataCellContent($row,$data);
echo '</td>';
}
}
We can use this new class like this:
$this->widget('zii.widgets.grid.CGridView', array(
'id' => 'article-grid',
'dataProvider' => $model->search(),
'filter' => $model,
'columns' => array(
'id',
'title',
array(
'name' => 'author',
'value' => '$data->author->username'
),
array(
'class' => 'DataColumn',
'name' => 'sortOrder',
'evaluateHtmlOptions' => true,
'htmlOptions' => array('id' => '"ordering_{$data->id}"'),
),
array(
'class' => 'CButtonColumn',
),
),
));

Categories