I have a form with onsubmit event:
<?php $form = ActiveForm::begin([
'id' => 'order',
'options' => [
'class' => 'validation-wizard wizard-circle form-horizontal',
'onsubmit' => 'checkStorageField()'
],
'enableAjaxValidation'=>true,
'enableClientValidation'=>true,
]); ?>
And the function which the event triggers is :
function checkStorageField(){
alert(123)
return false
}
But it seems that the event onsubmit is triggered 2 times because I get 2 alert on after another and the form is submitted anyway. What is my mistake?
You should use events of ActiveForm
for example:
$('#order').on('beforeSubmit', function (e) {
alert(123);
return false;
});
Related
This is my code:
[
'attribute' => 'status',
'value' => function ($model) {
return Html::dropDownList('status', ['10' => 'Active', '20' => 'Deactive']);
},
],
I just want dropdown in status column. If record is active or deactive it will be selected.
You need to use 'format' => 'raw' for the column options and your definition for the dropDownList() is wrong you need to have the selection string as the second parameter and the dropdown options as the third parameter. Change your code to below:
[
'attribute' => 'status',
'format' => 'raw',
'value' => function ($model) {
return Html::dropDownList('status', $model->status, ['10' => 'Active', '20' => 'Deactive']);
},
],
EDIT
You didnt had in the initial requirements that you waned to update the status too when the drop down is changed. You can bind ajax call to the drop-down.
Add the following javascript on top of your view where you are initializing the GridView.
NOTE: Change the url:'controller/update-status?id'+id in the ajax call to the relative controller where you want to update the status for the row, but dont remove the id
$js = <<<JS
$(document).on('ready pjax:success',function(){
$(".switch-status").on('change',function(){
var data={};
data[$(this).attr("name")]=$(this).val();
var id=$(this).closest("tr").data('key');
$.ajax({
method:'post',
url:'/controller/update-status?id='+id,
data:data,
success:function(data){
if(!data.success){
alert(data.message);
}else{
alert("Status updated.");
}
},
error:function(jqXHR, textStatus, errorThrown ){
alert(errorThrown);
}
});
});
});
JS;
$this->registerJs($js, yii\web\View::POS_END);
Then inside your GridView column for status change the dropdown to the following
return Html::dropDownList(Html::getInputName($model, 'active'), $model->active, [10 => 'Active', 20 => 'Deactive'], ['class' => 'switch-status']);
And the go to your controller and add the action code for updating the status
Note: Change the Model in the first line $model = Model::findOne($id); name with the respective model you are using.
public function actionUpdateStatus($id) {
$model = Affiliate::findOne($id);
$app = Yii::$app;
$request = $app->request;
if($request->IsAjax && $request->isPost) {
Yii::$app->response->format = Response::FORMAT_JSON;
if($model->load($request->post()) && $model->save()) {
return ['success' => true];
} else {
return [
'success' => false,
'message' => implode('<br />', ArrayHelper::getColumn($model->errors, '0'))
];
}
}
}
Use content property to render HTML elements. For example:
[
'attribute' => 'status',
'content' => function ($model) {
return Html::dropDownList('status', $model->status, ['10' => 'Active', '20' => 'Deactive']);
},
],
My Modal window is only displayed on the first line of Gridview (clicking on the second line or more opens a new page without formatting).
I was following this post.
Can someone help me? I saw that there is an unanswered topic for the same problem here https://stackoverflow.com/questions/42667602/yii2-gridview-modal-only-display-when-click-on-first-row
My gridview
<?php
yii\bootstrap\Modal::begin([
'id' =>'modal',
//'headerOptions' => ['id' => 'modalHeader'],
'header' => 'Tipos de situação',
]);
yii\bootstrap\Modal::end();
?>
columns...
[
'attribute' => 'status_id',
'enableSorting' => true,
'format' => 'raw',
'value' => function ($model) {
// return '<b style="color:#456789">'.$model->status->name.'</b>';
// },
return Html::a($model->status->name, ['/analise/status/list'], ['id' => 'popupModal']);
},
'filter' => ArrayHelper::map(Status::find()->orderBy('name')->asArray()->all(), 'id', 'name'),
'contentOptions'=>['style'=>'width: 10%;text-align:center;vertical-align: middle;'],
'headerOptions'=>['class'=>'active', 'style'=>'text-align:center;vertical-align: middle;'],
],
<?php
$this->registerJs("$(function() {
$('#popupModal').click(function(e) {
e.preventDefault();
$('#modal').modal('show').find('.modal-body')
.load($(this).attr('href'));
});
});");
?>
You have multiple links with the same id "popupModal", it's not right. You may use css class instead of id:
in column:
'value' => function ($model) {
return Html::a($model->status->name, ['/analise/status/list'], ['class' => 'popupModal']);
},
in js:
$this->registerJs("$(function() {
$('.popupModal').click(function(e) {
e.preventDefault();
$('#modal').modal('show')
.find('.modal-body')
.load($(this).attr('href'));
});
});");
I have a page that contains multi captcha in separated forms form example login and register modals , etc.
if I use below codes the problem is that when refresh one captcha then another captcha will be unusable because they use same session varible:
1) Login
login modal (view):
echo Captcha::widget([
'id' => 'Login-captcha',
'name' => 'LoginModel[captcha]',
'captchaAction' => '/site/captcha'
]);
LoginModel :
public function rules()
{
return [
['captcha', 'captcha'],
];
}
2) Register
register modal (view):
echo Captcha::widget([
'id' => 'register-captcha',
'name' => 'RegisterModel[captcha]',
'captchaAction' => '/site/captcha'
]);
RegisterModel:
public function rules()
{
return [
['captcha', 'captcha'],
];
}
to solve session problem I used different captcha actions to set different session variables:
1)Login
login modal view:
echo Captcha::widget([
'id' => 'Login-captcha',
'name' => 'LoginModel[captcha]',
'captchaAction' => '/site/captcha-login'
]);
LoginModel :
public function rules()
{
return [
['captcha', 'captcha', 'captchaAction' => 'site/captcha-login',],
];
}
2) Register
register modal (view):
echo Captcha::widget([
'id' => 'register-captcha',
'name' => 'RegisterModel[captcha]',
'captchaAction' => '/site/captcha-register'
]);
RegisterModel:
public function rules()
{
return [
['captcha', 'captcha', 'captchaAction' => 'site/captcha-register',],
];
}
until now everything is ok but when I move sessions from regular php files to database by below config in commponent section of main config file:
'session' => [
'class' => 'yii\web\DbSession',
],
then captchas in the first page load not works and have to refresh them to work correctly.
what is the problem?
Try this, it is for yii1 but you can get the idea, more detail
public function rules()
{
return array(
...
array('verifyCode1', 'captcha', ...
array('verifyCode2', 'verifycaptcha2', ...
);
}
public function verifycaptcha2($attribute, $params)
{
$captcha2 = Yii::app()->getController()->createAction('captcha2nd');
if (!$captcha2->validate($this->verifyCode2, false))
{
$this->addError('verifyCode2', 'invalid captcha.');
}
}
Also see this
I'm having an issue validation whether a submitted Email Address is Unique in the database.
When the User registers I need to validate whether the email address exists all of the other validation is working fine.
Is there a step missing when you are validating a using an Ajax form in Yii 2.
A User clicks on CTA to register on site/index
use yii\bootstrap\Modal;
use frontend\models\Register;
use yii\helpers\Html;
use yii\helpers\Url;
...
Modal::begin([
'id' => 'modal',
'size'=>'modal-lg',
'clientOptions' => ['backdrop' => 'static', 'keyboard' => FALSE],
]);
echo "<div id='modalContent'></div>";
Modal::end();
?>
<?= Html::button('Register', ['value' => Url::to(['register/create']), 'title' => 'Register', 'class' => 'btn btn-success','id'=>'modalButton']); ?>
This opens up a modal (register/create)
Model Register
class Register extends User
{
...
public function rules()
{
return [
['Email', 'filter', 'filter' => 'trim'],
['Email', 'required'],
['Email', 'email'],
['Email', 'unique', 'targetClass' => '\common\models\User', 'message' => 'This email address has already been taken.'],
];
}
public function signup()
{
$user = new User();
if ($this->validate()) {
$user->Email = $this->Email;
if ($user->save()) {
return $user;
}
} else {
return;
}
}
Register Controller
public function actionCreate()
{
$model = new Register(['scenario' => 'signup']);
if (Yii::$app->request->isAjax && $model->load(Yii::$app->request->post())) {
Yii::$app->response->format = Response::FORMAT_JSON;
Yii::error($model);
return $model->validate();
}
if ($model->load(Yii::$app->request->post())) {
if ($user = $model->signup()) {
if (Yii::$app->getUser()->login($user)) {
return $this->goHome();
}
}
}
return $this->renderAjax('create', [
'model' => $model,
]);
}
The View file
<?php $form = ActiveForm::begin(['id'=> 'register', 'enableClientValidation'=>true, 'enableAjaxValidation'=>true, 'validateOnChange'=> true, 'validationUrl' => Url::to(['register/create'])] ); ?>
<div class="form-group">
<?= $form->field($model, 'Email') ?>
</div>
Javascript file
$script = <<< JS
$('body').on('beforeSubmit', 'form#register', function (event, jqXHR, settings) {
var form = $(this);
// return false if form still have some validation errors
if (form.find('.has-error').length) {
return false;
}
// submit form
$.ajax({
url: form.attr('action'),
type: 'GET',
data: form.serialize(),
success: function (response) {
// do something with response
$(document).find('#modal').modal('hide');
}
});
return false;
});
JS;
$this->registerJs($script);
I was facing a similar issue where my email field was not triggering the "unique" rule in the javascript validation, but the "unique" rule was getting triggered on the form submit.
It's awesome that you came up with a solution for your question that gets the job done, but I think what I just learned could also shed some insight on this question for others.
The key for me was learning/realizing that the "unique" validation rule must use a database lookup to verify if the user input is unique, thus it must use ajax. Other validation rules, such as "required" or "email" don't need ajax to validate. They just use javascript in the client to validate, so they are client validation, whereas the "unique" validator is actually ajax validation.
Note: my code below is not really addressing your code directly, but is intended to communicate the overall understanding and code structure that is needed to answer your question. Some of these steps you already have, but some are missing :)
First, you need a model with a field that requires a 'unique' rule, such as an email address for a user account.
In your Model
public function rules()
{
$rules = [
[['email'], 'unique'],
// ... and all your other rules ...
];
}
When using \yii\widgets\ActiveForm, client validation is enabled by default, but ajax validation is not.
So, next you need to directly turn on ajax validation in the view. This can be done either for the entire form, or just for a single field. The Yii2 Validation docs explain this best, but in my case, I chose to just enable ajax validation on my email field.
In your View
<?php $form = ActiveForm::begin(); ?>
<?= $form->field($user, 'email', ['enableAjaxValidation' => true])->textInput();
//... other form fields and such here ...
<?php ActiveForm::end(); ?>
Next, you also need to handle the ajax validation in your controller, so your controller method could look something like this:
public function actionRegister()
{
$user = new User();
$post = Yii::$app->request->post();
$userLoaded = $user->load($post);
// validate for ajax request
if (Yii::$app->request->isAjax) {
Yii::$app->response->format = Response::FORMAT_JSON;
return ActiveForm::validate($user);
}
// vaidate for normal request
if ($userLoaded && $user->validate()) {
$user->save();
return $this->redirect(['view', 'id' => $user->id]);
}
// render
return $this->render('create', ['user' => $user]);
}
And then here's the catch ... everything above is what you would need when working with a normal (non-ajax) form. In your question, you are working on a form in a modal window that is being submit via ajax, so the above controller method will not work. With ajax forms, it becomes pretty tricky to handle the ajax form validation and the ajax form submit in the same controller method.
As usual, Yii has this all figured out for us, and the validationUrl form parameter will save the day. All you have to do is create a new method in your controller that is specifically for ajax validation, and reference the controller/action URL in your form. Something like this should do the trick:
In your View
<?php $form = ActiveForm::begin([
'id' => 'form-id', // always good to set a form id, especially when working with ajax/pjax forms
'validationUrl' => ['user/validate-email'], //['controller/action'],
]); ?>
In your Controller
public function actionRegister()
{
$user = new User();
$post = Yii::$app->request->post();
// vaidate for normal request
if ($user->load($post) && $user->validate()) {
$user->save();
return $this->redirect(['view', 'id' => $user->id]);
}
// render
return $this->render('create', ['user' => $user]);
}
public function actionValidateEmail()
{
// validate for ajax request
if (Yii::$app->request->isAjax) {
Yii::$app->response->format = Response::FORMAT_JSON;
$user = new User();
$post = Yii::$app->request->post();
$user->load($post);
return ActiveForm::validate($user);
}
}
Cheers!
I managed to solve this myself by using Javascript to make an Ajax request and PHP to receive the quest and check whether the Email already exists in the database.
function checkEmail(){
var email_check;
// Get the value of the email input field
var input_value = document.getElementById('register-email').value;
// Send the value to a PHP page to check
$.ajax({
url: 'checkemail.php/',
type: 'POST',
data: {
email_check: input_value
},
success: function(response) {
// If we have a repsonse we need to check whether it is True or False
email_check = response;
if (email_check == 1) {
// If True add error class
$('.field-register-email').addClass('has-error');
$('.field-register-email .help-block').text('The email supplied has already been used');
} else {
$('.field-register-email').removeClass('has-error');
$('.field-register-email .help-block').text(' ');
}
}
});
};
This will send a POST request to the checkemail.php which will check whether the email address is in the database
In the active form, I have 3 textinput and one checkbox.
All the 3 textinputs have rules that says cannot be empty. What I want is if the checkbox is clicked, It will disable the rules and will save the empty record in the database.
here is screen shot of the active form..
You could define the rules that way (using when):
public function rules()
{
return [
['cancelled', 'boolean'],
['checkNumber', 'required'],
['payee', 'required', 'when' => function ($model) {return !$model->cancelled;}],
['particulars', 'required', 'when' => function ($model) {return !$model->cancelled;}],
];
}
You may want to add whenClient as well to let the browser check this before it submits the form.
You can do something like this:
$model = new SomeForm();
if ($model->load(Yii::$app->request->post())){
if ($model->checkbox == true) $model->scenario = 'checked';
}
// your model rules:
[['name', 'email', 'subject', 'body'], 'safe', 'on' => 'checked']
or alternatively You can do this:
if ($model->checkbox == true) $model->save(false); //this will disable any validation so be carefull
edit:
if You need cliend side validation switch, You have to use this:
[['name', 'email', 'subject', 'body'], 'required', 'when' => function ($model) {
return $model->cancelled == '0';
}, 'whenClient' => new JsExpression("function (attribute, value) { return $('#mailform-cancelled').val() == '0';}")]