I'm trying to upload an image via Ajax request and seem to be hitting a similar issue as this question but it has no answer. I'm not sure if they are exactly the same so I'll post all the details I can here and hope the more detail helps someone find an answer.
I'm paraphrasing the below from my code (cutting out a lot of what I think is irrelevant to this question) so any typos you see are likely just me changing the code below.
The following is included in my model:
use yii\web\UploadedFile;
...
class Image extends \yii\db\ActiveRecord
{
public $imageFile;
public function rules()
{
return [
[['imageFile'], 'file', 'skipOnEmpty' => true, 'extensions' => 'png, jpg'],
];
}
public function upload()
{
if ($this->validate()) {
$this->imageFile->saveAs('uploads/' . $this->imageFile->baseName . '.' . $this->imageFile->extension);
return true;
} else {
return false;
}
}
Here is a portion of my view file:
<?php $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]) ?>
<?= $form->field($model, 'title') ?>
<?= $form->field($model, 'imageFile')->fileInput() ?>
<?= Html::submitButton('Upload', ['class' => 'btn btn-success']) ?>
<?php ActiveForm::end(); ?>
And the Ajax in the view
$('form').on('beforeSubmit', function(e) {
var form = $(this);
$.post(form.attr('action'), form.serialize()).done(function(result) {
console.log(result)
});
return false; // Prevent default form submit action
});
And the following in my controller
use yii\web\UploadedFile;
...
public function actionUpload()
{
$model = new Image();
if (Yii::$app->request->isAjax) {
$model->load(Yii::$app->request->post());
$model->imageFile = UploadedFile::getInstance($model, 'imageFile');
if ($model->upload()) {
$model->save(); // To save the title to the database
Yii::$app->getSession()->addFlash('success', 'Image uploaded');
return $this->redirect(['index']);
}
}
Yii::$app->response->format = Response::FORMAT_JSON;
return ['return' => 'just me testing here'];
}
The above Ajax will only ever save the title to the database and will not upload the file. If I transition everything to a standard post request I can get it all to work (title is saved to the database and image is uploaded to the proper directory). If I debug around the various views, models, and controllers, it looks like I'm just not getting the imageFile via the Ajax request. The $model->load(Yii::$app->request->post());
loads the title that was submitted via Ajax, so why does that not also pull the file? I thought maybe the $model->imageFiles = UploadedFile::getInstances($model, 'imageFiles');
would be the part that pulls the Ajax submitted files but it doesn't seem to get what I need either. As a test, I even tried treating the imageFile property as plain text and assigning it to another database property to be written and it worked just fine. So it seems it's being included in the model properly, just not being send with the Ajax submit.
Can anyone tell me how, in Yii2, I can submit the form over Ajax, including the selected file?
The Problem
What the problem in ajax is that $_FILES
details are not sent in asynchroous request.
When we submit the filled form without ajax request and debug in backend side in PHP by
echo '<pre>';
print_r($_FILES);
print_r($_POST);
echo '</pre>';
die;
then we successfuly get $_FILES
and $_POST
data.
But when we debug the same thing in ajax request, we get only $_POST
values and we get $_FILES
as NULL
. This led us to conclusion that $_FILES
data are not sent in ajax request by our above code.
The Solution
We need to use FormData
of JavaScript.
What does it do?
In simple words, it adds all necessary information of file which needs to be uploaded to data
param in $.ajax
OR fill up $_FILES
as well as all $_POST
data ie non file input such as strings number etc.
In your view file
<?php $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]) ?>
<?= $form->field($model, 'title') ?>
<?= $form->field($model, 'imageFile')->fileInput() ?>
<button type="button" class="btn btn-success subm">Upload</button>
<?php ActiveForm::end(); ?>
<script>
$('.subm').click(function(e){
var formData = new FormData($('form')[0]);
console.log(formData);
$.ajax({
url: "some_php_file.php", //Server script to process data
type: 'POST',
// Form data
data: formData,
beforeSend: beforeSendHandler, // its a function which you have to define
success: function(response) {
console.log(response);
},
error: function(){
alert('ERROR at PHP side!!');
},
//Options to tell jQuery not to process data or worry about content-type.
cache: false,
contentType: false,
processData: false
});
});
</script>
Testing
Now make ajax request and debug in PHP code by print_r()
as shown above, you will notice that $_FILES
is not NULL and its contains all file (which needs to be uploaded) data. And if it is set you can upload using move_uploaded_file()
funtion
So this is how your file is uploaded via Ajax.
Referece 1
Referece 2
Referece 3
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With