phpajaxyii2alertbefore-save

Yii2 - warning message before submit


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');
    }
});

Solution

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

    How I would go for this

    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');
        }
    });