我有一个页面,显示一个作者列表,并且希望每个作者都可以上传其图像。 我在foreach中有一个表格(针对每个作者或咨询编辑),该表格调用自定义绑定函数“ fileupload” 这是用于上传图片并调用API端点的处理程序。
问题出在API URL
this.EditorImageUploadUrl(Api.baseApi + "/topics/" + this.Id + "/uploadEditorImage/" + e.AuthorRef);
它总是返回一个作者引用,这是数组中的最后一个引用,而不是我选择的实际作者。 我会以错误的方式处理吗?如何返回正确的URL?有没有更好的方法来写这个?
谢谢
HTML
<div class="consulting-editors" data-bind="foreach: ConsultingEditors">
<i class="fa fa-times" data-bind="click: $parent.removeConsultingEditor"></i>
<span class="editor-name" data-bind="text: AuthorName"></span>
<form method="post" enctype="multipart/form-data" data-bind="fileupload: { url: $parent.EditorImageUploadUrl }" class="form-horizontal">
<div class="upload-image">
<div class="button">
<span class="btn btn-success fileinput-button">
<input type="file" id="file" class="hidden" />
<label for="file">Add editor photo</label>
</span>
</div>
<div class="progress" style="width: 30%; float: left; margin: 10px 0 0; display:none;">
<div class="bar" style="width: 0%;"></div>
</div>
<div class="info" style="width:30%; float:left; margin: 10px 0 0; display:none;"></div>
</div>
</form>
<div class="editor-image">
<img data-bind="attr: { src: EditorImageUrl }" />
</div>
</div>
获取图片上传URL和源路径
export class Topic {
ConsultingEditors: KnockoutObservableArray<NavigatorAuthorApi> = ko.observableArray();
EditorImageUploadUrl: KnockoutObservable<string> = ko.observable();
EditorImageSource: KnockoutObservable<string[]> = ko.observable();
removeConsultingEditor = (editor: NavigatorAuthorApi) => {
this.ConsultingEditors.remove(editor);
}
constructor(data: NavigatorTopicApi) {
this.Id = data.Id;
this.ConsultingEditors(data.ConsultingEditors);
data.ConsultingEditors.forEach((e) => {
e.EditorImageUrl = 'data:image/jpeg;base64,' + e.EditorImage;
this.EditorImageUploadUrl(Api.baseApi + "/topics/" + this.Id + "/uploadEditorImage/" + e.AuthorRef);
});
...
}
}
export type NavigatorAuthorApi =
{
SortOrder: number,
FirmRef: number,
FirmName: string,
AuthorRef: number,
AuthorName: string,
DisplayString: string,
EditorImage: ByteString[],
EditorImageUrl: string
}
文件上传脚本
import { ConfirmDialog } from '../../Components/Typescript/confirmdialog';
declare global {
interface JQuery {
fileupload(option: any, url?: any, value?: any): any;
confirmDialog: ConfirmDialog;
}
}
export default function init(ko: KnockoutStatic) {
ko.bindingHandlers.fileupload = {
init: function (element, valueAccessor, allBindings) {
var config = ko.unwrap(valueAccessor());
var url = ko.unwrap(config.url);
var confirmDialog = new ConfirmDialog("#confirmDialog");
$(element).fileupload({
add: function (e, data) {
var acceptFileTypes = config.acceptFileTypes || /(\.|\/)(jpg|gif|jpeg|png)$/i; // default to just images
if (data.originalFiles[0]['type'].length && !acceptFileTypes.test(data.originalFiles[0]['name'])) {
confirmDialog.showFailure({ title: "Error", subHeader: "Files of this type cannot be uploaded"});
}
else {
data.submit();
}
},
url: url,
type: 'POST',
progressall: function (e, data) {
var calc = data.loaded / data.total * 100;
var progress = parseInt(calc.toString(), 10);
$(element).find('.progress .bar').css(
'width',
progress + '%'
);
var filesize, loaded;
if (data.total >= 1000000000) {
filesize = (data.total / 1000000000).toFixed(2) + ' Gbit/s';
}
else if (data.total >= 1000000) {
filesize = (data.total / 1000000).toFixed(2) + ' Mbit/s';
}
else if (data.total >= 1000) {
filesize = (data.total / 1000).toFixed(2) + ' kbit/s';
}
else {
filesize = data.total.toFixed(2) + ' bit/s';
}
if (data.loaded >= 1000000000) {
loaded = (data.loaded / 1000000000).toFixed(2) + ' Gbit/s';
}
else if (data.loaded >= 1000000) {
loaded = (data.loaded / 1000000).toFixed(2) + ' Mbit/s';
}
else if (data.loaded >= 1000) {
loaded = (data.loaded / 1000).toFixed(2) + ' kbit/s';
}
else {
loaded = data.loaded.toFixed(2) + ' bit/s';
}
$(element).find('.info').html(loaded + '/' + filesize);
},
start: function (e, data) {
$(element).find('.progress, .info').show();
},
done: function (e, data) {
setTimeout(function () {
$(element).find('.progress, .info').fadeOut(400, function () {
$(element).find('.progress .bar').css('width', '0%');
});
}, 500);
confirmDialog.showSuccess({ title: "Success", subHeader: "Image uploaded successfully" });
},
fail: function (e, data) {
setTimeout(function () {
$(element).find('.progress, .info').fadeOut(400, function () {
$(element).find('.progress .bar').css('width', '0%');
});
}, 500);
var xhrObject = data.xhr();
if (xhrObject && xhrObject.status == '412') {
confirmDialog.showFailure({ title: "Error", subHeader: "Failed to upload image " + xhrObject });
} else {
confirmDialog.showFailure({ title: "Error", subHeader: "Failed to upload image " + data });
}
}
});
}
};
}
API端点
[Route("topics/{topicId}/uploadEditorImage/{authorRef}")]
[HttpPost]
public async Task<HttpResponseMessage> UpdateEditorImage(Guid topicId, int authorRef)
{
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.UnsupportedMediaType);
if (topicId != null)
{
if (Request.Content.IsMimeMultipartContent())
{
var provider = new MultipartMemoryStreamProvider();
await Request.Content.ReadAsMultipartAsync(provider);
var file = provider.Contents.First();
var data = await file.ReadAsByteArrayAsync();
await topicService.UploadEditorImage(topicId, authorRef, data);
return Request.CreateResponse(HttpStatusCode.OK);
}
}
else
{
response = Request.CreateResponse(HttpStatusCode.BadRequest, "The topic does not exist");
}
return response;
}
答案 0 :(得分:0)
@adiga是正确的,您只是在每次迭代Topic.EditorImageUploadUrl
上静态地重新分配data.ConsultingEditors.forEach
,显然最后一个最终为authorRef
,也许您可以创建url onClick而不是提前?
例如
html绑定:fileupload: { url: $parent.EditorImageUploadUrl, authorRef: authorRef }
以及在绑定处理程序中:var authorRef = config.authorRef
,以便您可以在文件上传绑定处理程序中构造网址
**评论后更新
那么,为什么不只在NavigatorAuthorApi
属性的NavigatorAuthorApi.EditorImageUploadUrl
类中输入url,那样您将为数据列表中的每个对象获得一个正确的url,甚至认为这是您的意图,但是您有一个this
而不是e
。
data.ConsultingEditors.forEach((e) => {
e.EditorImageUrl = 'data:image/jpeg;base64,' + e.EditorImage;
e.EditorImageUploadUrl(Api.baseApi + "/topics/" + this.Id + "/uploadEditorImage/" + e.AuthorRef);
});