In upload async file :
for example if i uploading 3 file Debug.WriteLine(info.FullName); and _db.Files.Add(New FileDto{FileName=info.Name}); repeated 50 time.means 50 record insert in database.
Why and how to avoid it?
what is my problem?
public Task<IEnumerable<FileDesc>> Post()
{
string folderName = "uploads";
string PATH = HttpContext.Current.Server.MapPath("~/" + folderName);
string rootUrl = Request.RequestUri.AbsoluteUri.Replace(Request.RequestUri.AbsolutePath, String.Empty);
if (Request.Content.IsMimeMultipartContent())
{
var streamProvider = new CustomMultipartFormDataStreamProvider(PATH);
var task = Request.Content.ReadAsMultipartAsync(streamProvider).ContinueWith<IEnumerable<FileDesc>>(t =>
{
if (t.IsFaulted || t.IsCanceled)
{
throw new HttpResponseException(HttpStatusCode.InternalServerError);
}
var fileInfo = streamProvider.FileData.Select(i =>
{
var info = new FileInfo(i.LocalFileName);
Debug.WriteLine(info.FullName);//************Repeated******
_db.Files.Add(New FileDto{FileName=info.Name});//************Repeated******
return new FileDesc(info.Name, rootUrl + "/" + folderName + "/" + info.Name, info.Length / 1024);
});
return fileInfo;
});
return task;
}
else
{
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotAcceptable, "This request is not properly formatted"));
}
}
[Update]
CustomMultipartFormDataStreamProvider :
public class CustomMultipartFormDataStreamProvider : MultipartFormDataStreamProvider
{
public CustomMultipartFormDataStreamProvider(string path)
: base(path)
{
}
public override string GetLocalFileName(System.Net.Http.Headers.HttpContentHeaders headers)
{
var name = !string.IsNullOrWhiteSpace(headers.ContentDisposition.FileName) ? headers.ContentDisposition.FileName : "NoName";
return name.Replace("\"", string.Empty);
}
}
[Update]
$('#fileupload').fileupload({
dataType: "json",
url: "/media/upload",
limitConcurrentUploads: 1,
sequentialUploads: true,
progressInterval: 100,
maxChunkSize: 10000,
add: function (e, data) {
$('#filelistholder').removeClass('hide');
data.context = $('<div />').text(data.files[0].name).appendTo('#filelistholder');
$('<div class="progress progress-striped active"><div style="width: 0%;" class="progress-bar progress-bar-warning"></div></div>').appendTo(data.context);
$('#btnUploadAll').click(function () {
data.submit();
});
},
done: function (e, data) {
data.context.text(data.files[0].name + '... Completed');
$('<div class="progress progress-striped active"><div style="width: 100%;" class="progress-bar progress-bar-success"></div></div>').appendTo(data.context);
},
progressall: function (e, data) {
var progress = parseInt(data.loaded / data.total * 100, 10);
$('#overallbar').css('width', progress + '%');
},
progress: function (e, data) {
var progress = parseInt(data.loaded / data.total * 100, 10);
data.context.find('.progress-bar').css('width', progress + '%');
}
});
Your Debug.WriteLine is in the projection function of streamProvider.FileData.Select, so it is executed as many times as there are items in streamProvider.FileData.
Related
I'm trying to invoke a javascript function in a Blazor component, but with no success.
The error is:
Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
Unhandled exception rendering component: Could not find 'FullCalendarInterop.init' ('FullCalendarInterop' was undefined).
Error: Could not find 'FullCalendarInterop.init' ('FullCalendarInterop' was undefined).
at https://localhost:7065/_framework/blazor.webassembly.js:1:328
at Array.forEach ()
at a.findFunction (https://localhost:7065/_framework/blazor.webassembly.js:1:296)
at _ (https://localhost:7065/_framework/blazor.webassembly.js:1:2437)
at https://localhost:7065/_framework/blazor.webassembly.js:1:3325
at new Promise ()
Component structure:
Razor page:
#using Microsoft.JSInterop
#inject IJSRuntime JSRuntime
protected override async Task OnAfterRenderAsync(bool firstRender)
{
var options = new CalendarOptions
{
Id = Id,
DefaultView = View,
CalendarEvents = Events.Where(r => r.Status == CalendarEventStatus.Active).ToList()
};
var dotNetObjectReference = DotNetObjectReference.Create(this);
var fullCalendarInterop = await JSRuntime.InvokeAsync<IJSObjectReference>("import", "./Shared/InputCalendar.razor.js");
await fullCalendarInterop.InvokeVoidAsync("FullCalendarInterop.init", options, dotNetObjectReference);
// I already just tried^
// await JSRuntime.InvokeVoidAsync("FullCalendarInterop.init", options, DotNetObjectReference.Create(this));
await base.OnAfterRenderAsync(firstRender);}
Javascript
var FullCalendarInterop = function () {
return {
//main function to initiate the module
init: function (options, dotNetReference) {
var calendarEl = document.getElementById(options.id);
var calendar = new window.FullCalendar.Calendar(calendarEl, {
plugins: ['interaction', 'dayGrid', 'timeGrid', 'list'],
isRTL: window.KTUtil.isRTL(),
header: {
left: 'prev,next today',
center: 'title',
right: 'dayGridMonth,timeGridWeek,timeGridDay,listWeek'
},
height: 800,
contentHeight: 750,
aspectRatio: 3, // see: https://fullcalendar.io/docs/aspectRatio
views: {
dayGridMonth: { buttonText: 'month' },
timeGridWeek: { buttonText: 'week' },
timeGridDay: { buttonText: 'day' },
listWeek: { buttonText: 'list' }
},
defaultView: options.defaultView,
defaultDate: options.defaultDate,
editable: true,
eventLimit: true, // allow "more" link when too many events
navLinks: true,
events: options.calendarEvents,
eventRender: function (info) {
var event = $(info.event);
var element = $(info.el);
var view = $(info.view);
if (info.event.extendedProps && info.event.extendedProps.description) {
if (element.hasClass('fc-day-grid-event')) {
element.data('content', info.event.extendedProps.description);
element.data('placement', 'top');
window.KTApp.initPopover(element);
} else if (element.hasClass('fc-time-grid-event')) {
element.find('.fc-title').append('<div class="fc-description">' + info.event.extendedProps.description + '</div>');
} else if (element.find('.fc-list-item-title').lenght !== 0) {
element.find('.fc-list-item-title').append('<div class="fc-description">' + info.event.extendedProps.description + '</div>');
}
}
element.find(".fc-bg").css("pointer-events", "none");
element.find(".fc-list-item-title.fc-widget-content").prepend(
"<span style='position: absolute; right: 5px;'>" +
"<button class='btn btn-icon btn-xs btn-circle btn-light' " +
"style='height: 16px; width: 16px;' id='calendar_del_" + event.id + "'>" +
"<i class='icon-xs text-dark-50 flaticon2-cross'></i></button></span>");
element.find(".fc-content").append("<span style='position: absolute; top: 5px; right: 5px;'>" +
"<button class='btn btn-icon btn-xs btn-circle btn-light' " +
"style='height: 16px; width: 16px;' id='calendar_del_" + event.id + "'>" +
"<i class='icon-xs text-dark-50 flaticon2-cross'></i></button></span>");
element.find("#calendar_del_" + event.id).click(function () {
var eventId = event[0]._def.defId;
var eventIdentifier = event[0]._def.extendedProps.identifier;
//Remove popover
removeContent(".popover.fade.show.bs-popover-top");
//$(".popover.fade.show.bs-popover-top").remove();
dotNetReference.invokeMethodAsync('CalendarEventDeleted', eventIdentifier);
//$("#candidate_calendar").fullCalendar('removeEvents', eventId);
});
},
viewSkeletonRender: function (info) {
var view = $(info.view);
var defaultView = view[0].type !== null ? view[0].type : "";
dotNetReference.invokeMethodAsync('SetDefaultView', defaultView);
//alert(defaultView);
}
});
calendar.render();
}
};
}
Modify your .JS file like so:
var FullCalendarInterop = function () {
return {
//main function to initiate the module
init: function (options, dotNetReference) {
... Trimmed for brevity ...
calendar.render();
}
};
}();
export { FullCalendarInterop };
I added (); to the end of your FullCalendarInterop function and then added the export. That should work for you.
As it says its a null reference error as you are not initializing JSmodule,
IJSObjectReference fullCalendarInterop;
fullCalendarInterop = await JSRuntime.InvokeAsync<IJSObjectReference>("import", "./Shared/InputCalendar.razor.js");
I am trying to load my typeahead.js by using bloohound's remote function where i can call my Web Method. I have seen similar threads where a querystring is being used :
Integrating Typeahead.js with ASP.Net Webmethod
Typeahead.js and Bloodhound.js integration with C# WebForms WebMethod
http://yassershaikh.com/using-twitter-typeahead-js-with-asp-net-mvc-web-api/
And many more....
However, i cannot find an example where ajax is used to call the webmethod from typeahead.js.
So this is what i have currently and it works:
WebMethod
[WebMethod]
public static string GetEmployeeTypeahead()
{
JavaScriptSerializer jss = new JavaScriptSerializer();
jss.MaxJsonLength = 100000000;
string json;
using (var rep = new RBZPOS_CSHARPEntities())
{
var result = rep.Employees
.Where(x => x.EMPLOYEESTATE == 1)
.Select(x => new {
x.EMPLOYEEID,
x.FULLNAME,
x.MANNO,
x.NRC
}).ToList();
json = jss.Serialize(result);
}
return json;
}
The Client
function LoadEmployeeJSON() {
$.ajax({
type: "POST",
url: "/WebMethods/Test.aspx/GetEmployeeTypeahead",
data: "{}",
contentType: "application/json",
dataType: "json",
success: function (msg) {
empList = $.parseJSON(msg.d); //otherwise does not work
LoadEmployeeTypeahead();
},
error: function (msg) {
alert("error:" + JSON.stringify(msg));
}
});
}
function LoadEmployeeTypeahead() {
var empData = empList;
var fullname = new Bloodhound({
datumTokenizer: function (d) {
return Bloodhound.tokenizers.whitespace(d.FULLNAME)
},
queryTokenizer: Bloodhound.tokenizers.whitespace,
local: empData,
limit: 10
});
fullname.initialize();
// Make the code less verbose by creating variables for the following
var fullnameTypeahead = $('#<%=txtFullName.ClientID %>.typeahead');
// Initialise typeahead for the employee name
fullnameTypeahead.typeahead({
highlight: true
}, {
name: 'FULLNAME',
displayKey: 'FULLNAME',
source: fullname.ttAdapter(),
templates: {
empty: [
'<div class="empty-message">',
'No match',
'</div>'
].join('\n'),
suggestion: function (data) {
return '<h6 class="">' + data.FULLNAME + "<span class='pull-right text-muted small'><em>" + data.NRC + "</em></span>" + '</h6>';
}
}
});
var fullnameSelectedHandler = function (eventObject, suggestionObject, suggestionDataset) {
/* See comment in previous method */
$('#<%=txtFullName.ClientID %>').val(suggestionObject.FULLNAME);
$('#<%=txtEmployeeID.ClientID %>').val(suggestionObject.EMPLOYEEID);
$('#<%=txtManNo.ClientID %>').val(suggestionObject.MANNO);
$('#<%=txtNRC.ClientID %>').val(suggestionObject.NRC);
};
// Associate the typeahead:selected event with the bespoke handler
fullnameTypeahead.on('typeahead:selected', fullnameSelectedHandler);
}
function clearAndReInitilize() {
$('.typeahead').typeahead('destroy');
$('.typeahead').val('');
}
So as you can see i am making a local call instead of remote.
How can i get the remote function to call my webthod and fill the typeahead without using any querystrings
Okay finally got it to work via an ashx generic handler. So instead of using a web method i used the following ashx handler:
public class Employess : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
JavaScriptSerializer jss = new JavaScriptSerializer();
jss.MaxJsonLength = Int32.MaxValue;
string json;
string prefixText = context.Request.QueryString["query"];
using (var rep = new RBZPOS_CSHARPEntities())
{
var result = rep.Employees
.Where(x => x.EMPLOYEESTATE == 1 && x.FULLNAME.Contains(prefixText.ToUpper()))
.Select(x => new
{
x.EMPLOYEEID,
x.FULLNAME,
x.MANNO,
x.NRC
}).ToArray();
json = jss.Serialize(result);
}
context.Response.ContentType = "text/javascript";
context.Response.Write(json);
}
public bool IsReusable
{
get
{
return false;
}
}
}
Below is the jquery and the ajax call to the ashx handler
$(document).ready(function () {
$(document).ajaxStart($.blockUI).ajaxStop($.unblockUI);
LoadEmployeeTypeahead();
// LoadEmployeeJSON();
});
function LoadEmployeeTypeahead() {
//var empData = empList;
var fullname = new Bloodhound({
remote: {
url: '/Employess.ashx?query=%QUERY',
wildcard: '%QUERY'
},
datumTokenizer: function (d) {
//var employees = $.parseJSON(msg.d);
return Bloodhound.tokenizers.whitespace(d.FULLNAME)
},
queryTokenizer: Bloodhound.tokenizers.whitespace,
limit: 10
});
fullname.initialize();
// Make the code less verbose by creating variables for the following
var fullnameTypeahead = $('#<%=txtFullName.ClientID %>.typeahead');
// Initialise typeahead for the employee name
fullnameTypeahead.typeahead({
highlight: true
}, {
name: 'FULLNAME',
displayKey: 'FULLNAME',
source: fullname.ttAdapter(),
templates: {
empty: [
'<div class="empty-message">',
'No match',
'</div>'
].join('\n'),
suggestion: function (data) {
return '<h6 class="">' + data.FULLNAME + "<span class='pull-right text-muted small'><em>" + data.MANNO + "</em></span><span class='pull-right text-muted small'><em>" + data.NRC + "</em></span>" + '</h6>';
}
}
});
var fullnameSelectedHandler = function (eventObject, suggestionObject, suggestionDataset) {
/* See comment in previous method */
$('#<%=txtFullName.ClientID %>').val(suggestionObject.FULLNAME);
$('#<%=txtEmployeeID.ClientID %>').val(suggestionObject.EMPLOYEEID);
$('#<%=txtManNo.ClientID %>').val(suggestionObject.MANNO);
$('#<%=txtNRC.ClientID %>').val(suggestionObject.NRC);
};
// Associate the typeahead:selected event with the bespoke handler
fullnameTypeahead.on('typeahead:selected', fullnameSelectedHandler);
}
the code on the belows add/remove/list products to cart, it works first time correctly, when i add second product its not refresh cart, when i refresh cart, i see second product. Anyone help me what i forget?
Note: Controller method returns JsonResult
jQuery(document).ready(function () {
jQuery('#vmCartModule').hover(
function () {
jQuery('#cart_list').stop(true, true).slideDown(400)
},
function () {
jQuery('#cart_list').stop(true, true).delay(500).slideUp(100)
}
)
new Request.HTML({
'url': 'Sepetim/Sepet',
'method': 'get',
'data': '',
'onSuccess': function (tree, elms, html, js) {
//jQuery(".vmCartModule").productUpdate();
mod = jQuery(".vmCartModule");
jQuery.getJSON(vmSiteurl + "Sepetim/Sepet",
function (datas) {
if (datas == null) {
mod.find(".text-cart").html("Sepetiniz Boş"); // Sepet boş
mod.find(".vm_cart_products").html("");
mod.find(".total").html("");
mod.find(".show_cart").html("");
}
else if (datas.ProductCount > 0) { // Ürün sayısı
//mod.find(".vm_cart_products").html("");
mod.find(".cart_list").html("");
mod.find(".crt-text").html(datas.ProductCount + " ürün mevcut");
datas.CartList.reverse();
jQuery.each(datas.CartList, function (key, val) {
if (key < 4) {
jQuery("#hiddencontainer .container").clone().appendTo(".vmCartModule .vm_cart_products");
jQuery.each(val, function (key, val) {
if (jQuery("#hiddencontainer .container ." + key)) {
mod.find(".vm_cart_products ." + key + ":last").html(mod.find(".vm_cart_products ." + key + ":last").html() + val);
}
});
}
});
mod.find(".total").html("Toplam Tutar: " + datas.TotalAmount + "TL"); //Toplam Tutar
mod.find(".show_cart").html(datas.ShowCart);
} else {
mod.find(".text-cart").html("Sepetiniz Boş"); // Sepet boş
mod.find(".vm_cart_products").html("");
mod.find(".total").html("");
mod.find(".show_cart").html("");
}
}
);
}
}).send();
});
function add_product_cart(elm) {
var cart_id = jQuery(elm).children("span.product_cart_id").text();
new Request.HTML({
'url': 'Sepetim/SepeteUrunEkle',
'method': 'post',
'data': 'productID=' + cart_id + '&count=' + 1,
'onSuccess': function (tree, elms, html, js) {
mod = jQuery(".vmCartModule");
jQuery.getJSON(vmSiteurl + "Sepetim/Sepet?callback=",
function (datas) {
if (datas.ProductCount > 0) { // Ürün sayısı
mod.find(".vm_cart_products").html("");
mod.find(".cart_list").html("");
mod.find(".crt-text").html(datas.ProductCount + " ürün mevcut");
datas.CartList.reverse();
jQuery.each(datas.CartList, function (key, val) {
if (key < 4) {
jQuery("#hiddencontainer .container").clone().appendTo(".vmCartModule .vm_cart_products");
jQuery.each(val, function (key, val) {
if (jQuery("#hiddencontainer .container ." + key)) mod.find(".vm_cart_products ." + key + ":last").html(val);
});
}
});
mod.find(".total").html("Toplam Tutar: " + datas.TotalAmount + "TL"); //Toplam Tutar
mod.find(".show_cart").html(datas.ShowCart);
} else {
mod.find(".text-cart").html("Sepetiniz Boş"); // Sepet boş
mod.find(".vm_cart_products").html("");
mod.find(".total").html("");
mod.find(".show_cart").html("");
}
}
);
}
}).send();
}
function remove_product_cart(elm) {
var cart_id = jQuery(elm).children("span.ProductID").text();
new Request.HTML({
'url': 'Sepetim/SepettenUrunSil',
'method': 'post',
'cache': false,
'datatype': JSON,
'data': 'productID=' + cart_id,
'onSuccess': function (tree, elms, html, js) {
mod = jQuery(".vmCartModule");
jQuery.getJSON(vmSiteurl + "Sepetim/Sepet?callback=",
function (datas) {
if (datas.ProductCount > 0) { // Ürün sayısı
mod.find(".vm_cart_products").html("");
mod.find(".cart_list").html("");
mod.find(".crt-text").html(datas.ProductCount + " ürün mevcut");
datas.CartList.reverse();
jQuery.each(datas.CartList, function (key, val) {
if (key < 4) {
jQuery("#hiddencontainer .container").clone().appendTo(".vmCartModule .vm_cart_products");
jQuery.each(val, function (key, val) {
if (jQuery("#hiddencontainer .container ." + key)) mod.find(".vm_cart_products ." + key + ":last").html(val);
});
}
});
mod.find(".total").html("Toplam Tutar: " + datas.TotalAmount + "TL"); //Toplam Tutar
mod.find(".show_cart").html(datas.ShowCart);
} else {
mod.find(".text-cart").html("Sepetiniz Boş"); // Sepet boş
mod.find(".vm_cart_products").html("");
mod.find(".total").html("");
mod.find(".show_cart").html("");
}
}
);
}
}).send();
}
Thanks
I am trying to upload file using phonegap "FileTransfer". I am using .NET WCF OData for uploading the image.
The "upload" function not calling my API, and returns the below error message:
{"code":null,"source":null,"http_stats":null,"body":null}
my described code is as below:
navigator.camera.getPicture(function(imageURI){
var url = encodeURI("http://api.xyz.com/DataService/DataService.svc/UploadImage");
var params = new Object();
params.id= parseInt(1);
var options = new FileUploadOptions();
options.fileKey = "file";
options.fileName = imageURI.substr(imageURI.lastIndexOf('/') + 1);
options.mimeType = "image/jpeg";
options.params = params;
options.chunkedMode = true;
var ft = new FileTransfer();
ft.upload(imageURI, url, function (data) { alert(JSON.stringify(data)) }, function (data) { alert(JSON.stringify(data)) }, options);
}
and my WCF OData code is as below:
[WebInvoke]
public void UploadImage(int id)
{
// **what to write here???**
}
I also tried with following code but window.resolveLocalFileSystemURI function throws an Error calling method on NPObject error
navigator.camera.getPicture(function (imageURI) {
var _this = this;
var encodedURL = encodeURI("http://api.xyz.com/DataService/DataService.svc/UploadImage");
try {
this.op = new FileUploadOptions();
this.op.fileKey = "file";
this.op.fileName = imageURI.substr(imageURI.lastIndexOf('/') + 1);
this.op.mimeType = "image/jpeg";
this.op.chunkedMode = false;
this.op.headers = { Connection: "close" };
this.ft = new FileTransfer();
if (window.device != undefined && device.platform == "Android") {
window.resolveLocalFileSystemURI(imageURI, function (fileEntry) {
fileEntry.file(function (fileObj) {
var fileFullPath = fileObj.fullPath;
_this.op.fileName = fileFullPath.substr(fileFullPath.lastIndexOf('/') + 1);
_this.ft.upload(fileFullPath, encodedURL, function (data) { alert("Success: " + JSON.stringify(data)); }, function (data) { alert("Failour: " + JSON.stringify(data)); }, _this.op, true);
});
});
} else {
this.ft.upload(imageURI, encodedURL, function (data) { alert("Success: " + JSON.stringify(data)); }, function (data) { alert("Failour: " + JSON.stringify(data)); }, this.op, true);
}
} catch (_error) {
alert(_error);
}
},
function (message) { },
{
quality: 50,
destinationType: navigator.camera.DestinationType.FILE_URI,
sourceType: navigator.camera.PictureSourceType.PHOTOLIBRARY
});
}
I'm trying to get the FileDescription asp:textbox to save into a db when the user clicks upload but it's coming back blank. what am I doing wrong?
this is in my upload.aspx file
<ajaxToolkit:AjaxFileUpload ID="AjaxFileUpload1"
ThrobberID="myThrobber" OnUploadComplete="AjaxFileUpload1_UploadComplete"
ContextKeys=""
AllowedFileTypes="jpg,jpeg,doc,xls"
MaximumNumberOfFiles="1"
runat="server"/>
</div>
File Description<asp:TextBox ID="FileDescription" Width="200" runat="server" ></asp:TextBox>
and this is in my upload.cs file
protected void AjaxFileUpload1_UploadComplete(object sender, AjaxControlToolkit.AjaxFileUploadEventArgs e)
{
string sFileDescription = FileDescription.Text;
string filePath = "~/" + e.FileName;
AjaxFileUpload1.SaveAs(filePath);
}
Let's add individual descriptions for each uploaded file. To do this you need to download AjaxControlToolkit sources from Codeplex (here is a link to download: Latest toolkit sources and modify three files:
AjaxFileUpload.Item.pre.js
AjaxFileUpload.Control.pre.js
AjaxFileUpload.css
New content of the AjaxFileUpload.Item.pre.js file:
/// <reference path="../../../client/microsoftajax.extended/common/common.pre.js" />
Type.registerNamespace("Sys.Extended.UI.AjaxFileUpload");
Type.registerNamespace("AjaxFileUpload");
Sys.Extended.UI.AjaxFileUpload.Item = function (parentId, fileItem, onRemoveItem) {
this._deleteButton = null;
this._parentId = parentId;
this._inputElementValue = fileItem.value;
this._id = fileItem.id;
this._slices = fileItem.slices;
this._sliceIndex = 0;
this._fileInfoContainer = null;
this._fileStatusText = null;
this._isUploaded = false;
this._isUploading = false;
this._fileSize = 0;
this._fileName = "";
this._fileType = "";
this._bytesUploaded = 0;
this._fileComment = null;
this._ui = this.initUI(onRemoveItem);
};
Sys.Extended.UI.AjaxFileUpload.Item.prototype = {
initUI: function (onRemoveItem) {
var self = this, file = this._inputElementValue, utils = new Sys.Extended.UI.AjaxFileUpload.Utils(),
isHtml5Support = utils.checkHtml5BrowserSupport(),
// generate unique id for each item
id = this._id,
// create line item container
container = $common.createElementFromTemplate({
nodeName: "div",
properties: {
id: this._parentId + '_FileItemContainer_' + id,
},
cssClasses: ['ajax__fileupload_fileItemInfo']
}),
// create file info/status container
fileInfoContainer = $common.createElementFromTemplate({
nodeName: "div",
properties: {
id: this._parentId + '_FileInfoContainer_' + id,
style: {
display: 'inline-block'
}
}
}),
// create file info placeholder
fileInfoText = $common.createElementFromTemplate({
nodeName: "span",
properties: {
id: this._parentId + '_FileItemInfo_' + id
},
cssClasses: ['ajax__fileupload_fileItemInfo']
}),
// create file status placeholder
fileStatusText = $common.createElementFromTemplate({
nodeName: "span",
properties: {
id: this._parentId + '_FileItemStatus_' + id
},
cssClasses: ['uploadstatus']
}),
commentContainer = $common.createElementFromTemplate({
nodeName: 'div',
cssClasses: ['ajax__fileupload_fileItem_commentContainer']
}),
fileComment = $common.createElementFromTemplate({
nodeName: "input",
properties: {
id: this._parentId + '_FileItemComment_' + id,
type: 'text',
style: {
width: '100%'
}
},
cssClasses: ['ajax__fileupload_fileItem_commentInput']
}),
// init remove button
deleteButton = $common.createElementFromTemplate({
nodeName: "div",
properties: {
id: this._parentId + '_FileItemDeleteButton_' + id
},
cssClasses: ['removeButton']
});
this._fileName = utils.getFileName(file);
if (isHtml5Support) {
this._fileSize = file.size;
var fType = file.type ? '<span class="filetype">(' + file.type + ')</span>' : '';
fileInfoText.innerHTML = '<span class="filename">' + this._fileName + '</span> '
+ fType
+ ' - <span class="filesize">' + utils.sizeToString(file.size) + '</span> ';
this._fileType = file.type;
} else {
fileInfoText.innerHTML = '<span class="filename">' + this._fileName + '</span>';
this._fileType = utils.getFileType(file);
}
commentContainer.innerHTML = '<label class="ajax__fileupload_fileItem_commentLabel" for="' + this._parentId + '_FileItemComment_' + id + '">Description:</label>';
commentContainer.appendChild(fileComment);
fileInfoContainer.appendChild(fileInfoText);
fileInfoContainer.appendChild(fileStatusText);
fileInfoContainer.appendChild(commentContainer);
$common.setText(deleteButton, Sys.Extended.UI.Resources.AjaxFileUpload_Remove);
$addHandlers(deleteButton, {
'click': Function.createDelegate(this, function () {
onRemoveItem(self);
})
});
// build the line item
if (Sys.Browser.agent == Sys.Browser.InternetExplorer && Sys.Browser.version <= 8) {
container.appendChild(deleteButton);
container.appendChild(fileInfoContainer);
}
else {
container.appendChild(fileInfoContainer);
container.appendChild(deleteButton);
}
this._fileInfoContainer = fileInfoContainer;
this._deleteButton = deleteButton;
this._fileStatusText = fileStatusText;
this._fileComment = fileComment;
return container;
},
setStatus: function (fileStatusText, text) {
$common.setText(this._fileStatusText, ' (' + text + ')');
this._fileInfoContainer.setAttribute('class', fileStatusText + 'State');
},
disabled: function (on) {
if (on)
this._deleteButton.disabled = this._fileComment.disabled = 'disabled';
else
this._deleteButton.disabled = this._fileComment.disabled = '';
},
hide: function () {
this._deleteButton.style.visibility = 'hidden';
this._fileComment.readOnly = true;
},
destroy: function () {
$common.removeElement(this._inputElementValue);
$common.removeElement(this._deleteButton);
$common.removeElement(this._fileComment);
$common.removeElement(this._ui);
},
get_inputElementValue: function () {
return this._inputElementValue;
},
appendNodeTo: function (parent) {
parent.appendChild(this._ui);
},
removeNodeFrom: function (parent) {
parent.removeChild(this._ui);
},
get_fileComment: function () {
return this._fileComment.value;
}
};
In this code added new class field _fileComment, new function get_fileComment and modified initUI, disabled, hide and destroy functions. After these changes, each file item will have individual textbox for file description.
After that, change a bit AjaxFileUpload.Control.pre.js file. Rewrite the doneAndUploadNextFile function as below:
doneAndUploadNextFile: function (fileItem) {
/// <summary>
/// Mark fileItem as uploaded, and upload next file in queue.
/// </summary>
/// <param name="fileItem">Uploaded File</param>
// send message to server to finalize this upload
var xhr = new XMLHttpRequest(),
self = this;
xhr.open("POST", "?contextKey="+ this._contextKey +"&done=1&guid=" + fileItem._id + "&comment=" + fileItem.get_fileComment(), true);
xhr.onreadystatechange = function (e) {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
// Mark as done and invoke event handler
self.raiseUploadComplete(Sys.Serialization.JavaScriptSerializer.deserialize(xhr.responseText));
// Upload next file
self._processor.startUpload();
} else {
// finalizing is error. next file will not be uploaded.
self.setFileStatus(fileItem, 'error', Sys.Extended.UI.Resources.AjaxFileUpload_error);
self.raiseUploadError(xhr);
throw "error raising upload complete event and start new upload";
}
}
};
xhr.send(null);
}
And the last step is a AjaxFileUpload.css file. Change heigh css rile in .ajax__fileupload_fileItemInfo class definition and add three additional classes for description:
.ajax__fileupload_fileItemInfo {
line-height: 20px;
height: 44px;
margin-bottom: 2px;
overflow: hidden;
}
.ajax__fileupload_fileItem_commentContainer {
display: table;
width: 100%;
}
.ajax__fileupload_fileItem_commentLabel {
display: table-cell;
width: 1px;
white-space: nowrap;
padding-right: 5px;
}
.ajax__fileupload_fileItem_commentInput {
display: table-cell;
width: 100%;
}
After these changes rebuild toolkit solution and use custom dlls.
Now you can get posted description from query string in OnUploadComplete event handler: var comment = Request.QueryString["comment"];