如何在淘汰赛 foreach 绑定中使用表单
Posted
技术标签:
【中文标题】如何在淘汰赛 foreach 绑定中使用表单【英文标题】:How to use form inside knockout foreach binding 【发布时间】:2019-07-25 05:45:57 【问题描述】:我有一个显示作者列表的页面,我希望能够为每个作者上传他们的图片。 我在 foreach 中有一个表单(对于每个作者或咨询编辑),它调用自定义绑定函数“fileupload” 这是用于上传图像和调用 API 端点的处理程序。
问题在于 API URL
this.EditorImageUploadUrl(Api.baseApi + "/topics/" + this.Id + "/uploadEditorImage/" + e.AuthorRef);
它总是返回一个作者引用,它是数组中的最后一个,而不是我选择的实际作者...... 我会以错误的方式解决这个问题吗?如何返回正确的 URL?有没有更好的写法?
谢谢
<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;
【问题讨论】:
应该EditorImageUploadUrl
是每个ConsultingEditors
的属性吗?
【参考方案1】:
@adiga 是对的,你只是在每次迭代 data.ConsultingEditors.forEach
时静态地重新分配 Topic.EditorImageUploadUrl
,显然最后一个最终是 authorRef
,也许你可以只创建 url onClick 而不是 in进步?
例如
html 绑定:fileupload: url: $parent.EditorImageUploadUrl, authorRef: authorRef
在bindinghandler中:var authorRef = config.authorRef
这样就可以在fileupload bindinghandler中构造url
**评论后更新
那么你为什么不直接在NavigatorAuthorApi.EditorImageUploadUrl
-property 上的NavigatorAuthorApi
类中输入 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);
);
【讨论】:
我需要这个在 url 因为文件上传自定义绑定在别处使用以上是关于如何在淘汰赛 foreach 绑定中使用表单的主要内容,如果未能解决你的问题,请参考以下文章