This function was build manually, but we want to know if there is a way, using Yii 2, of getting the model JS validation function automatically. We did so just to test.
Question:
How should we do this, without manually build this for each submodel form field?
JavaScript to add dynamic submodels' fields:
var horsePreferredFoodValidateFunction = function(attribute, value, messages) {
yii.validation.required(value, messages, {"message": "mandatory field"});
};
$(window).load(function() {
$('.container').on('click', '#add-horse-preferred-food', function() {
var horsePreferredFoodsCount = (parseInt($('#horsePreferredFoodsCount').val())) + 1;
$.post(
'/horse/add-horse-preferred-food',
{index : horsePreferredFoodsCount},
function(data) {
$('#horsePreferredFoodsCount').val(horsePreferredFoodsCount);
$("#horse-preferred-food-list").append(data);
var horseForm = $('#horse-form');
console.log(horseForm.data('yiiActiveForm'));
How should we do the attributes adding if we have a submodel with many fields?
$(horseForm).yiiActiveForm('add', {
id: 'horsepreferredfood-' + horsePreferredFoodsCount + '-name',
input: '#horsepreferredfood-' + horsePreferredFoodsCount + '-name',
name: 'name',//'[' + horsePreferredFoodsCount + '][name]',
container: '.field-horsepreferredfood-' + horsePreferredFoodsCount + '-name',
validate: horsePreferredFoodValidateFunction,
error: '.help-block.help-block-error'
});
console.log(horseForm.data('yiiActiveForm'));
}
);
});
});
function removeHorsePreferredFood(id) {
$('#div-horse-preferred-food-' + id).remove();
}
Aditional info:
HorsePreferredFood's rules:
public function rules()
{
return [
[['name', 'horse_id'], 'required'],
[['horse_id'], 'integer'],
[['name'], 'string', 'max' => 255]
];
}
The main form (horse/_form.php):
<div class="horse-form">
<?php
$form = ActiveForm::begin(
[
'id' => 'horse-form',
'action' => '/horse/' . (($horse->isNewRecord) ? 'create' : 'update/' . $horse->id),
'errorCssClass' => 'errorMessage',
]
);
?>
<?= $form->field($horse, 'name')->textInput(['maxlength' => 255]) ?>
<?= $form->field($horse, 'age')->textInput() ?>
<!-- HORSE PREFERRED FOODS -->
<fieldset class="fieldset">
<legend>Comidas Preferidas:</legend>
<div id ="horse-preferred-food-list">
<?php
$horsePreferredFoodsCount = count($horsePreferredFoods);
foreach ($horsePreferredFoods as $horsePreferredFoodIndex => $horsePreferredFood) {
$this->renderPartial(
'/horsePreferredFood/_form',
array(
'index' => $horsePreferredFoodIndex,
'horsePreferredFood' => $horsePreferredFood,
'form' => $form,
)
);
echo $form->field($horsePreferredFood, 'name')->textInput(['maxLength' => 255]);
}
?>
</div>
<div class="form-group">
<?php
echo \yii\bootstrap\Button::widget(
[
'label' => 'Adicionar Comida Preferida',
'options' => [
'id' => 'add-horse-preferred-food',
'class' => 'btn-lg',
],
]
);
?>
</div>
</fieldset>
<div class="form-group">
<?= Html::submitButton(
$horse->isNewRecord ?
'Criar' : 'Alterar',
[
'class' => $horse->isNewRecord ?
'btn btn-success' : 'btn btn-primary'
]
); ?>
</div>
<?php
ActiveForm::end();
echo Html::hiddenInput(
'horsePreferredFoodsCount',
$horsePreferredFoodsCount,
[
'id' => 'horsePreferredFoodsCount',
]
);
?>
</div>
The submodel form (horsePreferredFood/_form.php):
<?php
if (isset($isAjaxCall) && ($isAjaxCall)) {
$horsePreferredFood = new \app\models\HorsePreferredFood();
} else {
$isAjaxCall = false;
}
if (! isset($form)) {
$form = \yii\bootstrap\ActiveForm::begin(
[
'id' => 'horse-form',
'enableAjaxValidation' => false,
'enableClientValidation' => true,
]
);
}
?>
<div class="form" id="div-horse-preferred-food-<?php echo $index; ?>">
<fieldset class="fieldset">
<div class="form-group">
<?php
echo \yii\helpers\Html::activeHiddenInput($horsePreferredFood, "[$index]id");
echo $form->field($horsePreferredFood, "[$index]name")->textInput(['maxlength' => 255]);
?>
</div>
</fieldset>
<div class="form-group">
<?php
echo \yii\bootstrap\Button::widget(
[
'label' => 'Remover Comida Preferida',
'options' => [
'id' => "btn-remove-horse-preferred-food-$index",
'class' => 'btn-lg',
'onClick' => "removeHorsePreferredFood($index);",
],
]
);
?>
</div>
</div>
In HorseController, the action invoked via AJAX to return the submodel fields:
public function actionAddHorsePreferredFood() {
$index = $_POST['index'];
$partialView = "/horsePreferredFood/_form";
return $this->renderPartial(
$partialView,
[
'index' => $index,
'isAjaxCall' => true,
]
);
}
Related
I am trying to use select2 querying the database because there are 30000 records this is really the only efficient way I could think of.
My problem is if I just submit this form the pole_id doesn't update.
Can someone help either with jQuery getting the id or telling me why the select box doesn't update the pole_id field in the db?
<?php
/* #var $this JpapolesController */
/* #var $model Jpapoles */
/* #var $form CActiveForm */
?>
<div class="form">
<?php $form=$this->beginWidget('CActiveForm', array(
'id'=>'jpapoles-form',
'enableAjaxValidation'=>false,
)); ?>
<p class="note">Fields with <span class="required">*</span> are required.</p>
<?php echo $form->errorSummary($model); ?>
<div class="row">
<?php echo $form->labelEx($model,'pole_id'); ?>
<?php //echo $form->textField($model,'pole_id',array('id'=>'pole_id')); ?>
<?php
$list = CHtml::listData(Poles::model()->findAll(array('order' => 'pole_number')), 'id', 'pole_number');
//echo $form->dropDownList($model, 'pole_id', $list, array('class'=>"js-example-basic-multiple", 'name'=>'pole_id', 'multiple'=>'multiple'));
//
echo CHtml::hiddenField('selectbox_pole_id', '', array('class' => 'span5'));
$this->widget('ext.select2.ESelect2',array(
'id'=>'myselect',
'selector' => '#selectbox_pole_id',
'options' => array(
'allowClear'=>true,
'placeholder'=>'Select a Pole',
'minimumInputLength' => 3,
'ajax' => array(
'url' => Yii::app()->createUrl('jpapoles/poles'),
'type'=>'GET',
'dataType' => 'json',
'quietMillis'=> 100,
'data' => 'js: function(text,page) {
return {
q: text,
page_limit: 10,
page: page,
};
}',
'results'=>'js:function(data,page) { var more = (page * 10) < data.total; return {results: data, more:more };
}
',
),
),
));
?>
<?php echo $form->error($model,'pole_id'); ?>
</div>
<div class="row">
<?php echo $form->labelEx($model,'member_id'); ?>
<?php //echo $form->textField($model,'member_id'); ?>
<?php
$list = CHtml::listData(Members::model()->findAll(array('order' => 'abriviation')), 'id', 'abriviation');
echo $form->dropDownList($model, 'member_id', $list);
?>
<?php echo $form->error($model,'member_id'); ?>
</div>
<div class="row">
<?php //echo $form->labelEx($model,'jpa_id'); ?>
<?php echo $form->hiddenField($model,'jpa_id', array('value'=>$_GET['jpano'])); ?>
<?php echo $form->error($model,'jpa_id'); ?>
</div>
<div class="row buttons">
<?php echo CHtml::submitButton($model->isNewRecord ? 'Create' : 'Save'); ?>
</div>
<?php $this->endWidget(); ?>
</div><!-- form -->
<script type="javascript">
$("#myselect").on("change", function (e) {
var id = $("#myselect").select2("data")[0].id;
// Now you can work with the selected value, i.e.:
//$("#pole_id").val(id);
alert(id);
});
</script>
You can just use CActiveForm::hiddenField() to generate this hidden input:
<div class="row">
<?php echo $form->labelEx($model, 'pole_id'); ?>
<?php
echo $form->hiddenField($model, 'pole_id', ['id'=>'pole_id']);
$this->widget('ext.select2.ESelect2', [
'id' => 'myselect',
'selector' => '#' . CHtml::activeId($model, 'pole_id'),
'options' => [
'allowClear' => true,
'placeholder' => 'Select a Pole',
'minimumInputLength' => 3,
'ajax' => [
'url' => Yii::app()->createUrl('jpapoles/poles'),
'type' => 'GET',
'dataType' => 'json',
'quietMillis' => 100,
'data' => 'js: function(text,page) {
return {
q: text,
page_limit: 10,
page: page,
};
}',
'results' => 'js:function(data,page) {
var more = (page * 10) < data.total; return {results: data, more:more };
}',
],
],
]);
?>
<?php echo $form->error($model, 'pole_id'); ?>
</div>
It will correctly handle existing data and no special actions are required in controller to handle this input - $model->attributes = $_POST['Jpapoles'] will load pole_id as any other attribute.
But this extension should also work with models direly, so you can just use:
$this->widget('ext.select2.ESelect2', [
'model' => $model,
'attribute' => 'pole_id',
'options' => [
// ...
],
]);
The you don't need to create hidden filed yourself.
Two parts:
one I decided to var_dump in the controller action:
Which resulted in me discovering that hidden field with id: selectbox_pole_id is where the posted value was.
So, I renamed that id to match the db id pole_id and added the following line before save: $model->pole_id = $_POST['pole_id'];
public function actionCreate()
{
$model=new Jpapoles;
// Uncomment the following line if AJAX validation is needed
// $this->performAjaxValidation($model);
if(isset($_POST['Jpapoles']))
{
$model->attributes=$_POST['Jpapoles'];
$model->pole_id = $_POST['pole_id'];
if($model->save())
//$this->redirect(array('jpas/view','id'=>$_GET['jpano']));
var_dump($_REQUEST);
//echo $_POST['pole_id'];
}
$this->renderPartial('create',array(
'model'=>$model
),false,true);
}
/* #var $this JpapolesController */
/* #var $model Jpapoles */
/* #var $form CActiveForm */
?>
<div class="form">
<?php $form=$this->beginWidget('CActiveForm', array(
'id'=>'jpapoles-form',
'enableAjaxValidation'=>false,
)); ?>
<p class="note">Fields with <span class="required">*</span> are required.</p>
<?php echo $form->errorSummary($model); ?>
<div class="row">
<?php echo $form->labelEx($model,'pole_id'); ?>
<?php
echo CHtml::hiddenField('pole_id', '', array('class' => 'span5'));
$this->widget('ext.select2.ESelect2',array(
'id'=>'myselect',
'selector' => '#pole_id',
'model'=>$model,
'attribute'=>'pole_id',
'options' => array(
'allowClear'=>true,
'placeholder'=>'Select a Pole',
'minimumInputLength' => 3,
'ajax' => array(
'url' => Yii::app()->createUrl('jpapoles/poles'),
'type'=>'GET',
'dataType' => 'json',
'quietMillis'=> 100,
'data' => 'js: function(text,page) {
return {
q: text,
page_limit: 10,
page: page,
};
}',
'results'=>'js:function(data,page) { var more = (page * 10) < data.total; return {results: data, more:more };
}
',
),
),
));
?>
<?php echo $form->error($model,'pole_id'); ?>
</div>
<div class="row">
<?php echo $form->labelEx($model,'member_id'); ?>
<?php //echo $form->textField($model,'member_id'); ?>
<?php
$list = CHtml::listData(Members::model()->findAll(array('order' => 'abriviation')), 'id', 'abriviation');
echo $form->dropDownList($model, 'member_id', $list);
?>
<?php echo $form->error($model,'member_id'); ?>
</div>
<div class="row">
<?php //echo $form->labelEx($model,'jpa_id'); ?>
<?php echo $form->hiddenField($model,'jpa_id', array('value'=>$_GET['jpano'])); ?>
<?php echo $form->error($model,'jpa_id'); ?>
</div>
<div class="row buttons">
<?php echo CHtml::submitButton($model->isNewRecord ? 'Create' : 'Save'); ?>
</div>
<?php $this->endWidget(); ?>
</div><!-- form -->
<script type="text/javascript">
// Or for single select elements:
$("#select").select2({
initSelection : function (element, callback) {
var data = {id: element.val(), text: element.val()};
callback(data);
}
});
</script>
I am working on yii2. In one of my view, I am trying to upload an image. But I am unable to upload it.
Model
class MeterAcceptanceHeader extends \yii\db\ActiveRecord
{
public static $status_titles =[
0 => 'Prepared',
1 => 'Created',
2 => 'Printed',
3 => 'Canceled',
];
/**
* #inheritdoc
*/
public static function tableName()
{
return 'meter_acceptance_header';
}
/**
* #inheritdoc
*/
public function rules()
{
return [
[['sub_div', 'prepared_by'], 'required'],
[['prepared_by', 'updated_by'], 'integer'],
[['prepared_at', 'updated_at'], 'safe'],
[['sub_div', 'meter_type', 'status'], 'string', 'max' => 100],
[['images'], 'string', 'max' => 255],
[['images'], 'file', 'skipOnEmpty' => true, 'extensions' => 'png,jpg,pdf', 'maxFiles' => 4],
[['sub_div'], 'exist', 'skipOnError' => true, 'targetClass' => SurveyHescoSubdivision::className(), 'targetAttribute' => ['sub_div' => 'sub_div_code']],
[['prepared_by'], 'exist', 'skipOnError' => true, 'targetClass' => User::className(), 'targetAttribute' => ['prepared_by' => 'id']],
];
}
/**
* #inheritdoc
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'sub_div' => 'Sub Div',
'meter_type' => 'Meter Type',
'prepared_by' => 'Prepared By',
'prepared_at' => 'Prepared At',
'updated_at' => 'Updated At',
'status' => 'Status',
'updated_by' => 'Updated By',
'images' => 'Document Snap',
];
}
/**
* #return \yii\db\ActiveQuery
*/
public function getMeterAcceptanceDetails()
{
return $this->hasMany(MeterAcceptanceDetails::className(), ['accpt_id' => 'id']);
}
/**
* #return \yii\db\ActiveQuery
*/
public function getSubDiv()
{
return $this->hasOne(SurveyHescoSubdivision::className(), ['sub_div_code' => 'sub_div']);
}
/**
* #return \yii\db\ActiveQuery
*/
public function getPrepared()
{
return $this->hasOne(User::className(), ['id' => 'prepared_by']);
}
}
MeterAcceptanceHeader Table
MeterAcceptanceImages Table
There is a form1 in which user is prompt to select from the dropdown.
Form1 View
<div class="meter-acceptance-header-form">
<?php $model->status = common\models\MeterAcceptanceHeader::$status_titles[0]; ?>
<?php $form = ActiveForm::begin(['id'=>'acceptance-form','options' => ['enctype' => 'multipart/form-data']]); ?>
<?= $form->field($model, 'sub_div')->dropDownList([''=>'Please Select'] + \common\models\SurveyHescoSubdivision::toArrayList()) ?>
<?= $form->field($model, 'meter_type')->dropDownList([''=>'Please Select','Single-Phase' => 'Single-Phase', '3-Phase' => '3-Phase', 'L.T.TOU' => 'L.T.TOU']) ?>
<?= $form->field($model, 'status')->textInput(['maxlength' => true,'readonly' => true]) ?>
<div class="form-group">
<a class="btn btn-default" onclick="window.history.back()" href="javascript:;"><i
class="fa fa-close"></i>
Cancel</a>
<a class="<?= $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary' ?>" onclick="
$('#acceptance-form').submit();" href="javascript:">
<?= $model->isNewRecord ? 'Create' : 'Update' ?></a>
</div>
<?php ActiveForm::end(); ?>
After clicking on Create button the user is prompt to the second form in which a user will upload an image.
Below is my code for the controller from which I am trying to upload it.
public function actionSetpdf($id)
{
$model = $this->findModel($id);
$m = 0;
$accpt_id = $model->id;
$meter_type = $model->meter_type;
$ogp_sub_div = $model->sub_div;
$images=[];
$ic=0;
$files_uploaded = false;
if(Yii::$app->request->isAjax && Yii::$app->request->post())
{
$data = explode(',',$_POST['data']);
foreach($data as $value)
{
$m = new MeterAcceptanceDetails;
$m -> load(Yii::$app->request->post());
$m->accpt_id = $accpt_id;
$m->meter_type = $meter_type;
$m->created_at = date('Y-m-d H:i:s');
$m->created_by = Yii::$app->user->id;
$m->meter_id = $value;
$m->meter_msn = \common\models\Meters::idTomsn($value);
$m->flag = 1;// 1 means created
$m->ogp_sub_div = $ogp_sub_div;
if($m->save())
{
// Here the upload image code starts
if($ic==0)
{
$model->images = UploadedFile::getInstances($model, 'images');
foreach ($model->images as $file)
{
if (file_exists($file->tempName))
{
$img_s = new MeterAcceptanceImages;
$file_name = rand(0, 1000) . time().date('his') . '.' . $file->extension;
$file->saveAs('uploads/meter_acceptance/' . $file_name);
$img_s->file_path = $file_name;
$img_s->accpt_id = $accpt_id;
if ($img_s->save()) {
$images[] = $img_s;
} else {
print_r($img_s->getErrors());
}
}
}
}else{
foreach($images as $image){
$img_s = new MeterAcceptanceImages;
$img_s->file_path = $image->file_path;
$img_s->accpt_id = $accpt_id;
$img_s->save();
}
}
$model->status = MeterAcceptanceHeader::$status_titles[1];
$model->update();
}
else{
$this->renderAjax('viewcreated');
}
}
}
else{
$this->renderAjax('viewcreated');
}
return $this->redirect(Url::toRoute(['meteracceptanceheader/viewsetpdf','id' => $model->id,'model' => $this->findModel($id)]));
}
Form2 View
<div class="map-meters-form" id="doc">
<?php $form = ActiveForm::begin(['id' => 'map-form', 'enableClientValidation' => true, 'enableAjaxValidation' => false,
'options' => ['enctype' => 'multipart/form-data']]) ?>
<section class="content">
<div class="box">
<div id="chk" class="box-body">
<?php Pjax::begin(); ?>
<?= DetailView::widget([
'model' => $model,
'attributes' => [
[
'label'=>'Serial #',
'value' => function($d)
{
return $d->id;
}
],
[
'label' => 'Meter Type',
'value' => function ($d) {
if(is_object($d))
return $d->meter_type;
return ' - ';
},
],
'sub_div',
[
'label' => 'Sub Division Name',
'value' => function ($d) {
if(is_object($d))
return $d->subDiv->name;
return '-';
},
],
[
'label' => 'Prepared By',
'value' => function ($d) {
if(is_object($d))
return $d->prepared->name;
},
],
'prepared_at',
'status',
],
]) ?>
<br>
<div class="pre-scrollable">
<?= GridView::widget([
'dataProvider' => $dataProvider,
//'ajaxUpdate' => true,
'filterModel' => false,
//'id'=>'gv',
'columns' => [
['class' => 'yii\grid\SerialColumn'],
['class' => 'yii\grid\CheckboxColumn', 'checkboxOptions' => function($d) {
return ['value' => $d['meter_id']];
}],
'Meter_Serial_Number',
'Meter_Type',
'Sub_Division_Code',
'Sub_Division_Name',
],
]); ?>
</div>
<?php Pjax::end(); ?>
<?= $form->field($model, 'images[]')->fileInput(['multiple' => true, 'accept' => 'image/*'])?>
<br>
<form>
<p>
Submit
<br/>
</p>
</form>
</div>
</div>
</section>
<?php ActiveForm::end(); ?>
</div>
<?php
$url = Url::toRoute(['/meteracceptanceheader/setpdf','id'=>$model->id]);
$script = <<< JS
$(document).ready(function () {
$(document).on('pjax:end', function() {
$("#chk").find("input:checkbox").prop("checked", true);
});
$("#chk").find("input:checkbox").prop("checked", true);
$('#myid').on('click',function(e) {
e.preventDefault();
var strValue = "";
$('input[name="selection[]"]:checked').each(function() {
if(strValue!=="")
{
strValue = strValue + " , " + this.value;
}
else
strValue = this.value;
});
$.ajax({
url: '$url',
type: 'POST',
dataType: 'json',
data: {data:strValue},
success: function(data) {
alert(data);
}
});
})
});
JS;
$this->registerJs($script, \yii\web\View::POS_END);
?>
This will allow selecting an image. Now when I try to click submit button I am getting below error
PHP Notice 'yii\base\ErrorException' with message 'Undefined offset: 0'
in
E:\xampp\htdocs\inventory-web\vendor\yiisoft\yii2\db\Command.php:330
By debugging the controller code I found that the error comes at foreach ($model->images as $file) as print_r($model->images) return Array() empty.
By doing print_r($model) I got
common\models\MeterAcceptanceHeader Object ( [_attributes:yii\db\BaseActiveRecord:private] => Array ( [id] => 1 [sub_div] => 37111 [meter_type] => L.T.TOU [prepared_by] => 12 [prepared_at] => 2018-08-20 12:41:27 [updated_at] => [status] => Prepared [updated_by] => [images] => Array ( ) ) [_oldAttributes:yii\db\BaseActiveRecord:private] => Array ( [id] => 1 [sub_div] => 37111 [meter_type] => L.T.TOU [prepared_by] => 12 [prepared_at] => 2018-08-20 12:41:27 [updated_at] => [status] => Prepared [updated_by] => [images] => ) [_related:yii\db\BaseActiveRecord:private] => Array ( ) [_errors:yii\base\Model:private] => [_validators:yii\base\Model:private] => [_scenario:yii\base\Model:private] => default [_events:yii\base\Component:private] => Array ( ) [_behaviors:yii\base\Component:private] => Array ( ) )
I have used the same process in other modules as well and it works properly.
How can I get rid of this problem?
Update 1
<?php
use yii\helpers\Html;
use yii\grid\GridView;
use yii\helpers\Url;
use app\models\User;
use yii\widgets\DetailView;
use yii\widgets\ActiveForm;
use yii\widgets\Pjax;
use kartik\select2\Select2;
use kartik\file\FileInput;
/* #var $this yii\web\View */
/* #var $dataProvider yii\data\ActiveDataProvider */
$this->title = $model->id;
$this->title = 'Meter Acceptance Form';
$this->params['breadcrumbs'][] = $this->title;
?>
<section class="content-header">
<h1>Meter Acceptance</h1>
</section>
<div class="map-meters-form" id="doc">
<section class="content">
<div class="box">
<div id="chk" class="box-body">
<?php Pjax::begin(); ?>
<?=
DetailView::widget([
'model' => $model,
'attributes' => [
[
'label' => 'Serial #',
'value' => function($d){
return $d->id;
}
],
[
'label' => 'Meter Type',
'value' => function ($d){
if( is_object($d) )
return $d->meter_type;
return ' - ';
},
],
'sub_div',
[
'label' => 'Sub Division Name',
'value' => function ($d){
if( is_object($d) )
return $d->subDiv->name;
return '-';
},
],
[
'label' => 'Prepared By',
'value' => function ($d){
if( is_object($d) )
return $d->prepared->name;
},
],
'prepared_at',
'status',
],
])
?>
<br>
<div class="pre-scrollable">
<?=
GridView::widget([
'dataProvider' => $dataProvider,
//'ajaxUpdate' => true,
'filterModel' => false,
//'id'=>'gv',
'columns' => [
['class' => 'yii\grid\SerialColumn'],
['class' => 'yii\grid\CheckboxColumn', 'checkboxOptions' => function($d){
return ['value' => $d['meter_id']];
}],
'Meter_Serial_Number',
'Meter_Type',
'Sub_Division_Code',
'Sub_Division_Name',
],
]);
?>
</div>
<?php Pjax::end(); ?>
<?php
$form = ActiveForm::begin(['id' => 'map-form', 'enableClientValidation' => true, 'enableAjaxValidation' => false,
'options' => ['enctype' => 'multipart/form-data']])
?>
<?=$form->field($model, 'images[]')->fileInput(['multiple' => true, 'accept' => 'image/*']) ?>
<br>
<p>
Submit
<br/>
</p>
<?php ActiveForm::end(); ?>
</div>
</div>
</section>
</div>
<?php
$url = Url::toRoute(['/meteracceptanceheader/setpdf','id'=>$model->id]);
$script = <<< JS
$(document).ready(function () {
$(document).on('pjax:end', function() {
$("#chk").find("input:checkbox").prop("checked", true);
});
$("#chk").find("input:checkbox").prop("checked", true);
$('#myid').on('click',function(e) {
e.preventDefault();
//START Append form data
var data = new FormData();
var files= $('input[name="MeterAcceptanceHeader[images][]"]')[0].files;
//append files
$.each(files,function(index,file){
data.append("MeterAcceptanceHeader[images][]",file,file.name);
});
var strValue = "";
$('input[name="selection[]"]:checked').each(function() {
if(strValue!=="")
{
strValue = strValue + " , " + this.value;
}
else
strValue = this.value;
});
//alert(strValue);
//append your query string to the form data too
data.append('data',strValue);
//END append form data
$.ajax({
url: '$url',
type: 'POST',
dataType: 'json',
contentType: false,
processData: false,
data: {data:strValue},
success: function(data) {
alert(data);
}
});
})
});
JS;
$this->registerJs($script, \yii\web\View::POS_END);
?>
Any help would be highly appreciated.
What looks like that you are trying to submit an image via Ajax call when you click on submit button in the step 2 for image upload as you are binding the click to the #myid which is the anchor button
Submit
And if you are trying to send the image via ajax you need to use the FormData interface.
The FormData interface provides a way to easily construct a set of
key/value pairs representing form fields and their values, which can
then be easily sent using the XMLHttpRequest.send() method. It uses
the same format a form would use if the encoding type were set to
"multipart/form-data".
But before I address how to do it, you need to look into some other issues related to Form2 view.
You are nesting the 2 forms which is technically wrong and you can't do that see Why.
Above all why are you creating a separate form for the submit button?
see this line on top
<?php $form = ActiveForm::begin(['id' => 'map-form', 'enableClientValidation' => true, 'enableAjaxValidation' => false,
'options' => ['enctype' => 'multipart/form-data']]) ?>
This is where your first form starts and the file input field
<?= $form->field($model, 'images[]')->fileInput(['multiple' => true, 'accept' => 'image/*'])?>
is inside this form, and on the very next line you have the anchor button that i mentioned above in the start but you are wrapping it inside a separate form and that too before you close the ActiveForm
<form>
<p>
Submit
<br/>
</p>
</form>
instead you are closing the ActiveForm after this form by calling <?php ActiveForm::end(); ?>. As you have seen in the previous question that you faced weird behavior with the filter inputs for the GridVew as you were wrapping the GridView inside the form, and you are repeating that same mistake here too and also nesting 2 forms within.
What i will advise you to do first
Remove the form that you are creating just for the anchor button, as you wont be needing it if you want to submit the image via ajax by clicking on the anchor just keep the anchor inside the main ActiveForm. And Move the ActiveForm::begin() just before the fileInput() and after the Pjax::end().
With that said you should now user FormData to upload the image via ajax and to do so you have to add these options contentType: false and processData: false inside your ajax call and use FormData.append() to append the input files to the FormData.
So your javascript for the click function will look like this, i assume the model used for the image upload is MeterAcceptanceImages
$('#myid').on('click',function(e) {
event.preventDefault();
//START Append form data
let data = new FormData();
let files= $("input[name='MeterAcceptanceImages[images][]']")[0].files;
//append files
$.each(files,function(index,file){
data.append('MeterAcceptanceImages[images][]',file,file.name);
});
var strValue = "";
$('input[name="selection[]"]:checked').each(function() {
if(strValue!==""){
strValue = strValue + " , " + this.value;
}else{
strValue = this.value;
}
});
//append your query string to the form data too
data.append('data',strValue);
//END append form data
$.ajax({
url: '$url',
type: 'POST',
dataType: 'json',
contentType: false,
processData: false,
data: data,
success: function(data) {
alert(data);
}
});
});
So overall your view Form2.php should look like below
<div class="map-meters-form" id="doc">
<section class="content">
<div class="box">
<div id="chk" class="box-body">
<?php Pjax::begin(); ?>
<?=
DetailView::widget([
'model' => $model,
'attributes' => [
[
'label' => 'Serial #',
'value' => function($d){
return $d->id;
}
],
[
'label' => 'Meter Type',
'value' => function ($d){
if( is_object($d) )
return $d->meter_type;
return ' - ';
},
],
'sub_div',
[
'label' => 'Sub Division Name',
'value' => function ($d){
if( is_object($d) )
return $d->subDiv->name;
return '-';
},
],
[
'label' => 'Prepared By',
'value' => function ($d){
if( is_object($d) )
return $d->prepared->name;
},
],
'prepared_at',
'status',
],
])
?>
<br>
<div class="pre-scrollable">
<?=
GridView::widget([
'dataProvider' => $dataProvider,
//'ajaxUpdate' => true,
'filterModel' => false,
//'id'=>'gv',
'columns' => [
['class' => 'yii\grid\SerialColumn'],
['class' => 'yii\grid\CheckboxColumn', 'checkboxOptions' => function($d){
return ['value' => $d['meter_id']];
}],
'Meter_Serial_Number',
'Meter_Type',
'Sub_Division_Code',
'Sub_Division_Name',
],
]);
?>
</div>
<?php Pjax::end(); ?>
<?php
$form = ActiveForm::begin(['id' => 'map-form', 'enableClientValidation' => true, 'enableAjaxValidation' => false,
'options' => ['enctype' => 'multipart/form-data']])
?>
<?=$form->field($model, 'images[]')->fileInput(['multiple' => true, 'accept' => 'image/*']) ?>
<br>
<p>
Submit
<br/>
</p>
<?php ActiveForm::end(); ?>
</div>
</div>
</section>
</div>
<?php
$url = Url::toRoute(['/meteracceptanceheader/setpdf', 'id' => $model->id]);
$script = <<< JS
$(document).ready(function () {
$(document).on('pjax:end', function() {
$("#chk").find("input:checkbox").prop("checked", true);
});
$("#chk").find("input:checkbox").prop("checked", true);
$('#myid').on('click',function(e) {
event.preventDefault();
//START Append form data
let data = new FormData();
let files= $("input[name='MeterAcceptanceImages[images][]']")[0].files;
//append files
$.each(files,function(index,file){
data.append('MeterAcceptanceImages[images][]',file,file.name);
});
var strValue = "";
$('input[name="selection[]"]:checked').each(function() {
if(strValue!==""){
strValue = strValue + " , " + this.value;
}else{
strValue = this.value;
}
});
//append your query string to the form data too
data.append('data',strValue);
//END append form data
$.ajax({
url: '$url',
type: 'POST',
dataType: 'json',
contentType: false,
processData: false,
data: data,
success: function(data) {
alert(data);
}
});
});
});
JS;
$this->registerJs($script, \yii\web\View::POS_END);
?>
Now if you try to print_r(UploadedFile::getInstances('images')) should show you all the images you selected and submitted to upload. To troubleshoot in case of errors while uploading of the ajax call you can see my answer i posted previously related to ajax file uploads.
I have been searching for the solution for the past few days but i could not get the correct solution include posting it to stackoverflow before Submitting Button Value to Controller but fail to post the value, but i decided to submit it again because the problem has changed since i already know the error.
I want to post multiple submit button to controller in yii2, at first i can get the submitbutton value from $_POST['chosen'] in controller if the code looks like (below):
<?php $form =ActiveForm::begin() ?>
<hr>
<div class="row">
<div style="float:left" >
<?= Html::submitButton('Add Row', [ 'name' => 'chosen', 'value' => 'addmore', 'class' => 'btn btn-info']) ?>
</div>
<div style="float:right" >
<?= Html::submitButton('Next Page', ['class' => 'btn btn-primary', 'name' => 'chosen', 'value' => 'nextpage']) ?>
</div>
</div>
<?php ActiveForm::end()?>
but when i add my function to generate a div, i could not get the $_POST['chosen'] anymore, but i still can get the $model object in controller. the function (addRelationForm) is used to generate div object dynamically so i can submit undertermined-size of array to the controlleer. i could add dynamically the div by pressing add row button.
<?php
use kartik\widgets\RangeInput;
use yii\app\clientScript;
use yii\bootstrap\ActiveForm;
use yii\helpers\Html;
use frontend\models\relation;
$this->registerJsFile('http://code.jquery.com/jquery-2.1.4.min.js');
function addRelationForm($form, $item, $i){
return '<div class="col-md-12" id=\'r_'.($i).'\'>
<div class="form-group col-md-12">
<label> Friend ' . ($i + 1) . '</label>'.
$form->field($item, "[$i]user_friend_id") .
'<label> Closeness to you </label>
<div class="form-inline"> ' .
$form->field($item, "[$i]closeness")->widget(RangeInput::classname(), [
'options' => ['placeholder' => 'Rate (1 - 5)...'],
'html5Options' => [
'min' => 1, 'max' => 5,
'width' => '75%',
'addon' => ['append' => ['content' => '<i class="glyphicon glyphicon-star"></i>']]
]])->label(false).
'</div> '.
'<div class="form-inline" >
I know this person as a friend for approximately (in year) '.
$form->field($item, "[$i]known_for")->textInput(["type" => "number", "placeholder" => '(in year)'])->label(false).
'</div></div></div>';
}
?>
<h1>Friendship Survey</h1>
<p> Introverted the space below, list up to ten of your closest friends that are currently in Econs/ Math and Econs; a minimum of 5 is compulsory. *Please select their full names from the dropdown list provided. Also, please select on the scale how close you are to each friend. 1Note the incentives for this section </p>
<?php $form =ActiveForm::begin() ?>
<?php foreach ($items as $i => $item) {
echo addRelationForm($form ,$item, $i);
}
?>
<hr>
<div class="row">
<div style="float:left" >
<?= Html::submitButton('Add Row', [ 'name' => 'chosen', 'value' => 'addmore', 'class' => 'btn btn-info']) ?>
</div>
<div style="float:right" >
<?= Html::submitButton('Next Page', ['class' => 'btn btn-primary', 'name' => 'chosen', 'value' => 'nextpage']) ?>
</div>
</div>
<?php ActiveForm::end()?>
<?php
$this->registerJsFile('/advanced/frontend/web/js/partone-two.js');
?>
my controller looks like this:
public function actionTwo(){
if(\Yii::$app->user->isGuest){
$this->goHome();
}
$models = [];
var_dump($_POST);
Yii::trace("esting" .empty($_POST['chosen']));
for($i = 0; $i < 5 ; $i++){
$models[$i] = new RelationForm();
}
if(!empty($_POST['add'])){
if('addmore' == $_POST['add']){
Model::loadMultiple($models, Yii::$app->request->post('items'));
$model = new RelationForm();
array_push($models, $model);
return $this->render('two', ['items' => $models]);
}
}
if (Model::loadMultiple($models, Yii::$app->request->post()) )
{
$count = 0;
for($i = 0 ; $i < count($models); $i++){
if(!$models[$i]->validate()){
if($models[$i]->hasErrors()){
Yii::trace( Html::errorSummary($models[$i] ));
}
return $this->render('two', ['items' => $models]);
}
}
for($i = 0 ; $i < count($models); $i++){
if(!$models[$i]->store()){
return $this->render('two', ['items' => $models]);
}
}
Yii::$app->session->setFlash('success', "Processed {$count} records successfully.");
return $this->redirect('three', ['items' => $models]);// redirect to your next desired page
}
else {
Yii::trace("Render");
return $this->render('two', array('items' => $models));
}
return null;
}
Instead of <?= Html::submitButton('Add Row', [ 'name' => 'chosen', 'value' => 'addmore', 'class' => 'btn btn-info']) ?> which create <button type="submit" ... >Submit</button> use submitInput($label = 'Submit', $options = []) which create <input type="submit" name="chosen" value="addmore" class="btn btn-info">
Then in controller: $var = \Yii::$app->request->post('chosen');
you can check if variable is empty: empty($var) (different names for each submitInput with no values) or isset && $var === 'your_value' (same name, but diff. value in submitInput - not tested if it`s working)
i have been trying to submit a jquery mobile form using ajax in cakephp but the form does not submit, i don't know what could be wrong, here is my controller code:
public function add() {
if ($this->request->is('ajax')) {
$this->request->data['Room']['user_id'] = $this->Session->read('Auth.User.id');
$this->Room->User->updateAll(array("User.room_count"=>'User.room_count+1'),array('User.id'=> $this->Session->read('Auth.User.id') ));
$this->Room->create();
if ($this->Room->save($this->request->data)) {
$this->Session->setFlash(__('The room has been saved.'));
$this->render('AjaxRoom','ajax');
} else {
$this->render('AjaxRoom','ajax');
}
}
$users = $this->Room->User->find('list');
$this->set(compact('users'));
}
and here is my view code:
<div id="sent" style="display:none;">Updating...</div>
<div id="success"></div>
<script type="text/javascript">
//<![CDATA[
$(document).ready(function () {
$("#RoomIndexForm").bind("submit", function (event) {
$.ajax({
async:true,
beforeSend:function (XMLHttpRequest) {$("#sent").show(500)},
complete:function (XMLHttpRequest, textStatus) {$("#sent").hide(500);$("#TalkViewForm").each (function(){this.reset();});
//$("#refresh").load(location.href + " #refresh");
},
data:$("#RoomIndexForm").serialize(),
dataType:"html",
success:function (data, textStatus) { //$("#success").html(data);
},
type:"POST",
url: "<?php echo $this->Html->url(array('controller' => 'rooms', 'action' => 'add')); ?>"});
return false;
});
});
//]]>
</script>
<div data-role="popup" id="popupRoom" data-theme="a" class="ui-corner- all">
<?php echo $this->Form->create('Room',array('role'=>'form','url'=>array('controller'=>'r ooms', 'action'=>'add'))); ?>
<div style="padding:10px 20px;">
<h3>Add Room</h3>
<?php echo $this->Form->input('name', array(
'label' => false,
'placeholder'=>'Room Name'));
?>
<?php
echo $this->Form->input('description', array(
'label' => false,
'type' => 'textarea',
'maxlength'=>"140",
'placeholder'=>'Describe Your room briefly.'));
?>
<?php
$accountValues = array();
foreach ($categories as $key => $value) {
$accountValues[$value] = $value;
}
$categories = $accountValues;
echo $this->Form->select('category',array(
'options' =>$categories), array(
'label' => false,
'empty' => false
));
?>
<?php
//echo $this->Form->input('filename', array('type' => 'file','label'=>'Upload an Image'));
//echo $this->Form->input('file_dir', array('type' => 'hidden'));
?>
<?php
echo $this->Form->input('is_private', array(
'label' => 'Do you want a private Room ? If No, just ignore this field.',
'type'=>'checkbox',
));
?>
<?php echo $this->Form->submit('Create',array('class'=>'ui-btn ui-corner-all ui-shadow ui-btn-b ui-btn-icon-left ui-icon-check')); ?>
</div>
<?php echo $this->Form->end(); ?>
</div>
please how do i achieve this functionality? any help is welcomed.
The Html Helper does not support url i think:
$this->Html->url(array('controller' => 'rooms', 'action' => 'add'))
Try to use this instead:
$this->Html->link(['controller' => 'Rooms', 'action' => 'add'])
Another way is the url builder (http://book.cakephp.org/3.0/en/views/helpers/url.html):
$this->Url->build(['controller' => 'Rooms', 'action' => 'add'])
I am working on job portal,and have a search module for employers to search for application.I want to use ajax to list the application after search, listing the results in the same page.How should I do it.?,Below is the screenshot of the module.Have tried the following things.
//Contoller Code//
public function actionSearch()
{
$model = new SearchEmployee();
/*Getting Data From Search Form For Processing */
if (isset($_POST['SearchEmployee'])) {
$model->attributes = $_POST['SearchEmployee'];
$category = $_POST['SearchEmployee']['category'];
$skills = $_POST['SearchEmployee']['skills'];
$experience = $_POST['SearchEmployee']['experience'];
$ajaxmodel = SearchEmployee::model()->find(array(
'select' => array('*'), "condition" => "category_id=$category AND key_skills like'%$skills%'AND experience=$experience",
));
if($model==null)
{
Yii::app()->user->setFlash('success', "No Results");
$this->renderPartial('search');
}
else
{
$this->renderPartial('search', array('model' => $ajaxmodel));
Yii::app()->end();
}
}
// In views,Not posting full codes just codes to show the ajax results,//
<div class="view">
<h1>Results </h1>
<div class="view" id="id">
<h1> Records Display </h1>
<h4>Name: <?php echo $form->labelEx($model,'skills Required'); ?></h4>
<h4>Skills: <?php echo $form->labelEx($model,'Skills Required'); ?></h4>
<h4>Experience: <?php echo $form->labelEx($model,'Skills Required'); ?></h4>
<h5> <?php echo CHtml::submitButton('VIew Details'); ?></h5>
</div>
</div>
Is this way to do...
In your view just enable ajax, for example:
$form = $this->beginWidget('bootstrap.widgets.TbActiveForm', array(
'id' => 'client-document-form',
'method' => 'post',
'action' => $url,
'enableAjaxValidation' => false,
'errorMessageCssClass' => 'required_field_text'
)); ?>
This line enableAjaxValidation => true need be true also in your actions add this line $this->performAjaxValidation($model);
UPDATE:
$form = $this->beginWidget('bootstrap.widgets.TbActiveForm', array(
'id'=>'update-profile-form',
'enableAjaxValidation' => true,
'errorMessageCssClass' => 'required_field_text',
'clientOptions' => array(
'validateOnSubmit' => true,
'validateOnChange' => false,
'hideErrorMessage' => true,
'beforeValidate' => 'js:function(form) {
return validate.beforeValidate("update-profile-form");
}',
'afterValidate' => 'js:function(form, data, hasError) {
validate.afterValidate(data, "update-profile-form");
}'
),