Static menu in the Yii 2.0 advanced template back-end - ajax

I'm using Yii 2.0 advanced template, and in the back-end want to have something like this:
A menu of the left that should contains items, and when clicking on those items the corresponding pages to be open on the right. The menu of the left should be static and to not lose focus when items are clicked.
This means that I will probably need to use partial views? Is there some extension/widget that is doing what I need? I'm new in Yii so I'm really not sure how to solve this. Any suggestion or idea will be appreciated. I'm sure I'm not the only one that need this in Yii, but could not find something on google.

I think the simplest way is use layout. You can define a layout with the menu on the the left and the main page in rest of the page.
this could be a layout sample eg: 'mylayout.php'
<?php
use yii\helpers\Html;
use yii\bootstrap\Nav;
use yii\bootstrap\NavBar;
use yii\widgets\Breadcrumbs;
use frontend\assets\AppAsset;
/* #var $this \yii\web\View */
/* #var $content string */
AppAsset::register($this);
?>
<?php $this->beginPage() ?>
<!DOCTYPE html>
<html lang="<?= Yii::$app->language ?>">
<head>
<meta charset="<?= Yii::$app->charset ?>">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="shortcut icon" href="<?php echo Yii::$app->request->baseUrl; ?>/dfenx.ico" type="image/x-icon" />
<?= Html::csrfMetaTags() ?>
<title><?= Html::encode($this->title) ?></title>
<?php $this->head() ?>
</head>
<body>
<?php $this->beginBody() ?>
<div class="wrap">
<?php
NavBar::begin([
'brandLabel' => $this->title = Yii::$app->name ,
'brandUrl' => Yii::$app->homeUrl,
'brandOptions' =>[
'style' => 'font-family: palatino; font-size:24px;'
],
'options' => [
//'class' => 'navbar-inverse navbar-fixed-top',
'class' => 'navbar-default navbar-fixed-top',
],
]);
$menuItems = [
['label' => 'Home', 'url' => ['/site/index']],
['label' => 'About', 'url' => ['/site/about']],
['label' => 'Contact', 'url' => ['/site/contact']],
];
if (Yii::$app->user->isGuest) {
$menuItems[] = ['label' => 'Signup', 'url' => ['/user/register']];
$menuItems[] = ['label' => 'Login', 'url' => ['/user/login']];
} else {
$menuItems[] = [
'label' => 'Logout (' . Yii::$app->user->identity->username . ')',
'url' => ['/user/logout'],
'linkOptions' => ['data-method' => 'post']
];
}
echo Nav::widget([
'options' => ['class' => 'navbar-nav navbar-right'],
'items' => $menuItems,
]);
NavBar::end();
?>
<div class="container">
<?= Breadcrumbs::widget([
'links' => isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : [],
]) ?>
<div class='col-lg-3 col-md-3' >
<!-- here your left menu -->
</div>
<div class='col-lg-9 col-md-9' >
<!-- here your content page-->
<?= $content ?>
</div>
</div>
</div>
<footer class="footer">
<div class="container">
<p class="pull-left">© Digital FenX <?= date('Y') ?></p>
<p class="pull-right"><?php // Yii::powered() ?></p>
</div>
</footer>
<?php $this->endBody() ?>
</body>
</html>
<?php $this->endPage() ?>
in the controller you can set the layout you want use in this way
public function actionYourAction()
{
$this->layout = 'mylayout';
return $this->render(ourView', [
'model' =>$model,
'dataProvider' => $provider,
]);
}

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.

yii2 file extension validation not works

I have rule in my model like this
public function rules()
{
return [
[['tbl_data_induk_mahasiswa_id'], 'required'],
[['tbl_data_induk_mahasiswa_id'], 'integer'],
[['nama'], 'file','extensions'=>'png,jpg','maxSize' => 1024000,'tooBig' => 'Size maksimum adalah 1 MB'],
[['nama'], 'string', 'max' => 300],
[['tbl_data_induk_mahasiswa_id'], 'unique'],
[['tbl_data_induk_mahasiswa_id'], 'exist', 'skipOnError' => true, 'targetClass' => TblDataIndukMahasiswa::className(), 'targetAttribute' => ['tbl_data_induk_mahasiswa_id' => 'id']],
];
}
i have form like this
<?php
use yii\helpers\Html;
//use yii\widgets\ActiveForm;
echo Html::beginForm(
['mahasiswa-foto-biodata/update'],
'post',
['enctype' => 'multipart/form-data'] //if you want to upload file with post
); ?>
<div class="form-group form-file-upload form-file-multiple">
<?= Html::activeFileInput(
$model,
'nama',
['class' => 'inputFileHidden', 'multiple' => '']
); ?>
<div class="input-group">
<?= Html::activeTextInput(
$model,
'nama',
[
'class' => 'form-control inputFileVisible',
'placeholder' => 'Single File',
]
); ?>
<span class="input-group-btn">
<button type="button" class="btn btn-fab btn-round btn-primary">
<i class="material-icons">attach_file</i>
</button>
</span>
</div>
</div>
<div class="form-group">
<?= Html::submitButton('Save', ['class' => 'btn btn-success']) ?>
</div>
<?= Html::endForm(); ?>
I can not use activeForm widget because i must create html form that suit with my template, the form is work, the file succesfull uploaded, the problem is every tipe file is success uploaded, not just only png or jpg, but if i change the max rule for nama to [['nama'], 'string', 'max' => 2],then i upload a file that have name's length more than two the file can not be uploaded.
Any help?
Please check your form, you have 02 types of input with the same name ("nama"). One is "file", one is "text"
I think it is the reason that make your form does not works correctly!

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.

Submit form data using Ajax in Yii1

I tried to submit a form using ajax. Below is my code:
controller code:
public function actionIndex($complaint, $work)
{
...
$this->render('index',array(
'model' => $model,
'work_order' => $work_order,
'work' => $work,
'complaint' => $complaint,
'work_complaint'=> $work_complaint
));
}
ajax action
public function actionCreate($complaint,$work)
{
...
$this->renderPartial('create',array(
'model' => $model,
'complaint' => $complaint,
'work' => $work,
'work_complaint' => $work_complaint,
'work_order' => $work_order,
'man_hour' => $man_hour,
'jobs' => $jobs,
));
}
my views
Create.php
<h1>Add Job</h1>
<?php $this->renderPartial('_form', array('model' => $model,
'work_complaint' => $work_complaint,
'work_order' => $work_order,
'man_hour' => $man_hour,
'jobs' => $jobs,
'complaint' => $complaint,
'work' => $work
)); ?>
my _form.php
<div class="form">
<?php $form=$this->beginWidget('CActiveForm', array(
'id'=>'post-form',
'enableAjaxValidation'=>false,
)); ?>
...
<div class="row buttons">
<div class="col-md-6 col-lg-6" >
<?php echo CHtml::ajaxSubmitButton ("Post",
array('complaintJob/create','complaint'=>$complaint,'work'=>$work),
array('update' => '#post')); ?>
</div>
</div>
<?php $this->endWidget(); ?>
</div><!-- form -->
my index.php
<div id="post">
<?php
$man_hour = ManHourMaster::model()->findByPk(1);
$jobs = Job::model()->with('job_category1')->findAll( "job_category1.is_separate = 0" );
$this->renderPartial('create',array(
'model' => $model,
'complaint' => $complaint,
'work' => $work,
'work_complaint' => $work_complaint,
'work_order' => $work_order,
'man_hour' => $man_hour,
'jobs' => $jobs,
));
?>
</div>
...
so when i run this code i get the form, and when i submit it, i basically get 2 copies of the same view.
i tried this one and it worked
<?php $form=$this->beginWidget('CActiveForm', array(
'id'=>'complaint-job-form',
'enableAjaxValidation'=>true,
'clientOptions'=>array(
'validateOnSubmit'=>true,
'afterValidate'=>'js:function(form,data,hasError){
if(!hasError){
$.ajax({
"type":"POST",
"url":"'.CHtml::normalizeUrl(array('complaintJob/create','complaint'=>$complaint,'work'=>$work)).'",
"data":form.serialize(),
"success":function(data){
toastr.success("Saved successfully.", "Success");
$("#results").html(data);
$("#ComplaintJob_job_id").select2("val", "");
},
});
}
}'
),
)); ?>

Yii2 ajax validate and submit form

I have very little AJAX's Information. That's why I asked my question here...
in yii2 how can create and submit form with ajax validation?
So I searched but could not find the right solution...
for example: (according to the official training site)
<?php $form = ActiveForm::begin([
'id' => $model->formName(),
'enableAjaxValidation' => true,
]); ?>
<?= $form->field($model, 'title')->textInput(['maxlength' => true]) ?>
<?= $form->field($model, 'extra_txt')->textInput(['maxlength' => true]) ?>
<div class="form-group">
<?= Html::submitButton($model->isNewRecord ? 'Create' : 'Update', ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>
</div>
<?php ActiveForm::end(); ?>
and in controller:
if (Yii::$app->request->isAjax && $model->load(Yii::$app->request->post())) {
Yii::$app->response->format = 'json';
return ActiveForm::validate($model);
} else {
return $this->render('create', [
'model' => $model,
]);
}
My problems:
1- ajax validation
2- submit form with ajax
Why don't you use Pjax? Use yii\widgets\Pjax and add Pjax::begin() and Pjax::end() around your form.
A decent guide over here:
http://www.yiiframework.com/wiki/772/pjax-on-activeform-and-gridview-yii2/

Resources