Yii2:compare start and end time in tabular/array input - javascript

Is it possible to compare start and end time in my below form in yii2 client/ajax validation.
My view file code like this:
<?php foreach ($model->weekDaysList as $index => $value) : ?>
<div class="row">
<div class="col-sm-1">
</div>
<div class="col-sm-2">
<?= $form->field($model, "[$index]td_day")->checkbox(['label' => $value]) ?>
</div>
<div class="col-sm-3">
<?= $form->field($model, "[$index]td_from") ?>
</div>
<div class="col-sm-3">
<?= $form->field($model, "[$index]td_to") ?>
</div>
</div>
<?php endforeach; ?>
controller code:
public function actionSchedule()
{
$model = new TimetableDetails();
$model->scenario = 'MultiSchedule';
$model->attributes = Yii::$app->request->get('sd');
if ($model->load(Yii::$app->request->post())) {
if (Yii::$app->request->isAjax) {
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
return \yii\widgets\ActiveForm::validate($model);
}
}
if (Yii::$app->request->isAjax) {
return $this->renderAjax('schedule', [
'model' => $model,
]);
} else {
return $this->render('schedule', [
'model' => $model,
]);
}
}

You can define a rule for comparing two dates.
First you need to convert them to integer in order to be able to use integrated validator. The best way to do it to cast date to unix timestamp before validation and to the format you need after validation.
Add these in your model:
public function beforeValidate() {
$this->td_to = strtotime($this->td_to);
$this->td_from = strtotime($this->td_from);
return parent::beforeValidate();
}
public function afterValidate() {
$this->td_to = date(FORMAT, $this->td_to);
$this->td_from = date(FORMAT, $this->td_from);
}
Add new rule inside your rules method
return [
// rules
['td_to', 'compare', 'operator' => '<', 'type' => 'number', 'compareAttribute' => 'td_from', 'whenClient' => 'js:function () { /* validate values with jQuery or js here and if valid return true */ return true; }'],
];
This would work on ajax validation. In order to make client validation you need to add js function which validates the values and assign it to whenClient key of the rule.

Related

Yii2 Pjax ListView With Custom ActiveForm Filters - Duplicate Url Params Issue

Key question is, does the \yii\widgets\ListView actually support filters with Pjax, like it's \yii\widgets\GridView counterpart? Here's what I have tried that has led to a duplicate url params issue:
I have a Gii-created search model with a custom param, $userRoleFilter:
<?php
namespace common\models;
use yii\base\Model;
use yii\data\ActiveDataProvider;
use yii\rbac\Item;
/**
* UserSearch represents the model behind the search form of `common\models\User`.
*/
class UserSearch extends User
{
public $userRoleFilter = null;
/**
* {#inheritdoc}
*/
public function rules()
{
return [
[['id', 'flags', 'confirmed_at', 'blocked_at', 'updated_at', 'created_at', 'last_login_at', 'auth_tf_enabled', 'password_changed_at', 'gdpr_consent', 'gdpr_consent_date', 'gdpr_deleted'], 'integer'],
[['username', 'email', 'password_hash', 'auth_key', 'unconfirmed_email', 'registration_ip', 'last_login_ip', 'auth_tf_key', 'userRoleFilter'], 'safe'],
];
}
/**
* {#inheritdoc}
*/
public function scenarios()
{
// bypass scenarios() implementation in the parent class
return Model::scenarios();
}
/**
* Creates data provider instance with search query applied
*
* #param array $params
*
* #return ActiveDataProvider
*/
public function search($params)
{
$query = User::find();
// add conditions that should always apply here
$dataProvider = new ActiveDataProvider([
'query' => $query,
'pagination' => [
'pageSize' => 20,
],
]);
$this->load($params);
if (!$this->validate()) {
// uncomment the following line if you do not want to return any records when validation fails
// $query->where('0=1');
return $dataProvider;
}
// grid filtering conditions
$query->andFilterWhere([
'id' => $this->id,
'flags' => $this->flags,
'confirmed_at' => $this->confirmed_at,
'blocked_at' => $this->blocked_at,
'updated_at' => $this->updated_at,
'created_at' => $this->created_at,
'last_login_at' => $this->last_login_at,
'auth_tf_enabled' => $this->auth_tf_enabled,
'password_changed_at' => $this->password_changed_at,
'gdpr_consent' => $this->gdpr_consent,
'gdpr_consent_date' => $this->gdpr_consent_date,
'gdpr_deleted' => $this->gdpr_deleted,
]);
$query->andFilterWhere(['like', 'username', $this->username])
->andFilterWhere(['like', 'email', $this->email])
->andFilterWhere(['like', 'password_hash', $this->password_hash])
->andFilterWhere(['like', 'auth_key', $this->auth_key])
->andFilterWhere(['like', 'unconfirmed_email', $this->unconfirmed_email])
->andFilterWhere(['like', 'registration_ip', $this->registration_ip])
->andFilterWhere(['like', 'last_login_ip', $this->last_login_ip])
->andFilterWhere(['like', 'auth_tf_key', $this->auth_tf_key]);
if (!empty($params['UserSearch']['userRoleFilter'])) {
$userRoleFilter = $params['UserSearch']['userRoleFilter'];
// inner join to the user role items to filter by assigned role
$query->alias('u')
->innerJoin(
'auth_assignment AS aa',
'u.id = aa.user_id AND aa.item_name = :roleName',
['roleName' => $userRoleFilter]
)
->leftJoin(
'auth_item AS ai',
'aa.item_name = ai.name AND ai.type = :typeRole',
['typeRole' => Item::TYPE_ROLE]
);
}
return $dataProvider;
}
}
Controller method:
/**
* Displays pricing calculation & data exports index.
*
* #return string
*/
public function actionDisplayUsers()
{
$searchModel = new UserSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
return $this->render('display-users', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
]);
}
And manually wrapped my custom yii\bootstrap\ActiveForm in the Pjax tags:
<?php
/* #var $this yii\web\View */
/* #var $searchModel common\models\UserSearch */
/* #var $dataProvider yii\data\ActiveDataProvider */
use common\components\rbac\UserManager;
use yii\bootstrap\ActiveForm;
use yii\widgets\ListView;
use yii\widgets\Pjax;
$this->title = Yii::t('app', 'Display Users');
$this->params['breadcrumbs'][] = $this->title;
?>
<div class="site-display-users">
<div class="body-content">
<h1><?= $this->title ?></h1>
<?php Pjax::begin([
'options' => [
'id' => 'site-display-users-pjax-container',
],
'enablePushState' => true,
'enableReplaceState' => false,
]); ?>
<div class="well center-block meta-control">
<?php $form = ActiveForm::begin([
'id' => 'displayUsersForm',
'method' => 'get',
'options' => [
'data-pjax' => 1,
],
]); ?>
<div class="row row-grid">
<div class="col-xs-6">
<?=
$form
->field($searchModel, 'userRoleFilter')
->dropDownList(UserManager::getAvailableRoles(), [
'prompt' => 'Select User Role',
'id' => 'userRoleFilter',
])
?>
</div>
<div class="col-xs-6">
</div>
</div>
<?php ActiveForm::end(); ?>
</div>
<div class="row">
<div class="col-lg-12">
<?php
echo ListView::widget([
'dataProvider' => $dataProvider,
'itemView' => '_display-user',
'viewParams' => [
// add params to pass into view here
],
]);
?>
</div>
</div>
<?php Pjax::end(); ?>
</div>
</div>
This works fine and filters the users in the ListView according to the selected role. But it is creating a duplicate url param after each time the filter is changed:
/site/display-users
/site/display-users?UserSearch%5BuserRoleFilter%5D=admin
/site/display-users?UserSearch%5BuserRoleFilter%5D=admin&UserSearch%5BuserRoleFilter%5D=role-importer-user
/site/display-users?UserSearch%5BuserRoleFilter%5D=admin&UserSearch%5BuserRoleFilter%5D=role-importer-user&UserSearch%5BuserRoleFilter%5D=admin
and so on...
I know that I can set the Pjax enablePushState and enableReplaceState values to false and then it does not keep creating history items and modifying the url in the browser, but just sends the same ever-lengthening url in the ajax request...
What can be done? Is there a better way to handle this? A setting I am missing to stop this duplication of get param keys stacking up in the url?
Found out the solution... turns out that the ActiveForm form action parameter needs to be explicitly defined so that this URI is used for each form submission rather than relying on the URL from the address bar.
<?php $form = ActiveForm::begin([
'id' => 'displayUsersForm',
'method' => 'get',
'action' => Url::to(['site/display-users']),
'options' => [
'data-pjax' => 1,
],
]); ?>
See here for more details.

Validate form before submit

There is a form. The submit button does not apply to ActiveForm with id = "modal-btn-register-request". In JQuery, by clicking on this button I call $("#modal-btn-register-request").submit() and the form has been validated or not sent to the action. How can I validate before clicking the button. It's all about the button, if you insert the standard Html::submitButton, if there are errors in the form, the data is not sent
rules in model
public function rules()
{
return [
[['email'], 'required'],
[['email'], 'email'],
[['password','password_confirm'], 'required'],
];
}
form in view
<?php \yii\widgets\ActiveForm::begin(['action' => '/sign-up']); ?>
<?php echo $form->field($registerForm, 'email')->textInput(['placeholder' => 'Input login', 'class' => 'modal-login__input inp-main']); ?>
<?php echo $form->field($registerForm, 'password')->passwordInput(['placeholder' => 'Input password', 'class' => 'modal-login__input inp-main']) ?>
<?php echo $form->field($registerForm, 'password_confirm')->passwordInput(['placeholder' => 'Confirm the password','class' => 'modal-login__input inp-main']) ?>
<?php \yii\widgets\ActiveForm::end(); ?>
<div class="modal-login__form-btns-cont clearfix">
<div class="modal-login__form-btn-wp modal-login__form-submit-cont text-md-right float-md-right">
<a class="modal-login__submit-btn" id="modal-btn-register-request" href="">Come in</a>
</div>
</div>
jQuery code
$("#modal-btn-register-request").click(function() {
$("#w3").submit();
});
if there is an incorrect field, do not send the form and vice versa?
or how you can send the form when clicking on an element that does not belong to ActiveForm and take into account the validation
Use event.preventDefault() and the yiiActiveForm object:
$("#modal-btn-register-request").click(function(event) {
event.preventDefault();
jQuery('#w3').yiiActiveForm().submit();
});
try this
<?php \yii\widgets\ActiveForm::begin(['action' => '/sign-up']); ?>
<?php echo $form->field($registerForm, 'email')->textInput(['placeholder' => 'Input login', 'class' => 'modal-login__input inp-main']); ?>
<?php echo $form->field($registerForm, 'password')->passwordInput(['placeholder' => 'Input password', 'class' => 'modal-login__input inp-main']) ?>
<?php echo $form->field($registerForm, 'password_confirm')->passwordInput(['placeholder' => 'Confirm the password','class' => 'modal-login__input inp-main']) ?>
<div class="modal-login__form-btns-cont clearfix">
<div class="modal-login__form-btn-wp modal-login__form-submit-cont text-md-right float-md-right">
<a class="modal-login__submit-btn" id="modal-btn-register-request" href="">Come in</a>
</div>
</div>
<?php \yii\widgets\ActiveForm::end(); ?>
At first glance seems your button in not witnin the actual form.
Edit:
I think for what you need you can go about doing in two ways:
1) use an AJAX validation or
2)Use javascript (or JQuery if you prefer) in your view to process the fields before yo call $("#modal-btn-register-request").submit()
For (1) you can do like so:
Edit your form begin like so <?php \yii\widgets\ActiveForm::begin(['action' => '/sign-up', 'enableAjaxValidation' => true]); ?>
Next add the rule you want to verify ofr example:
public function rules()
{
return [
[['email'], 'required'],
[['email'], 'email'],
['email', 'unique'], //<---for example
[['password','password_confirm'], 'required'],
];
}
Now you would need to add to your action (the one that renders the form) an if statement to catch this AJAX call in your controller like so
public function actionSignup(){ //<-- assuming its the signup action
$model = new User();
if(Yii::$app->request->isAjax && $model->load(Yii::$app->request->post())){
Yii::$app->response->format = 'json';
return ActiveForm::validate($model);
}
return $this->render('signup',[
'model' => $model
]);
}
If you want to validate without even checking in your database then is can be doe strictly with javascript (or JQuery) and option (2) is your choice. In that case check out the question check length of input field?
Hope this helps.

active form multi model and multi attributes in Yii2

In my project, I have an aggregation between, let's say, a University model and a Department model: a university have at least one department, while every department belongs to only one university.
I'd like to have a possibility to create a university model instance with some number of department model instances and the exact number of departments is not known in advance (but at least one must exist). So, when creating a university, I'd like to have a page with one default department and an "Add Department" button that would allow me by means of javascript to add any number of departments that I need.
The question is: how should I write the create view page using ActiveForm in order that my POST array has the following structure:
"University" => ["name" => "Sorbonne", "city" => "Paris"],
"Faculty" => [
0 => ["name" => "Medicine", "dean" => "Person A"],
1 => ["name" => "Physics", "dean" => "Person B"],
2 => ["name" => "Mathematics", "dean" => "Person C"],
...
]
that I then pass to Faculty::loadMultiple() method.
I've tried something like this
$form = ActiveForm::begin();
echo $form->field($university, 'name')->textInput();
echo $form->field($university, 'city')->textInput();
foreach ($faculties as $i => $faculty) {
echo $form->field($faculty, "[$i]name")->textInput();
echo $form->field($faculty, "[$i]dean")->textInput()
}
ActiveForm::end();
It works, but when adding new department by means of javascript (I just clone an html node that contains department input fields), I am forced to elaborate the numbers coming from variable $i of the above php script. And this is quite annoying.
Another possibility that I've tried was to get rid of variable $i and write something like
$form = ActiveForm::begin();
echo $form->field($university, 'name')->textInput();
echo $form->field($university, 'city')->textInput();
foreach ($faculties as $faculty) {
echo $form->field($faculty, "[]name")->textInput();
echo $form->field($faculty, "[]dean")->textInput()
}
ActiveForm::end();
In this way, cloning the corresponding node is very simple, but the generated POST array has wrong structure due to [] brackets.
Is it possible to modify the latter approach and to have the required structure of the POST array?
Use Yii2 dynamic form extension:
Installation
The preferred way to install this extension is through composer.
Either run:
composer require --prefer-dist wbraganca/yii2-dynamicform "dev-master"
Or add to the require section of your composer.json file:
"wbraganca/yii2-dynamicform": "dev-master"
Demo page: Nested Dynamic Form
Nested Dynamic Form Demo Source Code:
Source Code - View: _form.php
<?php
use yii\helpers\Html;
use yii\bootstrap\ActiveForm;
use wbraganca\dynamicform\DynamicFormWidget;
?>
<div class="person-form">
<?php $form = ActiveForm::begin(['id' => 'dynamic- form']); ?>
<div class="row">
<div class="col-sm-6">
<?= $form->field($modelPerson, 'first_name')->textInput(['maxlength' => true]) ?>
</div>
<div class="col-sm-6">
<?= $form->field($modelPerson, 'last_name')->textInput(['maxlength' => true]) ?>
</div>
</div>
<div class="padding-v-md">
<div class="line line-dashed"></div>
</div>
<?php DynamicFormWidget::begin([
'widgetContainer' => 'dynamicform_wrapper',
'widgetBody' => '.container-items',
'widgetItem' => '.house-item',
'limit' => 10,
'min' => 1,
'insertButton' => '.add-house',
'deleteButton' => '.remove-house',
'model' => $modelsHouse[0],
'formId' => 'dynamic-form',
'formFields' => [
'description',
],
]); ?>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Houses</th>
<th style="width: 450px;">Rooms</th>
<th class="text-center" style="width: 90px;">
<button type="button" class="add-house btn btn-success btn-xs"><span class="fa fa-plus"></span></button>
</th>
</tr>
</thead>
<tbody class="container-items">
<?php foreach ($modelsHouse as $indexHouse => $modelHouse): ?>
<tr class="house-item">
<td class="vcenter">
<?php
// necessary for update action.
if (! $modelHouse->isNewRecord) {
echo Html::activeHiddenInput($modelHouse, "[{$indexHouse}]id");
}
?>
<?= $form->field($modelHouse, "[{$indexHouse}]description")->label(false)->textInput(['maxlength' => true]) ?>
</td>
<td>
<?= $this->render('_form-rooms', [
'form' => $form,
'indexHouse' => $indexHouse,
'modelsRoom' => $modelsRoom[$indexHouse],
]) ?>
</td>
<td class="text-center vcenter" style="width: 90px; verti">
<button type="button" class="remove-house btn btn-danger btn-xs"><span class="fa fa-minus"></span></button>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php DynamicFormWidget::end(); ?>
<div class="form-group">
<?= Html::submitButton($modelPerson->isNewRecord ? 'Create' : 'Update', ['class' => 'btn btn-primary']) ?>
</div>
<?php ActiveForm::end(); ?>
Source Code - View: _form-rooms.php
<?php
use yii\helpers\Html;
use wbraganca\dynamicform\DynamicFormWidget;
?>
<?php DynamicFormWidget::begin([
'widgetContainer' => 'dynamicform_inner',
'widgetBody' => '.container-rooms',
'widgetItem' => '.room-item',
'limit' => 4,
'min' => 1,
'insertButton' => '.add-room',
'deleteButton' => '.remove-room',
'model' => $modelsRoom[0],
'formId' => 'dynamic-form',
'formFields' => [
'description'
],
]); ?>
<table class="table table-bordered">
<thead>
<tr>
<th>Description</th>
<th class="text-center">
<button type="button" class="add-room btn btn-success btn-xs"><span class="glyphicon glyphicon-plus"></span></button>
</th>
</tr>
</thead>
<tbody class="container-rooms">
<?php foreach ($modelsRoom as $indexRoom => $modelRoom): ?>
<tr class="room-item">
<td class="vcenter">
<?php
// necessary for update action.
if (! $modelRoom->isNewRecord) {
echo Html::activeHiddenInput($modelRoom, "[{$indexHouse}][{$indexRoom}]id");
}
?>
<?= $form->field($modelRoom, "[{$indexHouse}][{$indexRoom}]description")->label(false)->textInput(['maxlength' => true]) ?>
</td>
<td class="text-center vcenter" style="width: 90px;">
<button type="button" class="remove-room btn btn-danger btn-xs"><span class="glyphicon glyphicon-minus"></span></button>
</td>
</tr>
<?php endforeach; ?>
</tbody>
Source Code - Controller
<?php
namespace app\modules\yii2extensions\controllers;
use Yii;
use yii\helpers\ArrayHelper;
use yii\web\NotFoundHttpException;
use yii\web\Response;
use yii\widgets\ActiveForm;
use app\base\Model;
use app\base\Controller;
use app\modules\yii2extensions\models\House;
use app\modules\yii2extensions\models\Person;
use app\modules\yii2extensions\models\Room;
use app\modules\yii2extensions\models\query\PersonQuery;
/**
* DynamicformDemo3Controller implements the CRUD actions for Person model.
*/
class DynamicformDemo3Controller extends Controller
{
/**
* Lists all Person models.
* #return mixed
*/
public function actionIndex()
{
$searchModel = new PersonQuery();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
return $this->render('index', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
]);
}
/**
* Displays a single Person model.
* #param integer $id
* #return mixed
*/
public function actionView($id)
{
$model = $this->findModel($id);
$houses = $model->houses;
return $this->render('view', [
'model' => $model,
'houses' => $houses,
]);
}
/**
* Creates a new Person model.
* If creation is successful, the browser will be redirected to the 'view' page.
* #return mixed
*/
public function actionCreate()
{
$modelPerson = new Person;
$modelsHouse = [new House];
$modelsRoom = [[new Room]];
if ($modelPerson->load(Yii::$app->request->post())) {
$modelsHouse = Model::createMultiple(House::classname());
Model::loadMultiple($modelsHouse, Yii::$app->request->post());
// validate person and houses models
$valid = $modelPerson->validate();
$valid = Model::validateMultiple($modelsHouse) && $valid;
if (isset($_POST['Room'][0][0])) {
foreach ($_POST['Room'] as $indexHouse => $rooms) {
foreach ($rooms as $indexRoom => $room) {
$data['Room'] = $room;
$modelRoom = new Room;
$modelRoom->load($data);
$modelsRoom[$indexHouse][$indexRoom] = $modelRoom;
$valid = $modelRoom->validate();
}
}
}
if ($valid) {
$transaction = Yii::$app->db->beginTransaction();
try {
if ($flag = $modelPerson->save(false)) {
foreach ($modelsHouse as $indexHouse => $modelHouse) {
if ($flag === false) {
break;
}
$modelHouse->person_id = $modelPerson->id;
if (!($flag = $modelHouse->save(false))) {
break;
}
if (isset($modelsRoom[$indexHouse]) && is_array($modelsRoom[$indexHouse])) {
foreach ($modelsRoom[$indexHouse] as $indexRoom => $modelRoom) {
$modelRoom->house_id = $modelHouse->id;
if (!($flag = $modelRoom->save(false))) {
break;
}
}
}
}
}
if ($flag) {
$transaction->commit();
return $this->redirect(['view', 'id' => $modelPerson->id]);
} else {
$transaction->rollBack();
}
} catch (Exception $e) {
$transaction->rollBack();
}
}
}
return $this->render('create', [
'modelPerson' => $modelPerson,
'modelsHouse' => (empty($modelsHouse)) ? [new House] : $modelsHouse,
'modelsRoom' => (empty($modelsRoom)) ? [[new Room]] : $modelsRoom,
]);
}
/**
* Updates an existing Person model.
* If update is successful, the browser will be redirected to the 'view' page.
* #param integer $id
* #return mixed
*/
public function actionUpdate($id)
{
$modelPerson = $this->findModel($id);
$modelsHouse = $modelPerson->houses;
$modelsRoom = [];
$oldRooms = [];
if (!empty($modelsHouse)) {
foreach ($modelsHouse as $indexHouse => $modelHouse) {
$rooms = $modelHouse->rooms;
$modelsRoom[$indexHouse] = $rooms;
$oldRooms = ArrayHelper::merge(ArrayHelper::index($rooms, 'id'), $oldRooms);
}
}
if ($modelPerson->load(Yii::$app->request->post())) {
// reset
$modelsRoom = [];
$oldHouseIDs = ArrayHelper::map($modelsHouse, 'id', 'id');
$modelsHouse = Model::createMultiple(House::classname(), $modelsHouse);
Model::loadMultiple($modelsHouse, Yii::$app->request->post());
$deletedHouseIDs = array_diff($oldHouseIDs, array_filter(ArrayHelper::map($modelsHouse, 'id', 'id')));
// validate person and houses models
$valid = $modelPerson->validate();
$valid = Model::validateMultiple($modelsHouse) && $valid;
$roomsIDs = [];
if (isset($_POST['Room'][0][0])) {
foreach ($_POST['Room'] as $indexHouse => $rooms) {
$roomsIDs = ArrayHelper::merge($roomsIDs, array_filter(ArrayHelper::getColumn($rooms, 'id')));
foreach ($rooms as $indexRoom => $room) {
$data['Room'] = $room;
$modelRoom = (isset($room['id']) && isset($oldRooms[$room['id']])) ? $oldRooms[$room['id']] : new Room;
$modelRoom->load($data);
$modelsRoom[$indexHouse][$indexRoom] = $modelRoom;
$valid = $modelRoom->validate();
}
}
}
$oldRoomsIDs = ArrayHelper::getColumn($oldRooms, 'id');
$deletedRoomsIDs = array_diff($oldRoomsIDs, $roomsIDs);
if ($valid) {
$transaction = Yii::$app->db->beginTransaction();
try {
if ($flag = $modelPerson->save(false)) {
if (! empty($deletedRoomsIDs)) {
Room::deleteAll(['id' => $deletedRoomsIDs]);
}
if (! empty($deletedHouseIDs)) {
House::deleteAll(['id' => $deletedHouseIDs]);
}
foreach ($modelsHouse as $indexHouse => $modelHouse) {
if ($flag === false) {
break;
}
$modelHouse->person_id = $modelPerson->id;
if (!($flag = $modelHouse->save(false))) {
break;
}
if (isset($modelsRoom[$indexHouse]) && is_array($modelsRoom[$indexHouse])) {
foreach ($modelsRoom[$indexHouse] as $indexRoom => $modelRoom) {
$modelRoom->house_id = $modelHouse->id;
if (!($flag = $modelRoom->save(false))) {
break;
}
}
}
}
}
if ($flag) {
$transaction->commit();
return $this->redirect(['view', 'id' => $modelPerson->id]);
} else {
$transaction->rollBack();
}
} catch (Exception $e) {
$transaction->rollBack();
}
}
}
return $this->render('update', [
'modelPerson' => $modelPerson,
'modelsHouse' => (empty($modelsHouse)) ? [new House] : $modelsHouse,
'modelsRoom' => (empty($modelsRoom)) ? [[new Room]] : $modelsRoom
]);
}
/**
* Deletes an existing Person model.
* If deletion is successful, the browser will be redirected to the 'index' page.
* #param integer $id
* #return mixed
*/
public function actionDelete($id)
{
$model = $this->findModel($id);
$name = $model->first_name;
if ($model->delete()) {
Yii::$app->session->setFlash('success', 'Record <strong>"' . $name . '"</strong> deleted successfully.');
}
return $this->redirect(['index']);
}
/**
* Finds the Person model based on its primary key value.
* If the model is not found, a 404 HTTP exception will be thrown.
* #param integer $id
* #return Person the loaded model
* #throws NotFoundHttpException if the model cannot be found
*/
protected function findModel($id)
{
if (($model = Person::findOne($id)) !== null) {
return $model;
} else {
throw new NotFoundHttpException('The requested page does not exist.');
}
}
}

Getting null value when inserting data through Yii2 form

I've added a textinput field in my production form. The unitprice fills up when I select productname field drop down. But when I'm saving the data, I'm getting following error -
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'unitprice' cannot be null
The SQL being executed was: INSERT INTO `bottle` (`usedate`, `useqty`, `productname`, `bottlename`, `unitprice`) VALUES ('2016-04-21', '12', 'CEFO', 'Enter', NULL)
The last "NULL" is the value for unitprice.
actionCreate in productionController-
public function actionCreate()
{
$model = new Production();
$productname = new Productnames();
$bottle = new Bottle();
$bottlename = new Bottlename();
if ($model->load(Yii::$app->request->post()) && $productname->load(Yii::$app->request->post()))
{
$model->save();
//$bottle->attributes = $model->attributes;
$bottle->usedate = $model->productiondate;
$bottle->useqty = $model->prodqty;
$bottle->productname = $model->productname;
$bottle->bottlename = $productname->bottletype;
$bottle->unitprice = $bottlename->unitprice;
// $employee->emp_mobile = $model->emp_mobile;
$bottle->save();
return $this->redirect(['create']);
} else {
return $this->render('create', [
'model' => $model,
'bottle' => $bottle,
'productname' => $productname,
'bottlename' => $bottlename,
]);
}
}
Production _form
<?php
use yii\helpers\Html;
use yii\helpers\Url;
use yii\widgets\ActiveForm;
use yii\web\View;
use frontend\assets\XyzAsset;
use yii\helpers\ArrayHelper;
use dosamigos\datepicker\DatePicker;
use kartik\select2\Select2;
use frontend\modules\production\models\Productbatch;
use frontend\modules\production\models\Productnames;
use kartik\depdrop\DepDrop;
use yii\helpers\Json;
use frontend\modules\production\models\Bottlename;
//XyzAsset::register($this);
/* #var $this yii\web\View */
/* #var $model frontend\modules\production\models\Production */
/* #var $form yii\widgets\ActiveForm */
?>
<div class="production-form">
<?php $form = ActiveForm::begin(); ?>
<!--<?= Html::a('Select Product', ['/production/productbatch/index'], ['class'=>'btn btn-primary']) ?> -->
<?= $form->field($model, 'productiondate')->widget(
DatePicker::className(), [
// inline too, not bad
'inline' => false,
// modify template for custom rendering
//'template' => '<div class="well well-sm" style="background-color: #fff; width:250px">{input}</div>',
'clientOptions' => [
'autoclose' => true,
'format' => 'yyyy-mm-dd'
]
]);?>
<!-- echo CHtml::button("(+)",array('title'=>"Select Product",'onclick'=>'js:selectproductforproduction();')); -->
<?= $form->field($model, 'productname')->widget(Select2::classname(), [
'data' => ArrayHelper::map(Productnames::find()->all(),'productnames_productname','productnames_productname'),
'language' => 'en',
'options' => ['placeholder' => 'Select Product Name', 'id' => 'catid'],
'pluginOptions' => [
'allowClear' => true
],
]); ?>
<?= $form->field($model, 'batchno')->widget(DepDrop::classname(), [
'options'=>['id'=>'subcat-id'],
'pluginOptions'=>[
'depends'=>['catid'],
'placeholder'=>'Select BatchNo',
'url'=>Url::to(['/production/productbatch/subcat'])
]
]); ?>
<?= $form->field($model, 'prodqty')->textInput() ?>
<?= $form->field($productname, 'bottletype')->textInput() ?>
<?= $form->field($bottlename, 'unitprice')->textInput() ?>
<div class="form-group">
<?= Html::submitButton($model->isNewRecord ? 'Create' : 'Update', ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>
</div>
<?php ActiveForm::end(); ?>
</div>
<?php
$script = <<< JS
$('#catid').change(function(){
var catid = $(this).val();
$.get('index.php?r=production/productnames/get-for-production',{ catid : catid }, function(data){
//alert(data);
var data = $.parseJSON(data);
$('#productnames-bottletype').attr('value',data.bottletype);
$('#bottlename-unitprice').attr('value',data.bottletype0.unitprice);
});
});
JS;
$this->registerJs($script);
?>
The action to get the data array
public function actionGetForProduction($catid)
{
$bottle = Productnames::find()->with('bottletype0')->where(['productnames_productname'=>$catid])->asArray()->one();
//$bottle -> select(['productnames.productnames_productname','productnames.bottletype','bottlename.unitprice'])->from('Productnames')->leftJoin('bottlename','productnames.bottletype = bottlename.bottlename')->where(['productnames_productname'=>$catid])->limit(1);
echo Json::encode($bottle);
This code works fine except the last unitprice. Please help.
You fotgot to add $bottlename->load(Yii::$app->request->post()) in if condition. So add like as,
if ($model->load(Yii::$app->request->post()) && $productname->load(Yii::$app->request->post()) && $bottlename->load(Yii::$app->request->post())) {
.......
}

Send extra parameter to action on form submission in yii2

i have a gridview of checkin model with checkbox action column
and on the same view i have form of model message with 2 field message and fileinput but i want to send one more data on the submit button click of message model form which is the keys of checkbox.
How can i so that?
it can be done only via javascript or there is some other technique as well?
here is my grid and view code
<div class="row">
<p>
<?php $form = ActiveForm::begin(['options'=>['enctype'=>'multipart/form-data']]); ?>
<div class="form-group col-xs-3 col-lg-3">
<?= $form->field($model, 'message')->textarea(['rows' => 6]) ?>
</div>
<div class="form-group col-xs-3 col-lg-3">
<?= $form->field($model, 'file')->fileInput() ?>
<div class="form-group">
<?= Html::submitButton('Send', ['class' => 'btn btn-danger','id'=>'sendMessage']) ?>
</div>
</div>
<?php ActiveForm::end(); ?>
</p>
</div>
<div class="checkin-index">
<h1><?= Html::encode($this->title) ?></h1>
<?php // echo $this->render('_search', ['model' => $searchModel]); ?>
<?php Pjax::begin(['id' => 'checkin-grid', 'timeout' => false]); ?>
<?= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'showOnEmpty'=>true,
'columns' => [
[
'class' => 'yii\grid\CheckboxColumn',
],
[
'attribute' => 'user_id',
'label' => 'Email',
'value' => 'users.email',
],
'user_type',
],
]);
?>
<?php Pjax::end(); ?>
And here is my checkin/index code where i can access the message and fileinput but i want list of keys as well...
So user must check at least one row before sending message
public function actionIndex()
{
$model = new Message();
$searchModel = new CheckinSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
return $this->render('index', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
'model' => $model,
]);
}
You can extend your Message model adding the fields you need
class Message extends \yii\db\ActiveRecord
{
public $yourField;
public static function tableName()
{
...
}
this way in your model you have one more field not mapped to database and yon can use for your need....
When you submit your value, the submit related action you shuold manage the models like this way
$models = $dataProvider->getModels();
if (Model::loadMultiple($models, Yii::$app->request->post()) && Model::validateMultiple($models)) {
...... your code for models managemnt
}
F

Categories

Resources