YiiBooster
YiiBooster copied to clipboard
TbEditable column not rendering after update to initially blank gridview
Hi
I have a TbExtendedGridview that uses some TbEditableColumns. The initial state of the gridview is that it has no results. I then populate the table via a dialog popup form which inserts the data in the background via ajax and updates the GridView using $.fn.yiiGridView.update(id);. Once the grid has finished updating it shows the data but the TbEditableColumns do not render correctly.
I am fairly sure this is due to there being no table rows when the GridView is first rendered so there is no initial javascript coming from the TbEditableColumn. When the GridView is updated via ajax and new data is displayed, the .editable javascript just isn't there to use.
I was hoping someone might point me in the right direction for a quick fix/workaround for this problem while still being able to dynamically update the GridView via ajax?
@angelcoding I don't know exact method calls but if I were you, and I were in need of quick workaround, I would find a way to fetch TbEditableColumn
s via ajax, too, and re-eval all relevant scripts along the way. Basically it means to re-implement the TbEditableColumn
initialization forcefully on the client side, though.
@hijarian Thanks for the quick response. I'll see if something like that will work...
I cheated in the end and did this slightly nasty hack by extending the TbEditableColumn class ...
Yii::import('bootstrap.widgets.TbEditableColumn');
class ETbEditableColumn extends TbEditableColumn {
public function init() {
parent::init();
// If we have no records ...
// render some fake data (without displaying it) so the necessary javascript is added for the column
if(!$this->grid->dataProvider->totalItemCount) {
ob_start();
$this->renderDataCellContent(0, $this->grid->dataProvider->model);
$fakeRow = ob_get_clean();
}
}
}
This basically forces the column to render the javascript even if no records are found. Obviously the best way would be for all necessary javascript to be added to the init() function rather than relying on the renderDataCellContent() method to display it. Perhaps something like this can be added in the not too distant future?
While the solution by @angelcoding from Feb 16, 2013 didn't work out of the box for me (perhaps because I'm using an older version of YiiBooster), the following did work for my case:
<?php
Yii::import('bootstrap.widgets.TbEditableColumn');
class ETbEditableColumn extends TbEditableColumn {
public function init() {
parent::init();
// If we have no records
if(!$this->grid->dataProvider->totalItemCount) {
$options = CMap::mergeArray(
$this->editable,
array(
'model' => $this->grid->dataProvider->model,
'attribute' => $this->name,
'parentid' => $this->grid->id,
)
);
$widget = $this->grid->controller->createWidget('TbEditableField', $options);
//manually make selector non unique to match all cells in column
$selector = str_replace('\\', '_',get_class($widget->model)) . '_' . $widget->attribute;
$widget->htmlOptions['rel'] = $selector;
//manually render client script (one for all cells in column)
$script = $widget->registerClientScript();
//use parent() as grid is totally replaced by new content
Yii::app()->getClientScript()->registerScript(
__CLASS__ . '#' . $this->grid->id . $selector . '-event',
'$("#' . $this->grid->id . '").parent().on("ajaxUpdate.yiiGridView", "#' . $this->grid->id . '", function() {' . $script . '});'
);
}
}
}
I think this implementation is a bit closer to what @angelcoding was thinking when he said he'd rather "all necessary javascript to be added to the init() function rather than relying on the renderDataCellContent() method to display it." In any case, maybe it'll help someone else.