Yii2 - warning message before submit

4.9k views Asked by At

I have a form with two fields "a" and "b" when in action update if the "b" field changes the "beforeSubmit" event a Modal Bootstrap alert is sent to the user without any button OK or CANCEL, only information during 5 seconds, after this time automatically save if the the "b" field were actually changed, if not change save whitout alert modal windows.

How do I send this condition from the controller to view where I have the javascript? maybe with ajax? but how?

Controller.php

public function actionUpdate()
    {
        $model = new Faqs();

        if ($model->load(Yii::$app->request->post()) && $model->save()) {

            if ($model->oldAttributes["b"] != $model->b){
                sleep(5);
            }

            return $this->redirect(['view', 'id' => $model->id]);
        } else {
            return $this->render('update', [
                'model' => $model,
            ]);
        }
    }

_form.php

$('#form').on('beforeSubmit', function(e) {
    if(old_B_attribute != current_B_attribute){ //example
        $('#modal').modal('show');
    }
});
3

There are 3 answers

4
Muhammad Omer Aslam On BEST ANSWER

You want to prompt the user if the attribute values were actually changed before submitting the form.

How I would go for this

  • Create a separate action in my controller actionAttributeDirty() which would validate if the selected attribute was actually changed.
  • Then, use a normal Html::button() rather than a Html::submitButton() for the form.
  • Add a hidden field to hold the current records id in the form.
  • Bind click event to the button which will send an ajax call to actionAttributeDirty() with the id of the current record.
  • Then use the success function to display the modal window and use setTimeout with $.yiiActiveForm('submitForm') to trigger the form submission after 5 seconds.

So in the similar order given above,

actionAttributeDirty

public function actionAttributeDirty()
{
    Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
    $id = Yii::$app->request->post('id');
    $model = Faqs::findOne($id);
    $response = ['changed' => false];
    $isValidRequest = Yii::$app->request->isAjax && Yii::$app->request->isPost;

    if ($isValidRequest && $model->load(Yii::$app->request->post())) {
        //get the name of the fields from the dirty attributes
        $changedAttributes = array_keys($model->getDirtyAttributes());

        //if the attribute name exists in the dirty attributes
        if (!empty($changedAttributes) && in_array("b", $changedAttributes)) {
            $response['changed'] = true;
        }
    }
    return $response;
}

Your form should have the following buttons along with other fields,

$form = \yii\widgets\ActiveForm::begin(['id' => 'form']);
echo \yii\helpers\Html::hiddenInput('id', $model->id);
echo \yii\helper\Html::button('save', ['id' => 'save-now']);
\yii\widgets\ActiveForm::end();

click Event for the Button

Add the following on the top of your view where you have the form.

Note: change the url of the ajax call '/site/attribute-dirty' accordingly where you copy the actionAttributeDirty() i assume you copy it inside the site controller.

$js = <<< JS
    $('#save-now').on('click', function(e) {
        e.preventDefault();
        let form = $("#form");

        $.ajax({
            url:'/site/attribute-dirty',
            method:'post',
            data:form.serialize(),
        }).done(function(response){
            if(response.changed){
                $('#modal').modal('show');
                setTimeout(function(){form.yiiActiveForm('submitForm');}
                , 5000);
            }else{
                form.yiiActiveForm('submitForm');
            }

        }).fail(function(response){
            console.log(response.responseText);
        });
    });
JS;

$this->registerJs($js, \yii\web\View::POS_READY);

EDIT

Pressing Enter button will not submit the form anyhow as there is no submit button, If you want Enter button to submit the form you should add the following along with the script too on the top of the view which will trigger the click event of the save-now button whenever the Enter button is pressed within any input.

$("#form").on('keypress','input',function(e){
    e.preventDefault();
    if(e.keyCode===13){
        $("#save-now").trigger('click');
    }
});
1
user206 On

your request can not be done on the client side by beforeSubmit.Because you have to decide on the server side.

On the client side you can use

$(document).on("beforeValidate", "form", function(event, messages, deferreds) {
//   #code
// console.log('BEFORE VALIDATE TEST');
}).on("afterValidate", "form", function(event, messages, errorAttributes) {
// console.log('AFTER VALIDATE TEST');
 //#code
});

Then decide in the rules method.

On the server side, you can also decide on the following events:(For what you want)  beforeValidate, afterValidate,beforeSave,afterSave,...

0
memo On

if you want show confirmation modal i use as below. you can change as your needs show or hide submit after x seconds

  $(function() {
    submitting = false;
  });

  $("form").on("beforeSubmit", function (event, messages, errorAttributes) {
    if (typeof(errorAttributes) === "undefined" || errorAttributes.length === 0) {
      $('#modal-confirm').modal('show');
      return submitting;
    }
  });

  var submit = function() {
    submitting = true;
    $("form").yiiActiveForm('submitForm');
  }

in modal submit

  <button type="button" onclick="submit();">Confirm</button>