Editable
Creates single editable element. Use it when you want to edit data not related with CModel.
Example
Widget source
<?php $this->widget('editable.Editable', array( 'type' => 'text', 'name' => 'user_name', 'pk' => 1, 'text' => 'John', 'url' => $this->createUrl('site/updateUser'), 'title' => 'Enter user name', 'placement' => 'right' )); ?>
EditableField
Makes editable single attribute of model. Attribute should be safe (e.g. defined in rules()
method of model)
It can be one of following types:
1. Text
Example
(try empty value to test validation)
Widget source
<?php $this->widget('editable.EditableField', array( 'type' => 'text', 'model' => $user, 'attribute' => 'user_name', 'url' => $this->createUrl('site/updateUser'), 'placement' => 'right', )); ?>
In model User.php
public function rules() { return array( array('user_name', 'required'), //make user_name safe and required ... ); }
2. Textarea
Example
Widget source
<?php $this->widget('editable.EditableField', array( 'type' => 'textarea', 'model' => $user, 'attribute' => 'user_comment', 'url' => $this->createUrl('site/updateUser'), 'placement' => 'right', 'showbuttons' => 'bottom', )); ?>
3. Select (load items from array)
Example
Widget source
<?php $this->widget('editable.EditableField', array( 'type' => 'select', 'model' => $user, 'attribute' => 'user_status', 'url' => $this->createUrl('site/updateUser'), 'source' => Editable::source(Status::model()->findAll(), 'status_id', 'status_text'), //or you can use plain arrays: //'source' => Editable::source(array(1 => 'Status1', 2 => 'Status2')), 'placement' => 'right', )); ?>
4. Select (load items from url)
Example
Widget source
<?php $this->widget('editable.EditableField', array( 'type' => 'select', 'model' => $user, 'attribute' => 'user_status_ext', 'url' => $this->createUrl('site/updateUser'), 'source' => $this->createUrl('site/getStatusList'), //you can also use js function returning string url //'source' => 'js: function() { return "?r=site/getStatusList"; }', 'placement' => 'right', )); ?>
Action site/GetStatusList
public function actionGetStatusList() { echo CJSON::encode(Editable::source(Status::model()->findAll(), 'status_id', 'status_text')); }
5. Date
Example
Widget source
<?php $this->widget('editable.EditableField', array( 'type' => 'date', 'model' => $user, 'attribute' => 'user_dob', 'url' => $this->createUrl('site/updateUser'), 'placement' => 'right', 'format' => 'yyyy-mm-dd', //format in which date is expected from model and submitted to server 'viewformat' => 'dd/mm/yyyy', //format in which date is displayed )); ?>
In model rules()
array('user_dob', 'default', 'value' => null), //make user_dob safe and convert "" to null
i18n:
For Bootstrap datepicker you should include lang file from here and set option language
$this->widget('editable.EditableField', array( ... 'options' => array( 'datepicker' => array('language' => 'ru') ) )); Yii::app()->clientScript->registerScriptFile(Yii::app()->baseUrl.'/js/bootstrap-datepicker.ru.js', CClientScript::POS_END);
For jQuery UI datepicker you just should include lang file from here.
Yii::app()->clientScript->registerScriptFile(Yii::app()->baseUrl.'/js/jquery.ui.datepicker-ru.js', CClientScript::POS_END);
6. Datetime (bootstrap only!)
Example
Widget source
<?php $this->widget('editable.EditableField', array( 'type' => 'datetime', 'model' => $user, 'attribute' => 'user_visit', 'url' => $this->createUrl('site/updateUser'), 'placement' => 'right', 'format' => 'yyyy-mm-dd hh:ii:ss', //database datetime format 'viewformat' => 'dd/mm/yyyy hh:ii', //format for display )); ?>
In model rules()
array('user_visit', 'default', 'value' => null), //make attribute safe and convert "" to null
7. Combodate
Example
Widget source
<?php $this->widget('editable.EditableField', array( 'type' => 'combodate', 'model' => $user, 'attribute' => 'user_reserve', //define value directly as it should match the format of combodate: Y-m-d H:i --> YYYY-MM-DD HH:mm 'value' => isset($user->user_visit) ? date('Y-m-d H:i', strtotime($user->user_visit)) : '', 'url' => $this->createUrl('site/updateUser'), 'placement' => 'right', 'format' => 'YYYY-MM-DD HH:mm', //in this format date sent to server 'viewformat' => 'MMM DD, YYYY HH:mm', //in this format date is displayed 'template' => 'DD / MMM / YYYY HH:mm', //template for dropdowns 'combodate' => array('minYear' => 1980, 'maxYear' => 2013), )); ?>
In model rules()
array('user_reserve', 'default', 'value' => null), //make attribute safe and convert "" to null
8. Checklist
Example
Widget source
<?php $this->widget('editable.EditableField', array( 'type' => 'checklist', 'model' => $user, 'attribute' => 'user_params', 'placement' => 'right', 'url' => $this->createUrl('site/updateUser'), 'source' => array('pretty', 'awesome', 'smart', 'ambitious'), )); ?>
In model User.php
public function rules() { return array( array('user_params', 'implodeParams'), //define custom validator to implode checked values into string ... ); } public function implodeParams($attribute) { if(is_array($this->$attribute)) { $this->$attribute = implode(',', $this->$attribute); } }
Value is stored in db as comma separated string of values, e.g. "1,3,4"
.
9. Select2
Example
Widget source
<?php $tags = array( array('id' => 1, 'text' => 'php'), array('id' => 2, 'text' => 'html'), array('id' => 3, 'text' => 'css'), array('id' => 4, 'text' => 'javascript'), ); $this->widget('editable.EditableField', array( 'type' => 'select2', 'model' => $user, 'attribute' => 'user_tags', 'url' => $this->createUrl('site/updateUser'), 'source' => $tags, 'placement' => 'right', 'select2' => array( 'multiple' => true ) )); ?>
In model rules()
public function rules() { return array( array('user_tags', 'implodeParams'), //define custom validator to implode checked values into string ... ); } public function implodeParams($attribute) { if(is_array($this->$attribute)) { $this->$attribute = implode(',', $this->$attribute); //in db it is stored as string e.g. '1,3,4' } }
EditableDetailView
Makes editable several attributes of single model, shown as name-value table.
Just define editable
section inside attribute config. Only safe attributes become editable.
1. Existing record
User Name | yiiuser |
---|---|
Group | |
Status | |
Date of birth | |
Language | France |
Comment | No comments.. |
Created | 2012-09-09 01:26:06 |
Source (equal for both cases)
<?php $this->widget('editable.EditableDetailView', array( 'data' => $user, //you can define any default params for child EditableFields 'url' => $this->createUrl('site/updateUser'), //common submit url for all fields 'params' => array('YII_CSRF_TOKEN' => Yii::app()->request->csrfToken), //params for all fields 'emptytext' => 'no value', //'apply' => false, //you can turn off applying editable to all attributes 'attributes' => array( array( 'name' => 'user_name', 'editable' => array( 'type' => 'text', 'inputclass' => 'input-large', 'emptytext' => 'special emptytext', 'validate' => 'function(value) { if(!value) return "User Name is required (client side)" }' ) ), array( //select loaded from database 'name' => 'group_id', 'editable' => array( 'type' => 'select', 'source' => Editable::source(Group::model()->findAll(), 'group_id', 'group_name') ) ), array( //select loaded from ajax. 'name' => 'user_status', 'editable' => array( 'type' => 'select', 'source' => $this->createUrl('site/getStatuses'), ) ), array( 'name' => 'user_dob', 'editable' => array( 'type' => 'date', 'viewformat' => 'dd/mm/yyyy' ) ), array( //edit related record 'name' => 'profile.language', 'editable' => array( 'url' => array('site/updateProfile') //related record requires own submit url ) ), 'user_comment', 'created_at', //will not be editable as attribute is not safe ) )); ?>
For new record you just pass to widget instance of new model, e.g. $user = new User;
.
When you click on Save button all values are collected, validated and submitted to server (you can find more details here).
Onclick handler can be set as following:
<? if($user->isNewRecord) { Yii::app()->clientScript->registerScript('new-user', ' $("#save-btn").click(function() { $(this).parent().parent().find(".editable").editable("submit", { url: "'.$this->createUrl('site/createUser').'", data: '.CJSON::encode(array('YII_CSRF_TOKEN' => Yii::app()->request->csrfToken)).', ajaxOptions: { dataType: "json" }, success: function(data, config) { if(data && data.id) { $(this).editable("option", "pk", data.id); $(this).removeClass("editable-unsaved"); $("#msg").removeClass("alert-error").addClass("alert-success") .html("User created! Now you can update it.").show(); $("#save-btn").hide(); } else { config.error.call(this, data && data.errors ? data.errors : "Unknown error"); } }, error: function(errors) { var msg = ""; if(errors && errors.responseText) { msg = errors.responseText; } else { $.each(errors, function(k, v) { msg += v+"<br>"; }); } $("#msg").removeClass("alert-success").addClass("alert-error") .html(msg).show(); } }); }); '); } ?>
Server-side action to create new record:
public function actionCreateUser() { if(Yii::app()->request->isPostRequest) { $model = new User; $model->attributes = $_POST; if($model->save()) { echo CJSON::encode(array('id' => $model->primaryKey)); } else { $errors = array_map(function($v){ return join(', ', $v); }, $model->getErrors()); echo CJSON::encode(array('errors' => $errors)); } } else { throw new CHttpException(400, 'Invalid request'); } }
EditableColumn
Makes editable one column in GridView. Grid stays editable after ajax sorting and pagination.
Parameters are defined in editable
section of column config.
Since 1.1 works with both CActiveDataProvider and CArrayDataProvider.
Example
User Name | Status | Date of birth | Comment | User language |
---|---|---|---|---|
user5 | ||||
yiiuser | No comments.. | France |
Source
<? $this->widget('bootstrap.widgets.TbGridView', array( 'id' => 'usergrid', 'itemsCssClass' => 'table-bordered items', 'dataProvider' => $dataProvider, 'columns'=>array( array( 'class' => 'editable.EditableColumn', 'name' => 'user_name', 'headerHtmlOptions' => array('style' => 'width: 110px'), 'editable' => array( //editable section 'apply' => '$data->user_status != 4', //can't edit deleted users 'url' => $this->createUrl('site/updateUser'), 'placement' => 'right', ) ), array( 'class' => 'editable.EditableColumn', 'name' => 'user_status', 'headerHtmlOptions' => array('style' => 'width: 100px'), 'editable' => array( 'type' => 'select', 'url' => $this->createUrl('site/updateUser'), 'source' => $this->createUrl('site/getStatuses'), 'options' => array( //custom display 'display' => 'js: function(value, sourceData) { var selected = $.grep(sourceData, function(o){ return value == o.value; }), colors = {1: "green", 2: "blue", 3: "red", 4: "gray"}; $(this).text(selected[0].text).css("color", colors[value]); }' ), //onsave event handler 'onSave' => 'js: function(e, params) { console && console.log("saved value: "+params.newValue); }', //source url can depend on some parameters, then use js function: /* 'source' => 'js: function() { var dob = $(this).closest("td").next().find(".editable").text(); var username = $(this).data("username"); return "?r=site/getStatuses&user="+username+"&dob="+dob; }', 'htmlOptions' => array( 'data-username' => '$data->user_name' ) */ ) ), array( 'class' => 'editable.EditableColumn', 'name' => 'user_dob', 'headerHtmlOptions' => array('style' => 'width: 100px'), 'editable' => array( 'type' => 'date', 'viewformat' => 'dd.mm.yyyy', 'url' => $this->createUrl('site/updateUser'), 'placement' => 'right', ) ), array( 'class' => 'editable.EditableColumn', 'name' => 'user_comment', 'editable' => array( 'type' => 'textarea', 'url' => $this->createUrl('site/updateUser'), 'placement' => 'left', ) ), //editable related attribute with sorting. //see http://www.yiiframework.com/wiki/281/searching-and-sorting-by-related-model-in-cgridview array( 'class' => 'editable.EditableColumn', 'name' => 'virtual_field', 'value' => 'CHtml::value($data, "profile.language")', 'editable' => array( 'type' => 'text', 'attribute' => 'profile.language', 'url' => $this->createUrl('site/updateProfile'), 'placement' => 'left', ) ), ), )); ?>
ListView
You can use usual CListView with editable items.
Example
Source views / listview
<?php $widget = $this->widget('bootstrap.widgets.TbListView', array( 'id' => 'listview', 'dataProvider' => $dataProvider, 'itemView' => 'listviewitem', )); //for update editables after ajax sort and pagination Editable::attachAjaxUpdateEvent($widget); ?>
Source views / listviewitem
<div style="float: left; width: 30%; border: solid 1px gray; margin: 10px; padding: 3px"> Username: <?php $this->widget('editable.EditableField', array( 'type' => 'text', 'model' => $data, 'attribute' => 'user_name', 'url' => $this->createUrl('site/updateUser'), 'placement' => 'right', 'liveTarget' => $widget->id, //for live update )); ?> <br> Status: <?php $this->widget('editable.EditableField', array( 'type' => 'select', 'model' => $data, 'attribute' => 'user_status', 'url' => $this->createUrl('site/updateUser'), 'source' => $this->createUrl('site/getStatuses'), 'placement' => 'right', 'liveTarget' => $widget->id, //for live update )); ?> </div> <? if(($index+1) % 3 == 0): ?> <div style="clear: both"></div> <? endif; ?>
Options
These options are passed as configuration array into EditableField or into editable
section of EditableDetailView and EditableColumn.
Please refer to X-editable docs for the most detailed description (options marked with x-editable).
Name | Type | Default | Description | Related |
---|---|---|---|---|
apply | boolean | null | whether to apply 'editable' js plugin to element. Only safe attributes become editable. | Yii |
attribute | string | required | attribute name. | Yii |
cssFile | mixed | 'jquery-ui.css' | for jQuery UI only. The theme CSS file name. By default Yii's jquery UI css used. | Yii |
disabled | boolean | false | will editable be initially disabled. It means editable plugin will be applied to element, but you should call .editable('enable') method to activate it. To totally disable applying 'editable' to element use apply option. | x-editable |
emptytext | string | null | text shown on empty field. If null - default X-editable value is used: Empty | x-editable |
encode | boolean | true | whether to HTML encode text on output | Yii |
format | string | null | format to send date on server. If null - default X-editable value is used: yyyy-mm-dd . | x-editable |
htmlOptions | array | array() | HTML options of element. In EditableColumn htmlOptions are PHP expressions so you can use $data to bind values to particular cell, e.g. `'data-categoryID' => '$data->categoryID'`. | Yii |
inputclass | string | null | css class of input. If null - default X-editable value is used: input-medium | x-editable |
liveSelector | string | null | jQuery selector of elements to wich will be applied editable. Usefull in combination of | Yii |
liveTarget | string | null | DOM id of target where afterAjaxUpdate handler will call live update of editable element | Yii |
mode | string | null | mode of input: inline | popup . If not set - default X-editable value is used: popup . | x-editable |
model | CActiveRecord | required | ActiveRecord to be updated. | Yii |
name* | string | null | name of field | x-editable |
options | array | array() | all config options of x-editable. See full list here. | Yii |
params | array | null | additional params to send on server | x-editable |
pk* | mixed | null | primary key | x-editable |
placement | string | null | placement of popup. Can be left , top , right , bottom . If null - default X-editable value is used: top | x-editable |
send | string | null | Strategy for sending data on server. Can be auto|always|never . When 'auto' data will be sent on server only if pk and url defined, otherwise new value will be stored locally. | x-editable |
showbuttons | string | null | visibility of buttons. Can be boolean false|true or string bottom . | x-editable |
source | mixed | null | source data for select, checklist. Can be string (url) or array in format: array( array("value" => 1, "text" => "abc"), ...) | x-editable |
text* | string | null | text to be shown as element content | Yii |
theme | string | 'base' | for jQuery UI only. The JUI theme name. | Yii |
themeUrl | string | for jQuery UI only. The root URL that contains JUI theme folders. If not set, default Yii's theme will be used. | Yii | |
title | string | null | title of popup. If null - will be generated automatically from attribute label. Can have token {label} inside that will be replaced with actual attribute label. | Yii |
type | string | null | type of editable widget. Can be text , textarea , select , date , checklist , etc. | x-editable |
url | string | null | url to submit value. Can be string or array containing Yii route, e.g. array('site/updateUser') | x-editable |
value | mixed | null | initial value. If not set - will be taken from text | x-editable |
viewformat | string | null | format to display date in element. If null - equals to format option. | x-editable |
* - required only for raw Editable class. Not used for other classes as CModel provides these data automatically.
Callbacks
Name | Description | Related |
---|---|---|
validate | A javascript function that will be invoked to validate value. Example: 'validate' => 'js: function(value) { if($.trim(value) == "") return "This field is required"; }' | x-editable |
success | A javascript function that will be invoked to process successful server response. Example: 'success' => 'js: function(response, newValue) { if(!response.success) return response.msg; }' | x-editable |
display | A javascript function that will be invoked to custom display value. Example: 'display' => 'js: function(value, sourceData) { var escapedValue = $("<div>").text(value).html(); $(this).html("<b>"+escapedValue+"</b>"); }' | x-editable |
Events
Please see also Events tab of X-editable docs.
Name | Description | Related |
---|---|---|
onInit | A javascript function that will be invoked when editable element is initialized | x-editable |
onShown | A javascript function that will be invoked when editable form is shown
Example:
'onShown' => 'js: function() { var $tip = $(this).data("editableContainer").tip(); $tip.find("input").val("overwriting value of input."); }' | x-editable |
onSave | A javascript function that will be invoked when new value is saved
Example:
'onSave' => 'js: function(e, params) { alert("Saved value: " + params.newValue); }' | x-editable |
onHidden | A javascript function that will be invoked when editable form is hidden
Example:
'onHidden' => 'js: function(e, reason) { if(reason === "save" || reason === "cancel") { //auto-open next editable $(this).closest("tr").next().find(".editable").editable("show"); } }' | x-editable |