Roboto6_1on
Roboto6_1on

Reputation: 315

Yii2 upload field always empty when ajax validation

I have problem with upload file. I use kartik-v/yii2-widget-fileinput extension. Here my code:

form model rule

/**
 * @inheritdoc
 */
public function rules()
{
    return [
        [['image'], 'required', 'on' => static::SCENARIO_CREATE],
        [['image'], 'file', 'extensions' => 'png, jpg, jpeg', 'maxSize' => 1024 * 1024],
    ];
}

form view

<?php $form = ActiveForm::begin([     
    'enableAjaxValidation' => true,
    'options' => ['enctype' => 'multipart/form-data']
]); ?>

 <?= $form->field($model, 'image')->widget(FileInput::classname(), [
            'options' => ['accept' => 'image/*'],
            'pluginOptions' => [
                'showPreview' => false,
                'showCaption' => true,
                'showRemove' => true,
                'showUpload' => false,
                'showCancel' => false
            ],            
        ]); ?>

controller action

 public function actionCreate()
{
    $model = new ItemForm();
    $model->scenario = ItemForm::SCENARIO_CREATE;

    if (Yii::$app->request->isAjax && $model->load(Yii::$app->request->post())) {
        Yii::$app->response->format = Response::FORMAT_JSON;
        return ActiveForm::validate($model);
    }

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

        $image = UploadedFile::getInstance($model, 'image');

        $randomString = Yii::$app->getSecurity()->generateRandomString(10);
        $name = Inflector::slug($model->title) . '_' . $randomString . '.' . $image->extension;

        $url = Image::URL . $name;

        $model->image = $name;          

        if ($model->save()) {
            $image->saveAs($url);
            return $this->redirect(['view', 'id' => $model->id]);
        }       
    } else {         
        return $this->render('create', [
            'model' => $model,             
        ]);
    }
}

Always when I submit form, I got error "image field is required". I have read many tutorials but still I have the same problem when I using ajax validation. Can anyone look at it and tell me what I'm doing wrong?

Upvotes: 1

Views: 1815

Answers (1)

Muhammad Omer Aslam
Muhammad Omer Aslam

Reputation: 23738

EDIT

Above all you should not use enableAjaxValidation option if you have a file type field in your form. see this ISSUE use enableClientValidation instead

Apart from that looking at your complete model it looks like you are trying to use the database table field image as the same field to upload images where as you should not do that you should declare a custom field inside your model and use it to upload the file and assign the new filename to the database field image currently you have to do some additions in your model and changes to the code

1. Declare a custom field with the name $file like below on top of your model after public $tags like this, public $myFile;

2. Change your validation rule

[['image'], 'file', 'extensions' => 'png, jpg, jpeg', 'maxSize' => 1024 * 1024],

to the following

[['myFile'], 'file', 'extensions' => 'png, jpg, jpeg', 'maxSize' => 1024 * 1024],

and

[['image'], 'required', 'on' => static::SCENARIO_CREATE],

to this

[['myFile','image'], 'required', 'on' => static::SCENARIO_CREATE],

3. Change your field name in the html form, from image to myFile i.e $form->field($model, 'image') to $form->field($model, 'myFile').

4. For changes inside the action and uploadItemImage() function see below i have updated them.


you are assigning the $name variable to the $model->image field

 $model->image = $name; 

and in the $name it is a string, whereas in the model it should be a file

 $name = Inflector::slug($model->title) . '_' . $randomString . '.' . $image->extension;

what you should be doing is assign the instance of the uploaded file to the model field image and then call the $model->save() and use the custom filename to saveAs(), change your action code to the following

public function actionCreate()
{
    $model = new ItemForm();
    $model->scenario = ItemForm::SCENARIO_CREATE;

    if (Yii::$app->request->isAjax && $model->load(Yii::$app->request->post())) {
        Yii::$app->response->format = Response::FORMAT_JSON;
        return ActiveForm::validate($model);
    }

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

        $model->myFile = UploadedFile::getInstance($model, 'myFile');
        $randomString = Yii::$app->getSecurity()->generateRandomString(10);
        $model->image = Inflector::slug($model->title) . '_' . $randomString . '.' . $model->myFile->extension;

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

and then create the following method inside your model

public function uploadItemImage(){
    $url = Image::URL . $this->image;
    if(!$this->myFile->saveAs($url)){
       $this->addError('myFile','Unable to save the uploaded file');
    }
}

Upvotes: 3

Related Questions