Submit multiple image upload forms on single button click - ajax

I have three forms in one view. Two forms have upload image (multipart) functionality and third is a regular form with text fields I want to upload all three forms on a single button click. can anyone help me with this?

Try this code it will work to upload multiple images in different tables in a single form.
public function actionCreate()
{
$db = Yii::$app->db;
$transaction = $db->beginTransaction();
$savedFlag = false;
$model = new Company();
$divisionModel = new Division();
$prajects = new Prajects();
if ($model->load(Yii::$app->request->post()) && $prajects ->load(Yii::$app->request->post()) && $divisionModel->load(Yii::$app->request->post())) {
try{
$model->company_logo = UploadedFile::getInstance($model, 'company_logo');
if ($model->company_logo) {
$model->company_logo->saveAs('uploads/' . $model->company_logo->baseName . '.' . $model->company_logo->extension);
}
if($model->save()){
$savedFlag = true;
$divisionModel->division_logo = UploadedFile::getInstance($divisionModel, 'division_logo');
if ($divisionModel->division_logo) {
$divisionModel->division_logo->saveAs('uploads/' . $divisionModel->division_logo->baseName . '.' . $divisionModel->division_logo->extension);
}
//$divisionModel->comapnay_id = $model->id;
if(!$divisionModel->save()){
$savedFlag = false;
}
if(!$prajects->save()){
$savedFlag = false;
}
}
if($savedFlag){
$transaction->commit();
return $this->redirect(['view', 'id' => $model->id]);
}else{
$transaction->rollBack();
}
}catch (\Exception $e) {
$transaction->rollBack();
throw $e;
}
}
return $this->render('create', [
'model' => $model,
'divisionModel' => $divisionModel,
'prajects' => $prajects,
]);
}
create.php file:
<?= $this->render('_form', [
'model' => $model,
'divisionModel' => $divisionModel,
'prajects' => $prajects,
]) ?>
_form.php file:
<?php $form = ActiveForm::begin(); ?>
<?= $form->field($model, 'name')->textInput(['maxlength' => true]) ?>
<?= $form->field($model, 'company_logo')->fileInput() ?>
<?= $form->field($divisionModel, 'division_name')->textInput(['maxlength' => true]) ?>
<?= $form->field($divisionModel, 'division_logo')->fileInput() ?>
<?= $form->field($prajects, 'name')->textInput(['maxlength' => true]) ?>
<div class="form-group">
<?= Html::submitButton('Save', ['class' => 'btn btn-success']) ?>
</div>
<?php ActiveForm::end(); ?>

Related

Validating array of inputs in a form Yii2

I have been developing a system to create a dynamic questioner, where an organizer can create questions for a user to respond, but I have been having trouble validating the answers of the users to the questioners. I have three types of inputs available for the organizer to create, a short answer, a long answer and an input field. I tried using the Each validation rule, but it doesn’t seem to be working. I search all around for an answer to this, but I didn't find anything that worked.
Here is my code.
View
<?php $form = ActiveForm::begin([ 'id' => 'respuesta-form', 'enableAjaxValidation' => true, 'options' => ['enctype' => 'multipart/form-data'], ]); ?>
<?php foreach ($preguntas as $i => $pregunta): ?>
<?php if($pregunta->tipo == 1): ?>
<?= $form->field($model, "respuesta[$i]")->textInput(['maxlength' => true])->label("<strong>" . $pregunta->descripcion . "</strong>") ?>
<?php endif; ?>
<?php if($pregunta->tipo == 2): ?>
<?= $form->field($model, "respuesta[$i]")->textarea(['maxlength' => true], ["style" => "resize: none;"])->label("<strong>" . $pregunta->descripcion . "</strong>") ?>
<?php endif; ?>
<?php if($pregunta->tipo == 3): ?>
<?= $form->field($model, "respuesta[$i]")->fileInput()->label("<strong>" . $pregunta->descripcion . "</strong>") ?>
<?php endif; ?>
<?php endforeach; ?>
<div class="form-group">
<?= Html::submitButton('Guardar', ['class' => 'btn btn-success']) ?>
</div>
<?php ActiveForm::end(); ?>
Model
public function rules()
{
return [
[['idpregunta', 'idinscripcion'], 'required'],
['respuesta', 'each', 'rule' => ['required']],
[['idpregunta', 'idinscripcion'], 'integer'],
[['respuesta'], 'string', 'max' => 500],
[['idpregunta'], 'exist', 'skipOnError' => true, 'targetClass' => Pregunta::className(), 'targetAttribute' => ['idpregunta' => 'id']],
[['idinscripcion'], 'exist', 'skipOnError' => true, 'targetClass' => Inscripcion::className(), 'targetAttribute' => ['idinscripcion' => 'idInscripcion']],
];
}
Controller
public function actionResponderFormulario($slug){
$evento = $this->findModel("", $slug);
$inscripcion = Inscripcion::find()->where(["idEvento" => $evento->idEvento, "idUsuario" => Yii::$app->user->identity->idUsuario])->one();
$preguntas = Pregunta::find()->where(["idevento" => $evento->idEvento])->all();
$model = new Pregunta();
if($inscripcion ==null){
$preguntas = Pregunta::find()->where(["idevento" => $evento->idEvento])->all();
return $this->render('responderFormulario',
["preguntas" => $preguntas,
"eventos" => $evento,
"model" => $model]);
}
}
The most important thing for me is for the questions to validate in general, I don’t care that much to validate each type separately, because I may remove this later.
Thank you in advance
I think this part of string validation with max length should change to this:
['respueusta', 'each', 'rule' => ['string', 'max' => 500]]
Sometime respuesta field receives the file in tipo=3 , you can not do this for clean and structured code. define another field for files.

how to ignore ajaxValidation in delete action in yii2?

I have a form like follow
<?php widgets\Pjax::begin(['id' => 'authors', 'enablePushState' => false]) ?>
<?php $form = ActiveForm::begin(['id' => $model->formName(),'enableAjaxValidation'=>true,'validationUrl'=>\yii\helpers\Url::toRoute(['paper-author/validation']), 'options' => ['data-pjax' => '']]); ?>
<?php echo $form->field($model, 'FirstName')->textInput()->input('string', ['placeholder' => Yii::t('app', ' FirstName...')])->label(false) ?>
<?php echo $form->field($model, 'LastName')->textInput()->input('string', ['placeholder' => Yii::t('app', ' LastName...')])->label(false) ?>
<?= Html::submitButton('Save', ['class' => 'btn btn-success', 'id' => 'btn1']) ?>
$widget = Yii::createObject([
'class' => 'yii\grid\GridView',
'dataProvider' => $dataprovider,
'columns' => [
'FirstName',
'LastName',
[
'class' => 'yii\grid\ActionColumn',
]
],
]
);
echo $widget->run();
<?php $form = ActiveForm::end(); ?>
<?php widgets\Pjax::end() ?>
and in my model I have some rules:
[['FirstName', 'LastName'],'required']
my controller:
public function actionValidation()
{
$model = new PaperAuthor();
$requestPost = Yii::$app->request->post();
if (Yii::$app->request->isAjax && $model->load($requestPost)) {
Yii::$app->response->format = 'json';
return ActiveForm::validate($model);
}
}
public function actionDelete($id)
{
$this->findModel($id)->delete();
echo Json::encode([
'success' => true,
'messages' => [
Yii::t('app', 'Successfully Deleted.')
],
]);
}
actionCreate works well. but I can't delete any recored from gridview, it throws an validation error(required validation).
what can I do?
thanks in advance.

Yii2: Load modal form and submit data via Ajax without redirecting to view

I have two models in my Yii2 project. One model: ApartmentBuilding depends on another model: Caretaker via a relationship. Assuming I am creating an ApartmentModel via a form whereby I select the caretaker from a dynamic dropdown. I then realize that the caretaker I need is not added yet to the database, hence, I have to add the details of the caretaker from the ApartmentBuilding model form then proceed filling in the details of the ApartmentBulding form. That is the usecase of my problem.
So far, I have managed to launch the Caretaker model form via a modal from the ApartmentBulding form. On submitting the details of the Caretaker model form, the site redirects to the view of the CaretakerController. However, what I need is to be able to get the dropdown form refresh with the new details of the caretaker that I just added via a modal, and be able to proceed with the filling of the rest of the form.
Any help in cracking this will be appreciated.
Here are my codes so far:
ApartmentBuilding _form.php
<?php
use yii\helpers\Html;
use kartik\widgets\ActiveForm;
use app\models\Landlord;
use app\models\Caretaker;
use yii\helpers\ArrayHelper;
use yii\bootstrap\Button;
use yii\helpers\Url;
/* #var $this yii\web\View */
/* #var $model app\models\ApartmentBuilding */
/* #var $form yii\widgets\ActiveForm */
?>
<div class="apartment-building-form">
<?php $form = ActiveForm::begin([
'type' => ActiveForm::TYPE_HORIZONTAL,
'formConfig' => ['labelSpan' => 3, 'deviceSize' => ActiveForm::SIZE_TINY],
]); ?>
<?= $form->field($model, 'apartment_name')->textInput(['maxlength' => true]) ?>
<?= $form->field($model, 'landlord_id')->dropDownList(ArrayHelper::map(Landlord::find()->select(['landlord_id', 'first_name', 'last_name'])->all(), 'landlord_id', 'displayName'),['class' => 'form-control inline-block', 'prompt'=>'Select Landlord']) ?>
<?= $form->field($model, 'physical_address')->textInput(['maxlength' => true]) ?>
<?= $form->field($model, 'plot_number')->textInput(['maxlength' => true]) ?>
<?= $form->field($model, 'address')->widget(\kalyabin\maplocation\SelectMapLocationWidget::className(), [
'attributeLatitude' => 'latitude',
'attributeLongitude' => 'longitude',
'googleMapApiKey' => 'YOUR_API_KEY_HERE',
]) ?>
<?= $form->field($model, 'number_of_floors')->textInput() ?>
<?= $form->field($model, 'apartment_desc')->textInput(['maxlength' => true]) ?>
<div class="form-group kv-fieldset-inline">
<?= Html::activeLabel($model, 'caretaker_id', ['label'=>'Caretaker', 'class'=>'col-sm-3 control-label']) ?>
<div class="col-sm-8">
<?= $form->field($model, 'caretaker_id',['showLabels'=>false])->dropDownList(ArrayHelper::map(Caretaker::find()->select(['caretaker_id', 'first_name', 'last_name'])->all(), 'caretaker_id', 'displayName'),['class' => 'form-control inline-block', 'prompt'=>'Select Caretaker']) ?>
</div>
<div class="col-sm-1">
<?= Html::button('<i class="glyphicon glyphicon-plus"></i>', ['value'=>Url::to(['caretaker/new']), 'title' => 'Create New Caretaker', 'class' => 'btn btn-success showModalButton']) ?>
</div>
</div>
<?= $form->field($model, 'other_apt_details')->textInput(['maxlength' => true]) ?>
<div class="col-sm-offset-3 col-sm-9">
<?= Html::submitButton($model->isNewRecord ? 'Create' : 'Update', ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>
<?= Html::resetButton('Reset', ['class' => 'btn btn-default']) ?>
</div>
<?php ActiveForm::end(); ?>
</div>
Caretaker _form.php
<?php
use yii\helpers\Html;
use kartik\widgets\ActiveForm;
use kartik\widgets\DatePicker;
/* #var $this yii\web\View */
/* #var $model app\models\Caretaker */
/* #var $form yii\widgets\ActiveForm */
?>
<div class="caretaker-form">
<?php $form = ActiveForm::begin([
'type' => ActiveForm::TYPE_HORIZONTAL,
'formConfig' => ['labelSpan' => 3, 'deviceSize' => ActiveForm::SIZE_TINY],
]); ?>
<?= $form->field($model, 'first_name')->textInput(['maxlength' => true]) ?>
<?= $form->field($model, 'last_name')->textInput(['maxlength' => true]) ?>
<?= $form->field($model, 'sex')->dropDownList(['Male' => 'Male', 'Female' => 'Female'],['prompt'=>'Select Sex']) ?>
<?= $form->field($model, 'date_of_birth')->widget(DatePicker::classname(), ['options' => ['placeholder' => 'Enter birth date ...'], 'pluginOptions' => ['autoclose'=>true, 'format' => 'yyyy-mm-dd']]) ?>
<?= $form->field($model, 'address')->textInput(['maxlength' => true]) ?>
<?= $form->field($model, 'mobile')->widget(\yii\widgets\MaskedInput::className(), ['mask' => '254999999999',]) ?>
<div class="col-sm-offset-3 col-sm-9">
<?= Html::submitButton($model->isNewRecord ? 'Create' : 'Update', ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>
<?= Html::resetButton('Reset', ['class' => 'btn btn-default']) ?>
</div>
<?php ActiveForm::end(); ?>
</div>
CaretakerController actionNew()
public function actionNew()
{
$model = new Caretaker();
$model->company_id = Yii::$app->user->identity->company_id;
if ($model->load(Yii::$app->request->post()) && $model->save()) {
return false;
} else {
return $this->renderAjax('create', [
'model' => $model,
]);
}
}
Modal Handler:
<?php
yii\bootstrap\Modal::begin([
'headerOptions' => ['id' => 'modalHeader'],
'id' => 'modal',
'size' => 'modal-lg',
//keeps from closing modal with esc key or by clicking out of the modal.
// user must click cancel or X to close
'clientOptions' => ['backdrop' => 'static', 'keyboard' => FALSE]
]);
echo '<div id="modalContent"><div style="text-align:center"><?= Html::img("#web/img/loading.gif");?></div></div>';
yii\bootstrap\Modal::end();
?>
modal-popup.js
$(function(){
//get the click of modal button to create / update item
//we get the button by class not by ID because you can only have one id on a page and you can
//have multiple classes therefore you can have multiple open modal buttons on a page all with or without
//the same link.
//we use on so the dom element can be called again if they are nested, otherwise when we load the content once it kills the dom element and wont let you load another modal on click without a page refresh
$(document).on('click', '.showModalButton', function(){
//check if the modal is open. if it's open just reload content not whole modal
//also this allows you to nest buttons inside of modals to reload the content it is in
//the if else are intentionally separated instead of put into a function to get the
//button since it is using a class not an #id so there are many of them and we need
//to ensure we get the right button and content.
// if ($('#modal').data('bs.modal').isShown)
if ($("#modal").data('modal') && $("#modal").data('modal').isShown){
$('#modal').find('#modalContent')
.load($(this).attr('value'));
//dynamically set the header for the modal
document.getElementById('modalHeader').innerHTML = '<h4>' + $(this).attr('title') + '</h4>';
} else {
//if modal isn't open; open it and load content
$('#modal').modal('show')
.find('#modalContent')
.load($(this).attr('value'));
//dynamiclly set the header for the modal
document.getElementById('modalHeader').innerHTML = '<h4>' + $(this).attr('title') + '</h4>';
}
});
});
$(function(){
//load the current page with the conten indicated by 'value' attribute for a given button.
$(document).on('click', '.loadMainContent', function(){
$('#main-content').load($(this).attr('value'));
});
});
Note
The modal handler code and the modal-popup.js are reused by several other modals such as view and create forms. The code for the modal handler is in the main.php of the layouts folder.
I have managed to solve the problem by doing the following (More thoughts on the same still welcome, I know there could be more perfect way of doing this):
I added the following Javascript code to the caretaker _form.php
<?php
$this->registerJs("$('#createcaretaker').click(function() {
var firstName = $('#caretaker-first_name').val();
var lastName = $('#caretaker-last_name').val();
var sex = $('#caretaker-sex').val();
var dOB = $('#caretaker-date_of_birth').val();
var address = $('#caretaker-address').val();
var mobile = $('#caretaker-mobile').val();
$('#modal').modal('hide');
$.get('new?firstName='+firstName+'&lastName='+lastName+'&sex='+sex+'&dOB='+dOB+'&address='+address+'&mobile='+mobile, function(success){
$('.refreshcaretaker').html(success);
});
});");
?>
Then, the submit button on the same form, I changed it to:
<button id="createcaretaker" type="button" class="btn btn-success">Create</button>
Hence, the button id is able to trigger the Javascript code above to send data to the server side.
I then created a controller action in the ApartmentBuilding controller to handle the data entry as follows:
public function actionNew($firstName, $lastName, $sex, $dOB, $address, $mobile)
{
$model = new Caretaker();
$model->company_id = Yii::$app->user->identity->company_id;
if ($firstName != '0' && $lastName != '0' && $sex != '0' && $dOB != '0' && $address != '0' && $mobile != '0') {
$model->first_name = $firstName;
$model->last_name = $lastName;
$model->sex = $sex;
$model->date_of_birth = $dOB;
$model->address = $address;
$model->mobile = $mobile;
$model->save();
$caretakers = Caretaker::find()->all();
foreach ($caretakers as $caretaker) {
echo '<option value="'.$caretaker->caretaker_id.'">'.$caretaker->displayName.'</option>';
}
} else {
return $this->renderAjax('caretaker_create', [
'model' => $model,
]);
}
}
Having done that, I changed the dropdown entry of the parent form to be able to refresh its values via ajax upon submitting the modal form to create the caretaker model as follows:
<?= $form->field($model, '[{$i}]caretaker_id',['showLabels'=>false])->dropDownList(ArrayHelper::map(Caretaker::find()->select(['caretaker_id', 'first_name', 'last_name'])->all(), 'caretaker_id', 'displayName'),['class' => 'form-control inline-block refreshcaretaker', 'prompt'=>'Select Caretaker']) ?>
Note the refreshcaretaker class that is triggered by the Javascript code above when the modal is submitted.
The following link talks more about using modal forms in Yii2.

Yii2 updating two related models does not show data of the second

I have two related models in hasToMany relation. The first is Invoices and the second is InvoiceItems. As a prototype process, I'm trying to conjugate the two models through the update view of the InvoicesController using the following code in actionUpdate of InvoicesController:
...
use common\models\Invoices;
use common\models\InvoicesSearch;
use common\models\InvoiceItems;
...
public function actionUpdate($id)
{
$model = $this->findModel($id);
$invoiceItems = new InvoiceItems();
if ($model->load(Yii::$app->request->post()) && $model->save()) {
$invoiceItems->invoice_id = $model->id;
if ($invoiceItems->load(Yii::$app->request->post()) && $invoiceItems->save()){
return $this->redirect(['view', 'id' => $model->id]);
}
else{
// return false;
}
} else {
$invoiceItems->invoice_id = $model->id;
return $this->render('update', [
'model' => $model,
'invoiceItems' => $invoiceItems,
]);
}
}
The following in update view:
<div class="invoices-update">
<h1><?= Html::encode($this->title) ?></h1>
<?= $this->render('_form', [
'model' => $model,
'invoiceItems' => $invoiceItems,
]) ?>
</div>
Finally, the following in _form view:
<div class="invoices-form">
<?php $form = ActiveForm::begin(); ?>
<?= $form->field($model, 'created')->textInput() ?>
<?= $form->field($model, 'type')->textInput(['maxlength' => true]) ?>
<hr />
<?= $form->field($invoiceItems, 'item_id')->textInput();?>
<?= $form->field($invoiceItems, 'unit_id')->textInput();?>
<?= $form->field($invoiceItems, 'qty')->textInput();?>
<div class="form-group">
<?= Html::submitButton($model->isNewRecord ? Yii::t('app', 'Create') : Yii::t('app', 'Update'), ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>
</div>
<?php ActiveForm::end(); ?>
</div>
The above code succeeded in saving data in invoice_items table. However, the update view form has empty fields for InvoiceItems model. i.e item_id, unit_id and qty are empty in the update form after saving.
Notice: This is initial code, i.e I will work later to be able to add many items to the invoice, but now I just try to have one item related to the invoice.
Seems the update view is empty because you render and empty InvoceItmes ..
$invoiceItems = new InvoiceItems();
you render update view in else section and this section the value posted are not loaded
$model = $this->findModel($id);
$invoiceItems = new InvoiceItems();
if ($model->load(Yii::$app->request->post()) && $model->save()) {
$invoiceItems->invoice_id = $model->id;
if ($invoiceItems->load(Yii::$app->request->post()) && $invoiceItems->save()){
return $this->redirect(['view', 'id' => $model->id]);
}
else{
// return false;
}
} else {//****** here the $invoceItems is empty (It has just been created) ***
//$invoiceItems->invoice_id = $model->id;
$invoceItems= findInvoceItmesModel($model->id);
return $this->render('update', [
'model' => $model,
'invoiceItems' => $invoiceItems,
]);
}
for populate the data for $invoceItems you need somethings like
protected function findInvoiceItemsModel($id)
{
if (($model = InvociceItems::findOne($id)) !== null) {
return $model;
} else {
throw new NotFoundHttpException('The requested page does not exist.');
}
}
Obviously this is for a single model.. you must refactory form more than one..

Yii2 EachValidator doesn't work

I have form with array attributes. I tried to use eachValidator, but it doesn't work. To test validator I create simle form, but each rule still doesn't work.
Model:
<?php
namespace frontend\models;
use common\models\User;
use yii\base\Model;
use Yii;
class Test extends Model
{
public $test;
public function rules()
{
return [
[['test'],'each','rule'=>['required']],
];
}
public function someFunc()
{
return null;
}
}
Controller:
public function actionTest()
{
$model = new Test();
return $this->render('test', [
'model' => $model,
]);
}
View:
<?php
use yii\helpers\Html;
use yii\bootstrap\ActiveForm;
?>
<div class="row">
<div class="col-lg-12">
<?php $form = ActiveForm::begin(['id' => 'test',]); ?>
<?= $form->field($model, 'test[]')->textInput(['placeholder'=>'test'])->label('Test'); ?>
<?= $form->field($model, 'test[]')->textInput(['placeholder'=>'test'])->label('Test'); ?>
<?= $form->field($model, 'test[]')->textInput(['placeholder'=>'test'])->label('Test'); ?>
<div class="form-group">
<?= Html::submitButton('Get started', ['class' => 'btn btn-primary', 'name' => 'signup-button']) ?>
</div>
<?php ActiveForm::end(); ?>
</div>
</div>
Form successfully submitted with empty fields.
I have Yii 2.0.6
Can enybody tell what I'm doing wrong and how can I validate array attributes?
yii\validators\EachValidator does not validate data on client side, you should simply call validate() or save() in your controller :
public function actionTest()
{
$model = new Test();
if ($model->load(Yii::$app->request->post()) && $model->save()) {
// do what you want
}
return $this->render('test', [
'model' => $model,
]);
}

Resources