📜 ⬆️ ⬇️

Context-sensitive form in yii

When working with frameworks, you always have to create the basic functionality yourself, preferably using the capabilities of the framework (why then do we need it). As the title implies, we’ll talk about context-sensitive forms in Yii. The article describes the implementation of this form using a modal window. I hope that this option will be useful to someone.

Looking ahead, I’ll say that the result should be such a field, a drop-down menu and a button on the right to select the necessary data.



Context-sensitive selection window:
')


After selection:



Why was the option with a modal window chosen? This allows you to simplify the selection of the desired item. In a modal window, you can display CGridView, while you can sort, search and filter data, which is very convenient if you have to choose from a large number of elements.
So, the ingredients for making this Yii scissors:

Now, be patient and start cooking.

Suppose we have a menuController.php controller, a viewform _form.php file and a Menu.php model. I will not dwell on who is who, all this is standard, automatically generated code Gii , Gee.

Model (Menu.php)


We first clarify how the model works. We assume that we have a bundle of data type and ID, which is tied to the data type. The model (as well as in the database) must contain the type and data_id fields , both integral. For convenience, when loading the model, we will load the name of the object to which it refers (needed when editing the object). Suppose in the data_name field. Check the necessary frauds in the afterFind () function. Also make the list of data types more dynamic. We define a static array in the class, so if we need to expand or narrow the type options, we will only edit the model class.
Since we use ActiveRecord, in fact, you only need to know the name of the model and view to work with a specific data type.

static $types = array( 1 => array("name" => "", "model" => "Pages", "view" => "pages_grid"), 2 => array("name" => "", "model" => "Docs", "view" => "docs_grid"), 3 => array("name" => "", "model" => "Cats", "view" => "cats_grid"), ); public static function getSimpleTypes() { //   .   DropDownList $st = array(); foreach (Menu::$types as $key => $value) $st[$key] = $value["name"]; return $st; } var $data_name; public function afterFind() { $dataModel = $types[$this->type]['model']::model()->findByPk($this->data_id); $this->data_name = $dataModel->title; //   $data_name    parent::afterFind(); } 

At the end of this review model.

View form (_form.php)


We look view file of our form _form.php

 <!--    --> <?php $form=$this->beginWidget('bootstrap.widgets.TbActiveForm',array( 'id'=>'menu-form', 'enableAjaxValidation'=>false, 'type' => 'horizontal', )); ?> <!--       --> <?php echo $form->errorSummary($model);?> <?php echo $form->textFieldRow($model,'name');?> <!--  ,    data_id --> <?php echo $form->textField($model,'data_id',array('class'=>'hide')); ?> <!--        bootstrap--> <div class="control-group"> <div class="control-label"> <?=$form->labelEx($model,'type')?> </div> <div class="controls"> <div class="input-append"> <?php echo $form->dropDownList($model,'type',Menu::getSimpleTypes());?> <button class="btn" id="data-select-btn" data-loading-text="..." type="button"><i class="icon-list"></i></button> </div> </div> </div> <!--   ,    .     Update,   ,  --> <div id="data-info" class="alert alert-success controls <?if($model->isNewRecord):?>hide<?endif;?>"> <i class="icon-file"></i> <span class="info"> <?if(!$model->isNewRecord) echo $model->data_name?> </span> </div> <!--  /--> <div class="form-actions"> <?php $this->widget('bootstrap.widgets.TbButton', array( 'buttonType'=>'submit', 'type'=>'primary', 'label'=>$model->isNewRecord ? 'Create' : 'Save', )); ?> </div> <?php $this->endWidget(); ?> <!--      --> <?php $this->beginWidget('bootstrap.widgets.TbModal', array('id'=>'dataModal')); ?> <div class="modal-header"> <a class="close" data-dismiss="modal">×</a> <h4><?=Yii::t("menu", " ")?></h4> </div> <div class="modal-body"></div> <div class="modal-footer"> <?php $this->widget('bootstrap.widgets.TbButton', array( 'label'=>Yii::t("menu", ""), 'url'=>'#', 'htmlOptions'=>array('data-dismiss'=>'modal'), )); ?> </div> <?php $this->endWidget(); ?> <script> //       function selectData(id, name) { $("#Menu_data_id").val(id); $("#data-info .info").html(name); $("#data-info").show(); $('#dataModal').modal("hide"); } //  data_id     $('#Menu_type').change(function(){ $("#Menu_data_id").val(""); $("#data-info").hide(); }) //         ,   AJAX $('#data-select-btn').click(function(){ var buttn = this; $(buttn).button('loading'); $.ajax({ url: "<?php echo $this->createAbsoluteUrl('menu/loadData') ?>", cache: false, data: "type="+$("#Menu_type").val(), success: function(html){ $(".modal-body").html(html); $(buttn).button('reset'); $('#dataModal').modal().css({ width: 'auto', 'margin-left': function () { return -($(this).width() / 2); }, }); } }); }) </script> 

Actually this is the entire form file. The main elements here are our field and function for AJAX data request.
As you can see, the data retrieval function accesses the menu / loadData action . Let's see what he does:

Controller (menuController.php)


  public function actionLoadData($type) { $model_name = Menu::$types[$type]['model']; $model = new $model_name('search'); //      if(isset($_GET[$model_name])) //          $model->attributes=$_GET[$model_name]; $this->renderPartial(Menu::$types[$type]['view'],array( 'model'=>$model, ), false, true); //   $processOutput = true,      . } 

It is worth noting that you need to set the parameter $ processOutput = true for the renderPartial function, otherwise the scripts connected by the widgets in the view file will not be loaded.
You also need to clarify a very important point, when setting the $ processOutput parameter, all files will be uploaded, including those that have already been connected on the main page, which is very critical in the case of, for example, JQuery. Therefore, I advise you to install the NLSClientScript extension, it will check that all files are connected once.

View file for modal window (docs_grid.php)


View files should be stored in the designated folder of the controller, i.e. in our case it will be / protected / views / menu
Now let's analyze one of the view files for the modal window. You can use any convenient form to select data, the main thing is that it works through the model object. I like the CGridView because it has everything you need: search, pagination and sorting.

 $this->widget('bootstrap.widgets.TbGridView',array( 'id'=>'docs-grid', 'dataProvider'=>$model->search(), 'filter'=>$model, 'columns'=>array( 'id', 'title', 'updated', array( 'class'=>'CButtonColumn', 'template' => "{insert}", 'buttons' => array( "insert" => array( 'label' => "", 'options' => array( "class" => "btn btn-mini btn-success", "onclick" => 'selectData($(this).parent().parent().children(":nth-child(1)").text(),$(this).parent().parent().children(":nth-child(2)").text());', ) ), ) ), ), )); 

There is nothing superfluous, one single grid with item selection buttons. The example uses a bootstrap grid, but you can use a standard CGridView.
But there is one trick. As you noticed, there is a nondescript script on the item selection button that tears out the id and title of the item from the table. Unfortunately, the GridView widget does not allow to operate with data of a single record. Therefore, it is necessary in this way to get the necessary id and title , which are passed to the selectData function described in the view _form.php file.

That's all. In order to add a new data type, it is enough to add one more line in the array created in the Menu.php model and write or generate, with the help of Gii, the ActiveRecord model for the new type.

Source: https://habr.com/ru/post/178303/


All Articles