Action not found after AJAX request

2019-08-02 06:21发布

Before for submitting I want to send the request to an action. But in return I get 404 not found. The action is obviously there. Also got it in the filters of the controller. JS:

$('#home-contact').on('beforeSubmit', function(){
                    $.ajax({
                        method: 'post',
                        url: '/site/send-contact',
                        data: new FormData($(this))[0],
                        success: function(data){
                            console.log(data)                          
                        }
                    })
                    return false
                })

Controller filters:

'access' => [
                'class' => AccessControl::className(),
                'only' => ['logout', 'signup', 'send-contact'],
                'rules' => [
                    [
                        'actions' => ['signup', 'send-contact'],
                        'allow' => true,
                        'roles' => ['?'],
                    ],
                    [
                        'actions' => ['logout'],
                        'allow' => true,
                        'roles' => ['@'],
                    ],
                ],
            ],

And the action also :

public function actionSendContact()
    {
        Yii::$app->response->format = Response::FORMAT_JSON;
        $model = new Contact();
        if($model->load(Yii::$app->request->post()) && $model->save()){
            return $data['success'] = Yii::t('app', 'Successfully sent message.');
        }
        return $data['error'] = Yii::t('app', 'Something went wrong. Please try again.');
    }

The scenario happens in the frontend if that matters somehow. Thank you!

3条回答
一纸荒年 Trace。
2楼-- · 2019-08-02 06:41

URL in JavaScript seems to be not fully specified.

The valid way would be:

url: 'index.php?r=site/send-contact',

But this works only if your index.php is in root folder.

To make it work with any situation (e.g., index.php is not in root), then you have different solutions. I personally like to use this:

  • Declare action and id in your form:

Example:

$form = ActiveForm::begin([
    'action' => ['site/send-contact'],
    'id' => 'my-form',
]);
  • Use a link (that is generated by Yii2 itself) in your JS code:

Example:

$('#home-contact').on('beforeSubmit', function() {
    $.ajax({
        method: 'post',
        url: $('#my-form').attr('action'),
        data: new FormData($(this))[0],
        success: function(data) {
            console.log(data)                          
        }
    });

    return false;
});

This should work in all cases, whenever your files are.

Hope that helps!

查看更多
姐就是有狂的资本
3楼-- · 2019-08-02 06:54

Not sure about the 404 you are having as the url in the request is correct and the url that would be generated for the ajax request will be like http://example.com/site/send-contact but only if you are using the 'enablePrettyUrl' => true, for the urlManager component, otherwise it should be like index.php?r=site/index that could only be the reason behind the 404, a better way is to get the url from the form action attribute.

Apart from above,

You are using the new FormData() to send the data with the request like

data: new FormData($(this))[0] 

which isn't correct and won't send any FormData with the request as it will return undefined, you can check the console or by using the print_r($_POST) inside the action sendContact once you are done with the 404, it should be

data: new FormData($(this)[0]),

you need to get the form via $(this)[0] and pass to the new FormData().

But this is not enough you have to set the contentType and processData to be false to correctly submit the FormData or you will get the exception in console

Uncaught TypeError: Illegal invocation

So your code should be like

$('#contact-form').on('beforeSubmit', function(){
    let url=$(this).attr('action');
    let form=$(this)[0];
    let data=new FormData(form);

    $.ajax({
        method: 'post',
        url: url,
        data:data,
        contentType: false, // NEEDED, DON'T OMIT THIS (requires jQuery 1.6+)
        processData: false,
        success: function(data){
            console.log(data)                          
        }
    });
    return false;
})

EDIT

Note: Above all you should use data:$(form).serialize() simply rather than using new FormData() until unless you are planning to upload files along with the form using ajax.

查看更多
一纸荒年 Trace。
4楼-- · 2019-08-02 07:03

did you add 'enableAjaxValidation' => true or add action name in active form?

$form = ActiveForm::begin([
    'action' => ['controller/action'],
    'enableAjaxValidation' => true
]);
查看更多
登录 后发表回答