У меня есть страница, на которой отображается список авторов, и для каждого автора я хочу иметь возможность загрузить свое изображение.У меня есть форма внутри 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;
}