我正在尝试更新“文章”,其中包括标题(文本),正文(文本区域)和图像(文件)。一切顺利,直到我尝试通过Ajax实现上传。通过常规Laravel上传图像意味着效果很好,但是使用Ajax,我遇到的障碍很小。首先,它拒绝验证文件。第二,如果我在控制器方法中注释掉文件的验证,它会进行“排序” ...但是然后检查$request->hasFile("image")
根本无法识别文件...因此,将默认值写入db (“ noimage.jpg”)。我其他的ajax函数都很好用,只更新会引起问题。
这是ajax函数:
function ajaksUpdate(){
let token = document.querySelector("meta[name='csrf-token']").getAttribute("content");
console.log("hitUpdate");
//console.log();
let updateForm = document.getElementById("updateForm");
let urlId = window.location.href;
let getaArticleId = urlId.lastIndexOf("/");
let articleId = urlId.substring(getaArticleId+1, urlId.length);
let updateFormElements = {};
updateFormElements.title = updateForm.elements[3].value;
updateFormElements.body = CKEDITOR.instances.ckeditor.getData();//Ovo trece po redu je id polja sa ckeditorom.
updateFormElements.image = updateForm.elements[5].files[0];
//console.log();
/*var myformData = new FormData();
myformData.append('title', updateFormElements.title);
myformData.append('body', updateFormElements.body);
myformData.append('image', updateFormElements.image);
let formData = $('#updateForm').serializeArray();
console.log(updateFormElements);*/
console.log("******");
/*for (var [key, value] of myformData.entries()) {
console.log(key, value);
}*/
$.ajax({
url: '/updateAjax/'+articleId,
enctype: 'multipart/form-data',
type: 'POST',
data: {_token: token , message: "bravo", articleId: articleId, title: updateFormElements.title, body: updateFormElements.body,image:updateFormElements.image},
dataType: 'JSON',
/*cache: false,
contentType: false,
processData: false,*/
success: (response) => {
console.log("success");
console.log(response);
},
error: (response) => {
console.log("error");
console.log(response);
}
});
}
这是控制器方法:
public function ajaxUpdate(Request $request)
{
if($request->ajax()){
$article = Article::find($request->articleId);
$validator = \Validator::make($request->all(), [
"title" => "required",
"body" => "required",
'image' => 'image|nullable|max:1999'/*If commented, validation passes.*/
]);
if ($validator->passes()){/*If validation passes, it cannot find 'image'*/
$hasImage = false;
//Handle file upload
if($request->hasFile("image")){
$filenameWithExt = $request->file("image")->getClientOriginalName();
$filename = pathinfo($filenameWithExt, PATHINFO_FILENAME);
$extension = $request->file("image")->getClientOriginalExtension();
$fileNameToStore = $filename."_".time().".".$extension;
$path = $request->file("image")->storeAs("public/images", $fileNameToStore);
}
else{
$fileNameToStore = "noimage.jpg";
}
$article->title = $request->input("title");
$article->body = $request->input("body");
//$article->user_id = auth()->user()->id;
$article->image = $fileNameToStore;
$article->save();
$response = array(
'status' => 'success',
'msg' => "Hello!",
"request" => $request->all(),
"passesValidation" => true,
"article" => $article,
"hasImage" => $hasImage,
);
return response()->json($response);
}
else{
$response = array(
'status' => 'success',
'msg' => "Hello!",
"request" => $request->all(),
"passesValidation" => false,
);
return response()->json($response);
}
}
}
编辑1:
如果未注释掉控制器中的验证(用于图像),它将显示如下字符串:“ C:\ fakepath \ 855d671944d2c143ba672010acd04437.jpg”。 如果没有注释掉Json:
{
msg: "Hello!"
passesValidation: false
request:
articleId: "3"
body: "posttext"
image: "C:\fakepath\855d671944d2c143ba672010acd04437.jpg"
message: "bravo"
title: "Post1"
_token: "ZVZ9NDNOcMdgoJgvzYhR9LmrPfh7RfMiM1QJVk9v"
__proto__: Object
status: "success"
__proto__: Object
}
如果注释掉,json看起来像这样:
{
article: {id: 3, title: "Post1", body: "<p><em>Lorem ipsum</em><strong> </strong>dolor sit…ctum. Duis feugiat facilisis lectus a cursus.</p>", created_at: "2019-06-18 00:23:25", updated_at: "2019-06-25 00:18:37", …}
hasImage: false
msg: "Hello!"
passesValidation: true
request:
articleId: "3"
body: "posttext"
image: "C:\fakepath\855d671944d2c143ba672010acd04437.jpg"
message: "bravo"
title: "Post1"
_token: "ZVZ9NDNOcMdgoJgvzYhR9LmrPfh7RfMiM1QJVk9v"
__proto__: Object
status: "success"
__proto__: Object
}
编辑2:
我也尝试过:
let formData = new FormData();
formData.append("title", updateFormElements.title);
formData.append("body", updateFormElements.body);
formData.append("image", updateFormElements.image);
,然后插入并发送。它引发“在...处非法调用”。而且无论出于什么原因,当我console.log(formData)它时,formData对象都是空的。
Edit3: 即使我添加processData:false,在ajax调用中。但是随后抛出419错误...
编辑4:
我不知道这是否对您有帮助,但是我的表单是模式表单,没有提交按钮,而带有ajaksUpdate()函数的按钮是提交/更新的按钮,它不在表单之外。我正在使用put方法进行更新,也以模态形式获取了csrf。
以下是我的表单/模态的图像:
编辑5:
根据@pal请求: 我的html是动态生成的,它是在布局文件中的另一个功能(在加载文档时调用此功能)
function ajaksShow(){
let token = document.querySelector("meta[name='csrf-token']").getAttribute("content");
console.log("hit");
//var n = str.lastIndexOf("planet");
let urlId = window.location.href;
let getaArticleId = urlId.lastIndexOf("/");
let articleId = urlId.substring(getaArticleId+1, urlId.length);
console.log(articleId);
$.ajax({
url: '/showAjax',
type: 'POST',
data: {_token: token , message: "bravo", articleId: articleId},
dataType: 'JSON',
success: (response) => {
console.log("success");
console.log(response);
let body = "";
let imageStyle = ";height: 435px; background-position: center top; background-attachment: fixed; background-repeat: no-repeat;background-size:cover;";
let img = response.article.image;
let find = " ";
let rep = new RegExp(find, 'g');
img = img.replace(rep, "%20"); // class="alert alert-danger"
let mymodalDelete = "<div class='modal' id='myModalDelete'><div class='modal-dialog'><div class='modal-content'><div class='modal-header'><h4 class='modal-title'>Do you really want to delete this article?</h4><button type='button' class='close' data-dismiss='modal'>×</button></div><div class='modal-body'>deleting ...</div><div class='modal-footer'><button class='btn btn-outline-danger' style='position: absolute;left:0px; margin-left: 1rem;' onclick='ajaksDelete(this)'>Delete</button><button type='button' class='btn btn-danger' data-dismiss='modal'>Close</button></div></div></div></div>";
let updateForm = "<form method='POST' id='updateForm' enctype='multipart/form-data'><input type='hidden' name='_method' value='PUT'><input type='hidden' name='_token' value='"+token+"'><input id='' type='hidden' name='article_id' value='"+response.article.id+"' /><div class='form-group'><label class='label' for='title'>Title</label><input type='text' class='form-control' name='title' placeholder='Title' value='"+response.article.title+"' required></div><div class='form-group'><label for='body'>Body</label><textarea class='form-control' id='ckeditor' name='body' placeholder='Body' required>"+response.article.body+"</textarea></div><div class='form-group'><input type='file' name='image' id='image'></div></form>";
let mymodalUpdate = "<div class='modal' id='myModalUpdate'><div class='modal-dialog'><div class='modal-content'><div class='modal-header'><h4 class='modal-title'>Do you really want to update this article?</h4><button type='button' class='close' data-dismiss='modal'>×</button></div><div class='modal-body'>"+updateForm+"</div><div class='modal-footer'><button class='btn btn-outline-success' style='position: absolute;left:0px; margin-left: 1rem;' onclick='ajaksUpdate()'>Update</button><button type='button' class='btn btn-info' data-dismiss='modal'>Close</button></div></div></div></div>";
let imageUrl = "/storage/images/"+img;
let html = "<a href='/list' class='btn btn-outline-info btn-sm'>Go Back</a><div class='nextPrev'><a href='/list/"+response.prev+"' class='btn btn-outline-success'><i class='fas fa-arrow-left'></i></a><a href='/list/"+response.next+"' class='btn btn-outline-info'><i class='fas fa-arrow-right'></i></a></div><br><br><div id='single-kv' style='background-image: url("+imageUrl+")"+imageStyle+";background-color: red !important;'></div><div id='single-intro'><div id='single-intro-wrap'><h1> "+response.article.title+"</h1>";
if(response.article.body.length > 400){
body = response.article.body.substring(0, 400)+"<a id='readMore' href='/list/"+response.article.id+"'>...Read more</a>";
}
else{
body = response.article.body;
}
html += body;
html += "<div class='comment-time excerpt-details' style='margin-bottom: 20px; font-size: 14px;'><a href='#gotoprofil'> "+response.user.name+" </a> - "+response.article.created_at+"</div><button id='update' class='btn btn-outline-info btn-sm float-left' data-toggle='modal' data-target='#myModalUpdate' onclick='getCkEditor()'>Update</button><button class='btn btn-outline-danger btn-sm float-right' data-toggle='modal' data-target='#myModalDelete'>Delete</button></div></div><br><hr style='color:whitesmoke; width: 50%;'><div id='single-body'><div id='single-content'>"+response.article.body+"</div></div>"+mymodalDelete+mymodalUpdate;
if(document.getElementById("maine")){
document.getElementById("maine").innerHTML = html;
}
},
error: (response) => {
console.log("error");
console.log(response);
}
});
}
Form是updateForm变量和激活它的按钮,位于mymodalUpdate变量中,在此它调用函数ajaksUpdate()。另外,updateForm链接在mymodalUpdate中,每侧有两个加号。
Edit6 : 我也尝试过:
let formData = $('#updateForm').serializeArray();
console.log(formData);
但是它仅显示csrf,隐藏的方法put字段,token,title和body字段。没有文件字段?。
Edit7:
这里有两张照片(希望如此)可以说明我的观点:
Edit8:
有人建议这是与419错误有关的csrf不匹配,因此他们建议暂时禁用csrf,以查看结果,这是图片:
已使用change ajax功能更新。如果我添加到ajax电话
cache: false,
contentType: false,
processData: false,
然后显示:“ POST http://articleapp.test/updateAjax/3 419(未知状态)”错误。如果将这三行注释掉,那么它将显示:“ Uncaught TypeError:非法调用 在添加...时出现错误。我尝试了所有操作。而csrf不是,因为我尝试禁用它,它发送了空白请求。
最终编辑: 我不知道自己做了什么,但是文件上传有效。 这是ajax函数:
function ajaksUpdate(){
let token = document.querySelector("meta[name='csrf-token']").getAttribute("content");
console.log("hitUpdate");
//console.log();
let updateForm = document.getElementById("updateForm");
let urlId = window.location.href;
let getaArticleId = urlId.lastIndexOf("/");
let articleId = urlId.substring(getaArticleId+1, urlId.length);
let updateFormElements = {};
updateFormElements.title = updateForm.elements[3].value;
updateFormElements.body = CKEDITOR.instances.ckeditor.getData();//Ovo trece po redu je id polja sa ckeditorom.
updateFormElements.image = updateForm.elements[5].files[0];
let imginp = document.getElementById("imagex").files;
//console.log(imginp);
var myformData = new FormData();
myformData.append('title', updateFormElements.title);
myformData.append('body', updateFormElements.body);
myformData.append('image', updateFormElements.image);
myformData.append('_token', token);
myformData.append('articleId', articleId);
//let formData = $('#updateForm').serializeArray();
console.log("******");
for (var [key, value] of myformData.entries()) {
console.log(key, value);
}
console.log("======");
$.ajax({
url: '/updateAjax/'+articleId,
enctype: 'multipart/form-data',
type: 'POST',
data: myformData,
dataType: 'JSON',
cache: false,
contentType: false,
processData: false,
success: (response) => {
console.log("success");
console.log(response);
},
error: (response) => {
console.log("error");
console.log(response);
}
});
}
这是控制器方法:
public function ajaxUpdate(Request $request)
{
if($request->ajax()){
$article = Article::find($request->articleId);
$validator = \Validator::make($request->all(), [
"title" => "required",
"body" => "required",
'image' => 'image|nullable|max:1999'
]);
if ($validator->passes()){
$hasImage = false;
//Handle file upload
if($request->hasFile("image")){
$filenameWithExt = $request->file("image")->getClientOriginalName();
$filename = pathinfo($filenameWithExt, PATHINFO_FILENAME);
$extension = $request->file("image")->getClientOriginalExtension();
$fileNameToStore = $filename."_".time().".".$extension;
$path = $request->file("image")->storeAs("public/images", $fileNameToStore);
}
else{
$fileNameToStore = "noimage.jpg";
}
$article->title = $request->input("title");
$article->body = $request->input("body");
//$article->user_id = auth()->user()->id;
$article->image = $fileNameToStore;
$article->save();
$response = array(
'status' => 'success',
'msg' => "Hello!",
"request" => $request->all(),
"passesValidation" => true,
"article" => $article,
"hasImage" => $hasImage,
);
return response()->json($response);
}
else{
$response = array(
'status' => 'success',
'msg' => "Hello!",
"request" => $request->all(),
"passesValidation" => false,
);
return response()->json($response);
}
}
}
只是想把这个留给后代,并问其他人:您是否曾经遇到奇迹般解决的问题,但是无论如何解决,您都不是明智之举?
答案 0 :(得分:0)
好象您正在将本地路径上传到图像,而不是Ajax方法中的图像本身。阅读this part of MDN documentation后,我意识到您可能会这样写:
updateFormElements.image = updateForm.elements[5].files[0];
答案 1 :(得分:0)
代替这个
let formData = new FormData();
formData.append("title", updateFormElements.title);
formData.append("body", updateFormElements.body);
formData.append("image", updateFormElements.image);
使用此
var formData = new FormData(this);
动态生成的完整源代码如下,如果直接提供点击事件,请改用事件绑定: 请检查一下 event binding
只需给出如下按钮: 提交 将按钮从按钮的侧面移出,可以从button outside form
中移出<script>
$(document).ready(function (e) {
$('#updateBtn').on('submit',(function(e) {
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
e.preventDefault();
var formData = new FormData(this);
$.ajax({
type:'POST',
url: "{{ url('save-image')}}",
data:formData,
success:function(data){ },
error: function(data){}
});
}));
});
答案 2 :(得分:0)
要使用ajax上传文件,请尝试以下操作:
var fileData = $('#id_of_file').prop('files')[0];
var formData = new FormData(); // Create formdata object
formData.append('fileData', fileData); // append key: value pair in it
formData.append('key1', value1);
formData.append('key2', value2);
并在ajax中使用它,例如:
$.ajax({
url: $('meta[name="route"]').attr('content') + '/ur_route',
method: 'post',
data: formData,
contentType : false,
processData : false,
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
},
success: function(response){
// do whatever you want
}
});
在服务器端(控制器),您将使用fileData
索引获取文件。