yii2 from validation on array form elements - yii2

I've a form containing array elements and I've to validate it. i cant validate it by using the in-built validation rules, because the elements are not present in the database. i'm serialising the data and save them in a single field in database. so i tried to do the validation with custom validation.
my actual problem is the array field is validating but it doesn't shows the validation error message in the corresponding field.
This is the form
<div class="col-md-6">
<?php Portlet::begin(['title' => t('Shipper')]) ?>
<?= $form->field($model, 'shipper[name]')
->textInput(['maxlength' => true])->label(t('Name'))?>
<div class="row">
<div class="col-md-8">
<?= $form->field($model, 'shipper[address_line1]')
->textInput(['maxlength' => true])->label(t('Address Line 1')) ?>
<?= $form->field($model, 'shipper[address_line2]')
->textInput(['maxlength' => true])->label(t('Address Line 2')) ?>
</div>
<div class="col-md-4">
<?= $form->field($model, 'shipper[city]')
->textInput(['maxlength' => true])->label(t('City')) ?>
<?= $form->field($model, 'shipper[pin]')
->textInput(['maxlength' => true])->label(t('Pin Code')) ?>
</div>
</div>
Model
.....
['shipper', function ($attribute, $params) {
if (!filter_var($this->{$attribute}['email'], FILTER_VALIDATE_EMAIL)) {
$this->addError('shipper', 'The email format is invalid!');
}
}],
....

You could add attributes to your model class like the following:
class MyModel extends \yii\db\ActiveRecord {
public $shipperAddressLine1;
public $shipperAddressLine2;
public $shipperCity;
public $shipperPin;
...
}
Then you can add validation rules for them just like your database attributes.

Related

Yii2 how to format <sup> tags in forms and GridView?

I have an attributeLabels for an attribute that has a <sup> tag:
public function attributeLabels() {
return [
'density' => Yii::t('yii', 'density (kg/dm<sup>3</sup>)'),
];
}
In the view it looks appropriate, but in the form and in the GridView as label it's simply like (kg/dm<sup>3</sup>)
I have tried to add labelOptions with many different format values to it, but no luck.
<?= $form->field($model, 'density', ['labelOptions' => ['format' => '(html/text/raw etc.)']])->textInput() ?>
Is it possible to make it look like a real <sup> (kg/dm3) text in the form, and if yes, can you please tell me how? Thank you.
Call it like that:
<?= $model->getAttributeLabel('density'); ?>
<?= $form->field($model, 'density')->textinput()->label(false) ?>
and after that format your template
Edit (better way):
<?= $form->field($model, 'density', ['labelOptions' => ['label' => $model->getAttributeLabel('density')]])->textinput() ?>

Cakephp 3.0 - using Chronos and datetimepicker, how to input a date without time?

In my Cakephp3.0 app, I use Chronos and datetimepicker.
In my Entity file, I have:
#property \Cake\I18n\Time $purchase_date
In my Table, I put this:
use Cake\ORM\Query;
use Cake\ORM\RulesChecker;
use Cake\ORM\Table;
use Cake\Validation\Validator;
Then for the Validator:
$validator
->date('purchase_date', ['mdy'])
->allowEmpty('purchase_date');
In edit.ctp, I put this:
<?= $this->Form->input('purchase_date', ['empty' => true]) ?>
When I click on the glyphicon-calendar button, I keep getting a value including the time, like : "10/17/2017, 01:58 PM".
What should I do to input only Date in this format: "10/17/2017" ?
Thanks in advance.
instead of:
<?= $this->Form->input('purchase_date', ['empty' => true]) ?>
This code worked for me:
<div class='input-group date' id='datetimepicker6'><?= $this->Form->input('purchase_date', ['format' => 'mdy', 'empty' => true]) ?></div>

Yii2: How to validate a form with multiple instances of the same model

In my form I update more start and end dates from the same model at once. See the simplified form:
<?php $form = ActiveForm::begin(); ?>
<?php foreach($dates as $i=>$date): ?>
<?= $form->field($date,"[$i]start"); ?>
<?= $form->field($date,"[$i]end"); ?>
<?php endforeach; ?>
</table>
<?= Html::submitButton('Save'); ?>
<?php ActiveForm::end(); ?>
In the model I need to control, if the end date is after the start date:
public function rules() {
return [
[['end'], 'compare', 'compareAttribute' => 'start', 'operator' => '>', 'message' => '{attribute} have to be after {compareValue}.‌'],
];
}
I tried to change selectors similarly as described in: Yii2: Validation in form with two instances of same model, but I was not successful. I suppose I need to change the 'compareAttribute' from 'mymodel-start' to 'mymodel-0-start' in the validation JS:
{yii.validation.compare(value, messages, {"operator":">","type":"string","compareAttribute":"mymodel-start","skipOnEmpty":1,"message":"End have to be after start.‌"});}
So, I look for something like:
$form->field($date,"[$i]end", [
'selectors' => [
'compareAttribute' => 'mymodel-'.$i.'-start'
]
])
Solution
The solution is based on the answer of lucas.
In the model I override the formName() method, so for every date I have a unique form name (based on ID for the existing dates and based on random number for new dates):
use ReflectionClass;
...
public $randomNumber;
public function formName()
{
$this->randomNumber = $this->randomNumber ? $this->randomNumber : rand();
$number = $this->id ? $this->id : '0' . $this->randomNumber;
$reflector = new ReflectionClass($this);
return $reflector->getShortName() . '-' . $number;
}
The form then looks like this:
<?php $form = ActiveForm::begin(); ?>
<?php foreach($dates as $date): ?>
<?= $form->field($date,"start"); ?>
<?= $form->field($date,"end"); ?>
<?php endforeach; ?>
</table>
<?= Html::submitButton('Save'); ?>
<?php ActiveForm::end(); ?>
Override the formName() method in your model class to make it unique. If you don't want to change your model class, create a subclass of it for the purpose of working for this controller action. After doing this, the html ID and name fields will automatically be unique.

How to use 'onchange' in Yii2 MaskedInput widget

I have an Yii2 app with advanced template. There is 2 fields on my form. 1st: MaskedInput and 2nd textInput with readonly attribute.
So, I wanted to fill 2nd textInput automatically right after I have filled MaskedInput. For this I tried to use onchange. But I got following error:
Unknown Property – yii\base\UnknownPropertyException
Setting unknown property: yii\widgets\MaskedInput::onchange
Here is my code:
<?php $form = ActiveForm::begin(); ?>
<div class="row">
<div class="col-xs-3">
<?= Html::label("Ser num")?>
<?= MaskedInput::widget(['name'=>'serNum',
'mask'=>'AA 9999999',
'onchange'=>'
$.post("index.php?r=act/actid&serNum='.'"+$(this).val(),function(data){
$("select#ser-sernum").html(data);
});
'
])?>
</div>
<div class="col-xs-3">
<?= $form->field($model, 'sernum')->textInput(['readonly'=>true]) ?>
</div>
<div class="col-xs-6">
<b id="actstatus"></b>
</div>
</div>
Try with options property:
<?= yii\widgets\MaskedInput::widget(['name'=>'serNum',
'mask'=>'AA 9999999',
'options' => [
'onchange'=>'
$.post("index.php?r=act/actid&serNum='.'"+$(this).val(),function(data){
$("select#ser-sernum").html(data);
});'
]
])?>

Yii2 Add a Form field not in model

As we know,
<?= $form->field($model, 'name_field')->textInput() ?>
Adds a text field connected to 'name_field' in the model/table.
I want to add a field NOT in the model/table, and then run some JS when it loses focus to calculate the other fields.
How firstly do you add a free text field not connected to the model ?
Second, does anyone have any examples of adding JS/Jquery to the _form.php ?
The Html class contains the functions for generation of fields. In fact, your code above ends up calling Html::textInput(). To add a field
<?= Html::textInput("name", $value) ?>
To add javascript to a view just use registerJs():
$this->registerJs("alert('true');");
You can have the field rendered the same way as the ActiveField, with a label and classes. For example, let’s add a Cc field to a Mail form.
First display the To: field (in the model):
<?= $form->field($model, 'to')->textInput() ?>
Let’s add the Cc field (not in the model):
<?= Html::beginTag('div', ['class' => 'form-group field-mail-cc']) ?>
<?= Html::label('Cc:', 'mail-cc', ['class' => 'control-label']) ?>
<?= Html::textInput('Mail[cc]', '', ['id' => 'mail-cc', 'class' => 'form-control']) ?>
<?= Html::endTag('div') ?>
The class and id names mail-cc and field-mail-cc follow the ActiveForm naming pattern. The input name Mail[cc] adds your field to the ActiveForm group, so you can easily retrieve it with the usual
$form = Yii::$app->request->post('Mail');