Dependent fields yii2 - yii2

I need 2 dependent fields in framework Yii2 Example:
I want when i insert in "Numero de Personas"= 5 or other numeric value, automatically "Consumo de Agua"= 2 * "Numero de Personas" = 10.
I saw onchange yii2 but i don't know how use it, i think onchange yii2 is an alternative.
<?= $form->field($model, 'NUM_PERSONAS')->textInput(['maxlength' => true]) ?>
<?= $form->field($model, 'AGUA_CONSUMO')->textInput(['maxlength' => true]) ?>
Update:
With 2 calculated fields example:
$("#consumo-form #{$aguaId},#consumo-form #{$personaId}").on("keyup", function (e) {
var persona = $("#consumo-form #{$personaId}").val();
var agua = $("#consumo-form #{$aguaId}").val();
$("#consumo-form #{$indConsumoAguaM}").val(persona*agua)
});

Here is the approach i would use:
in your view:
<?php
$personaId = Html::getInputId($model, 'NUM_PERSONAS');
$aguaId = Html::getInputId($model, 'AGUA_CONSUMO');
?>
<!-- Begin of form -->
<?= $form->field($model, 'NUM_PERSONAS')->textInput(['maxlength' => true]) ?>
<?= $form->field($model, 'AGUA_CONSUMO')->textInput(['maxlength' => true]) ?>
<!-- End of form -->
<?php
$js = <<<JS
$("#my-form-id #{$personaId}").on("keyup", function (e) {
var persona = $(this).val();
$("#my-form-id #{$aguaId}").val(persona*2)
});
$("#my-form-id #{$aguaId}").on("keyup", function (e) {
var agua = $(this).val()%2 == 0 ? $(this).val() : $(this).val() - 1;
$("#my-form-id #{$personaId}").val(agua/2)
});
JS;
$this->registerJs($js);
With that, both fields will try to auto-complete after the other being changed. But, just to be safe, we need to add a validation on model's rules also.
In your Model:
public function rules()
{
return [
// Your rules
[['NUM_PERSONAS', 'AGUA_CONSUMO'], 'checkValues']
];
}
public function checkValues($attribute)
{
$persona = $this->NUM_PERSONAS;
$agua = $this->AGUA_CONSUMO%2 == 0 ? $this->AGUA_CONSUMO : $this->AGUA_CONSUMO - 1;
if ($persona != $agua/2) {
$this->addError($attribute, 'Error message');
}
}

Related

Dependend dropdowns not refreshing properly in Yii2

I have a problem that's driving me mad. I have two Select2-Dropdowns showing employees, one for dayshift, the other for nightshift. The employee selected for dayshift should be removed from the nightshift dropdown and vice versa. I managed to refresh the nightshift dropdown when an employee is selected in the dayshift dropdown, but when I select an employee in the nightshift dropdown he isn't removed from the dayshift dropdown...
here's the snippet from the _form.php:
<?= $form->field($model, 'customer_id')->widget(Select2::classname(), [
'options'=>['id'=>'customer-id','class'=>'customer-id shift-name'],
'disabled' => !$create_jn,
'data' => ArrayHelper::map(customer::find()->where(['active_yn' => 1])->orderBy(['name'=>SORT_ASC])->all(),'customer_id','name')
]); ?>
<?=
$form->field($model, 'site_id')->widget(DepDrop::classname(), [
'options'=>['id'=>'site-id','class'=>'site-id shift-name'],
'disabled' => $disable_yn,
'type' => DepDrop::TYPE_SELECT2,
'pluginOptions'=>[
'depends'=>['cutomer-id'],
'placeholder'=>'Please choose',
'url'=>Url::to(['/site/customer-site']),
// 'initialize'=>true,
]]);
?>
<?= $form->field($model, 'site_employee_id')->widget(DepDrop::classname(), [
'options'=>['id'=>'site-employee-id'],
'disabled' => $disable_yn,
'type' => DepDrop::TYPE_SELECT2,
'pluginOptions'=>[
'depends'=>['customer-id'],
'placeholder'=>'Please choose',
'url'=>Url::to(['/site/customer']),
'params' => ['site-employee-night-id'],
// 'initialize'=>true,
]
]); ?>
<?= $form->field($model, 'bst_leiter_nacht_id')->widget(DepDrop::classname(), [
'options'=>['id'=>'site-employee-night-id'],
'disabled' => $disable_yn,
'type' => DepDrop::TYPE_SELECT2,
'pluginOptions'=>[
'depends'=>['customer-id','site-employee-id'],
'placeholder'=>'Please choose',
'url'=>Url::to(['/site/customer-night']),
'params' => ['site-employee-id'],
'initialize'=>true,
]
]); ?>
and here's the controller:
public function actionCustomer() {
Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
$out=array();
if (isset($_POST['depdrop_parents'])) {
$parents = $_POST['depdrop_parents'];
if (isset($_POST['depdrop_params'])) {
$params = $_POST['depdrop_params'];
if ($parents != null) {
$customer_id = $parents[0];
if($params != null) {
$site_employee_night_id = $params[0];
$out= \frontend\models\Employee::find()
->where(['customer_id'=>$customer_id])
->andWhere(['<>','employee_id', $site_employee_night_id])
->select(['employee_id as id','CONCAT(firstname," ",lastname) as name'])
->orderBy('lastname')->asArray()->all();
return ['output'=>$out, 'selected'=>''];
}
}
}
}
return ['output'=>'', 'selected'=>''];
}
public function actionCustomerNight() {
Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
$out=array();
if (isset($_POST['depdrop_parents'])) {
$parents = $_POST['depdrop_parents'];
if (isset($_POST['depdrop_params'])) {
$params = $_POST['depdrop_params'];
if ($parents != null) {
$customer_id = $parents[0];
if($params != null) {
$site_employee_id = $params[0];
$out= \frontend\models\Employee::find()
->where(['customer_id'=>$customer_id])
->andWhere(['<>','employee_id', $site_employee_id])
->select(['employee_id as id','CONCAT(firstname," ",lastname) as name'])
->orderBy('lastname')->asArray()->all();
return ['output'=>$out, 'selected'=>''];
}
}
}
}
return ['output'=>'', 'selected'=>''];
}
Any help, tips, hints would be highly appreciated.
The problem might be that night shift dropdown depends on dayshift dropdown and gets refreshed when dayshift one is changed. Since dayshift dropdown depends only on customer-id it won't be refreshed (function in controller wont refresh data) when you change night shift dropdown.
On nightshift add onchange event and trigger refresh manually

Validation error on custom model attributes not displayed in form

I have a model with the following custom attributes topic_names, topic_details (string fields). I have also a model form with the custom attributes and custom rules. When I insert wrong data in the form fields, there is a model error, but it isn't displayed.
Model code:
......
public function rules()
{
return [
...
[['topics_names','topics_details'],'string'],
[['topics_names'],'checkCorrectAndSetTopics'],
];
}
public function checkCorrectAndSetTopics(){
if($this->topics_names AND $this->topics_details){
$topicsNamesArray = explode(',',$this->topics_names);
$topicsDetailsArray = explode(';',$this->topics_details);
if(sizeof($topicsNamesArray) !== sizeof($topicsDetailsArray)){
$this->addError('topics_names', \Yii::t('app', 'The topics names and details sets have different sizes'));
return FALSE;
}
}
return TRUE;
}
The problem is when the second rules is violeted, the form doesn't show any error, but there is. I checked it debugging the code below.
Form code:
..........
<?php
ActiveForm::$autoIdPrefix = createRandomId();//Function which creates a random id
$form = ActiveForm::begin(
['enableAjaxValidation' => true, "options"=> ["class"=>"extra-form"]]);
?>
<?= $form->errorSummary($model); ?>
<?= $form->field($model, 'topics_names')->textInput()
->label(\Yii::t('app', 'Topics Names'))?>
<?= $form->field($model, 'topics_details')->textarea(['rows' => 6])
->label(\Yii::t('app', 'Topics Details'))?>
........
Controller code:
public function actionAddExtraData($id){
if(!Yii::$app->request->isAjax){
throw new ForbiddenHttpException(\Yii::t('app','Cannot access this action directly.'));
}
$event = $this->findModel($id);
$extraData = ExtraData::find()
->andWhere(['event_id'=>$id])
->one();
if(!$extraData){
$extraData = new ExtraData();
$extraData->event_id = $id;
}else{
$extraData->prePerformForm();//Insert data on custom attributes
}
if(Yii::$app->request->isPost AND Yii::$app->request->isAjax AND Yii::$app->request->post("submitting") != TRUE
AND $extraData->load(Yii::$app->request->post())){
Yii::$app->response->format = Response::FORMAT_JSON;
$validation = ActiveForm::validate($extraData);
return $validation;
}
if ($extraData->load(Yii::$app->request->post()) && $extraData->save()) {
if (Yii::$app->request->isAjax) {
Yii::$app->response->format = Response::FORMAT_JSON;
return ["success" => TRUE];
} else {
return $this->redirect(Yii::$app->request->referrer);
}
}
return $this->renderAjax('_event_extra_form',['model'=>$extraData,'event'=>$event]);
}
First thing, pretty sure you don't need to return true or false, you just need to add error. Second thing, in your example you name the attribute, you can actually get this when defining the function, so your function could look something like this
public function checkCorrectAndSetTopics($attribute, $model){
if($this->topics_names AND $this->topics_details){
$topicsNamesArray = explode(',',$this->topics_names);
$topicsDetailsArray = explode(';',$this->topics_details);
if(sizeof($topicsNamesArray) !== sizeof($topicsDetailsArray)){
$this->addError($attribute, \Yii::t('app', 'The topics names and details sets have different sizes'));
}
}
}

How to update field in user table yii2

I have modified user table to add one column, the column's name is id_periode, I have advanced template, so from backend controler i want update that column value. I create controller like this
public function actionPindahPeriode($id)
{
$model2 = $this->findModel2($id);
if ($model2->load(Yii::$app->request->post()) ) {
$model2->save();
return $this->render('view',
'model2' => $this->findModel2($id),
]);
}
date_default_timezone_set('Asia/Makassar');
$jam_sekarang = date('h:i:s', time());
$tgl_sekarang=date('Y-m-d');
$model_periode = Periode::find()
->andWhere(['>','mulai_daftar_ulang',$tgl_sekarang ])
->asArray()
->all();
return $this->renderAjax('pindah_periode', [
'model_periode' => $model_periode,
'model2' => $this->findModel2($id),
]);
}
The findModel2 function is like this
protected function findModel2($id)
{
if (($model = User::findOne($id)) !== null) {
return $model;
}
throw new NotFoundHttpException('The requested page does not exist.');
}
I render that model into a form
<?php $form = ActiveForm::begin(); ?>
<?php $listData=ArrayHelper::map($model_periode,'id',function($model_periode){
return $model_periode['nama_periode'].' Tahun '.$model_periode['tahun'];});?>
<?= $form->field($model2, 'id_periode')->dropDownList($listData, ['prompt' => '']) ?>
<div class="form-group">
<?= Html::submitButton('Save', ['class' => 'btn btn-danger']) ?>
</div>
<?php ActiveForm::end(); ?>
The form is working but i can not update the value id_periode column in table user. There is not error showing, any suggestion?
Make sure your new attribute id_periode has a rule defined in the public function rules(){} function, this way $model2->load(Yii::$app->request->post()) will assign this value from the data submitted.
$model->save() returns a bool value whether the record was saved or not. You can use this to your advantage and check whether there are any validation errors.ie:
if($model2->save()) {
return $this->render('view',
'model2' => $this->findModel2($id),
]);
} else {
return $this->renderAjax('pindah_periode', [
'model_periode' => $model_periode,
'model2' => $this->findModel2($id),
]);
}
Option 1 : Check your column fields in User model's validation rules. You need to shift unwanted column fields from required attribute to safe attribute.
Option 2 : try $model2->save(false);. false will override your model rules.

Dependent Dropdown in Yii2 lost values on Update

I created a form with a dropdownlist dependent on another (without extensions) and it ran fast.
But when you try to change the same form, the value of the second drop-down list is lost (type_id). Basically the Type field depends on the selected Area. See my code:
_form.php
<?= $form->field($model, 'area_id')->dropDownList(ArrayHelper::map(Department::find()->where(['helpdesk' => 1])->all(),'id','name'),['prompt'=>'Selecione a Área',
'onchange' => '
$.post("index.php?r=helpdesk/solicitation/lists&id=' . '"+$(this).val(),function(data){
$("select#solicitation-type_id").html(data);
});']) ?>
<?php
echo $form->field($model, 'type_id')->dropDownList(['prompt'=>'Selecione a Área']);
?>
Controller
public function actionLists($id)
{
$countType = Type::find()
->where(['area_id' => $id])
->count();
$types = Type::find()
->where(['area_id' => $id])
->orderBy(['name' => SORT_ASC])
->all();
if($countType > 0 )
{
foreach($types as $type ){
echo "<option value='".$type->id."'>".$type->name."</option>";
}
}
else{
echo "<option> - </option>";
}
}
I think it's the same problem at this topic, but I did not understand how it worked.
you need to provide the default set of options from which it should select the saved option whereas you are not providing any data
<?php
$types = Type::find()
->where(['area_id' => $model->area_id])
->orderBy(['name' => SORT_ASC])
->all();
echo $form->field($model, 'type_id')->dropDownList(ArrayHelper::map($types,'id','name'),['prompt'=>'Selecione a Área']);
?>
Now when you will use findOne() and select the model the saved value for the type_id will be automatically selected.
You can move the above query in the controller/action and pass the $types to the view.
also you can make you method actionLists D.R.Y by using count($types) and remove the first query
public function actionLists($id)
{
$types = Type::find()
->where(['area_id' => $id])
->orderBy(['name' => SORT_ASC])
->all();
if(count($types) > 0 )
{
foreach($types as $type ){
echo "<option value='".$type->id."'>".$type->name."</option>";
}
}
else{
echo "<option> - </option>";
}
}

How to make dependent dropdownlist in Yii2?

I'm trying to make a dependend dropDownList in Yii2. I'm trying to use DepDrop Widget, but I can't understand how to edit the code according to my situation. I have 1 model and inside of it I need to make category dropdown list and according to the category_id, the next dropDownList should be Item. (F.e If I select category 1, the Item should be Item1 and so on).
I guess that extension only can do dropdowns of the same model? I'm new to Yii2, so.
My view file:
<div class="site-create">
<?php $form = ActiveForm::begin(); ?>
<?= $form->field($model, 'code') ?>
<?= $form->field($category, 'id')->dropDownList($category, ['id'=>'category-id']); ?>
<?= $form->field($item, 'subcat')->widget(DepDrop::Item(), [
'options'=>['id'=>'item-id'],
'pluginOptions'=>[
'depends'=>['category-id'],
'placeholder'=>'Select...',
'url'=>Url::to(['/site/subcat'])
]
]); ?>
My $model is different model from $category and $item. I set those variables to use a different model in the action
Here is my action:
public function actionSubcat() {
$category = new Category();
$item = new Item();
$out = [];
if (isset($_POST['depdrop_parents'])) {
$parents = $_POST['depdrop_parents'];
if ($parents != null) {
$cat_id = $parents[0];
$out = self::getSubCatList($cat_id);
echo Json::encode(['output'=>$out, 'selected'=>'']);
return $this->render('create', [
'category' => $category,
'item' => $item,
]);
}
}
echo Json::encode(['output'=>'', 'selected'=>'']);
}
}
Now I'm getting the error message that the $category variable is undefined. Could someone explain me what I'm doing wrong?
Actually you dont need any Widgets or Plugins. In yii2 you can easily do Dependent Dropdown list here is example:
echo $form->field($search,'category')->dropDownList(
ArrayHelper::map(
\app\models\Category::find()->all(),
'id','name'
),
[
'prompt' => Yii::t('app','choose_city'),
'onchange'=>'
$.get( "'.Yii::$app->urlManager->createUrl('site/dropdown?id=').'"+$(this).val(), function( data ) {
$( "select#subcat" ).html( data );
})'
]
);
echo $form->field($search, 'sub_category', ['inputOptions'=>['id'=>'subcat',]])->dropDownList([]);
after that you need to create action for returning action. Example:
public function actionDropdown($id)
{
$countPosts = \app\models\SubCategory::find()
->where(['category_id' => $id])
->count();
$posts = \app\models\SubCategory::find()
->where(['category_id' => $id])
->orderBy('name ASC')
->all();
echo "<option value=''>-</option>";
if($countPosts>0){
foreach($posts as $post){
echo "<option value='".$post->id."'>".Yii::t('app',$post->name)."</option>";
}
}
}
thats all.
i suggest using knockoutjs for doing this. i answered a similar question here
knockout example is here (category > product)
html:
<select data-bind="options: data, value: selected, optionsText: 'title', optionsCaption: '---'"></select>
<select data-bind="options: dependent"></select>
javascript:
<script>
function viewmodel() {
var self = this;
this.data = [
{ title: 'title a', items: ['a1', 'a2', 'a3'] },
{ title: 'title b', items: ['b1', 'b2', 'b3'] },
{ title: 'title c', items: ['c1', 'c2', 'c3'] }
];
this.selected = ko.observable();
this.dependent = ko.computed(function() {
return ((self.selected() || {}).items || []);
});
}
$(document).ready(function() {
ko.applyBindings(new viewmodel());
});
</script>
you can still use $form->field, just add 'data-bind' attribute as inputOption.
if you want to use the field's default values, Json::encode those key-value-pairs and create the viewmodel like this:
ko.applyBindings(new viewmodel(<?= Json::encode($data) ?>));
using those parameters is javascript manual labour
<?= $form->field(**$category**, 'id')->dropDownList(**$category_dropdown**, ['id'=>'category-id']); ?>
Both the names are not same:
$category = your model
$category_dropdown = arrayhelper variable in your action
like below
$transactioncategory = ArrayHelper::map(Transactioncategory::find()->all(), 'id', 'transaction_category');