Adding a .ajaxForm function to standard .ajax call - ajax

So I'm trying to find a method of getting a progress bar working on my .ajax call but not having much luck. I know that the ajaxForm plugin has the following code in it that allows for the uploadProgress option but the way my code works I'm not able to use that plugin. Is there anyway of adding the following code somehow so that it attaches to the standard .ajax call? Long shot I know!
// XMLHttpRequest Level 2 file uploads (big hat tip to francois2metz)
function fileUploadXhr(a) {
var formdata = new FormData();
for (var i=0; i < a.length; i++) {
formdata.append(a[i].name, a[i].value);
}
if (options.extraData) {
var serializedData = deepSerialize(options.extraData);
for (i=0; i < serializedData.length; i++)
if (serializedData[i])
formdata.append(serializedData[i][0], serializedData[i][1]);
}
options.data = null;
var s = $.extend(true, {}, $.ajaxSettings, options, {
contentType: false,
processData: false,
cache: false,
type: method || 'POST'
});
if (options.uploadProgress) {
// workaround because jqXHR does not expose upload property
s.xhr = function() {
var xhr = jQuery.ajaxSettings.xhr();
if (xhr.upload) {
xhr.upload.addEventListener('progress', function(event) {
var percent = 0;
var position = event.loaded || event.position; /*event.position is deprecated*/
var total = event.total;
if (event.lengthComputable) {
percent = Math.ceil(position / total * 100);
}
options.uploadProgress(event, position, total, percent);
}, false);
}
return xhr;
};
}
s.data = null;
var beforeSend = s.beforeSend;
s.beforeSend = function(xhr, o) {
o.data = formdata;
if(beforeSend)
beforeSend.call(this, xhr, o);
};
return $.ajax(s);
}

I do not guarantee on that, but try this:
xhr.upload.onprogress = function(event) {
var percent = 0;
var position = event.loaded || event.position;
var total = event.total;
if (event.lengthComputable) {
percent = Math.ceil(position / total * 100);
}
console.log("Progress: "+percent+"%"); //debug to see if the problem is there
options.uploadProgress(event, position, total, percent);
};
From posted code, I cannot even guess if the problem is in onprogress event handling or that options.uploadProgress, whatever it is.
I posted this as answer only because it wouldn't fit in comment.

Related

While make frequent request on Chrome.Getting Aw snap! error

I'm uploading the big files using chunk method.If i make minimum number request to the server uploading is working fine.if make high number of request to the server Chrome browser has crashed with Aw Snap! error message.But other browsers are working fine with high number of request.
How to resolve this.Is there workaround?is it chromium bug?
Updated
Below function will slice the file then upload chunk to server .After all chunks uploaded. Merge Api will merge the chunk.
Code:
function readFile (file) {
var uploadBatchKey = this.guid;
var start = 0; //Start Index
var stop = file.size; //End Index
var chunksize = (document.getElementById('chunkSize').value * 1048576);
var index = this.chunkUploadIndex;
var reader = new FileReader();
var filecontent = null;
var waitingInterval = null;
var totalsegment = Math.ceil(stop / chunksize);
var isPreviousChunkUpload = true;
var match = ko.utils.arrayFirst(JSViewmodel.SelectedFiles(), function (item) {
return item.UploadManager == undefined ? false : (uploadBatchKey === item.UploadManager.guid);
});
match.UploadBatchKey(uploadBatchKey);
var handle = setInterval(function () {
if (isPreviousChunkUpload) {
if (!match.IsUploading()) {
clearInterval(handle);
}
else if (index > totalsegment) {
isPreviousChunkUpload = false;
var filename = match.IsRelativePath() ? file.webkitRelativePath : file.name;
console.log(file.size);
var batchData = { uploadBatchKey: uploadBatchKey, fileName: filename, fileSize: file.size };
$.ajax({
url: "/Home/MergeChunk",
type: 'POST',
async: false,
data: batchData,
success: function (result) {
debugger;
console.log(result);
if (result == "False")
match.IsFailed(true);
},
error: function (result) {
console.log(result);
debugger;
match.IsFailed(true);
}
});
match.IsUploading(false);
match.IsCompleted(true);
clearInterval(handle);
}
start = (index - 1) * chunksize;
stop = (index * chunksize) - 1;
reader.onloadend = function (evt) {
if (evt.target.readyState == FileReader.DONE) { // DONE == 2
filecontent = evt.target.result;
var chunkContent = { chunkContent: window.btoa(filecontent), chunkIndex: index - 1, uploadBatchKey: uploadBatchKey };
console.log("onloadend" + chunkContent.chunkIndex);
$.ajax({
url: "/Home/Upload",
type: 'POST',
async: false,
data: chunkContent,
success: function (result) {
match.Percentage(Math.round((chunkContent.chunkIndex / totalsegment) * 100));
isPreviousChunkUpload = true;
}
});
}
};
var blob = file.slice(start, stop + 1);
reader.readAsBinaryString(blob);
isPreviousChunkUpload = false;
console.log("file slice:" + index);
index++;
match.UploadManager.chunkUploadIndex = index;
}
}, 500);
}

Error Message- Failed with: success/error was not called

Parse.Cloud.job("JobSchedule", function(request, response) {
var Group = Parse.Object.extend("Group");
var query = new Parse.Query(Group);
query.equalTo("JobScheduled", true);
query.find({
success: function(results) {
for (var i = 0; i < results.length; ++i) {
var created = new Date(results[i].createdAt);
var current = new Date();
var timeDiff = Math.abs(current.getTime() - created.getTime());
var horsDiff = timeDiff / (60 * 60 * 1000);
if (horsDiff >= parseInt(results[i].get("JobHours"))) {
results[i].set("JobScheduled", false);
results[i].set("GroupType", "Private");
results[i].set("JobHours", 0);
results[i].save();
var GroupMembers = Parse.Object.extend("GroupMembers");
var query1 = new Parse.Query(GroupMembers);
query1.equalTo("GroupId", results[i].id);
query1.find({
success: function(grpresults) {
for (var j = 0; j < grpresults.length; ++j) {
grpresults[j].set("GroupType", "Private");
grpresults[j].save();
}
},
error: function(error) {
response.error(error);
}
})
}
}
},
error: function(error) {
response.error(error);
}
});
});
Script is running properly(it updates the values as defined). But in parse log it shown as Failed with: success/error was not called. Please suggest me over this issue
You simply never call response.success() or response.error(), and you should always call at least one of those.
You should really be storing all of the promises returned from your queries and saves and waiting until all of them are complete and then calling success or error based on the result from those promises.

Json result returned as a file in Internet Explorer?

net MVC application, in which I have multiple charts. On these charts, I have applied filters and by clicking each filter, I do an ajax call which returns the result in Json and then applies to the charts.
Now its working perfectly in Firefox and Chrome, but in Internet Explorer - Ajax call is always unsuccessful. I tried hitting the web api url directly through my browser and the issue it seems is, the result json was being returned as a file to be downloaded.
This is my ajax code :
function getIssueResolvedGraphdata(control, departCode, departName) {
$.ajax(
{
type: "GET",
url: WebApiURL + "/api/home/GetQueryIssueResolvedData?deptCode=" + departCode,
dataType: "json",
crossDomain: true,
async: true,
cache: false,
success: function (myData) {
var resolvedStartDate = myData.data.IssueResolvedStartDate;
var issueData = myData.data.IssueData;
var resolveData = myData.data.ResolvedData;
//converting issueData into integer array...
var issue = issueData.replace("[", "");
var issue1 = issue.replace("]", "");
var issue2 = issue1.split(",");
for (var i = 0; i < issue2.length; i++) { issue2[i] = parseInt(issue2[i]); }
//converting resolvedData into integer array
var resolve = resolveData.replace("[", "");
var resolve1 = resolve.replace("]", "");
var resolve2 = resolve1.split(",");
for (var j = 0; j < resolve2.length; j++) { resolve2[j] = parseInt(resolve2[j]); }
//getting max value from array...
var issueMaxVal = Math.max.apply(null, issue2);
var resolveMaxVal = Math.max.apply(null, resolve2);
//Eliminating leading zeros in issue array
var removeIndex = 0;
var myDate;
var newDate;
var arrayLength;
if (issueMaxVal != 0) {
arrayLength = issue2.length;
for (var i = 0; i < arrayLength; i++) {
if (issue2[0] == 0) {
issue2.splice(0, 1);
removeIndex = i;
} else {
break;
}
}
//Getting days count of current month
var monthStart = new Date(new Date().getFullYear(), new Date().getMonth(), 1);
var monthEnd = new Date(new Date().getFullYear(), new Date().getMonth() + 1, 1);
var monthLength = (monthEnd - monthStart) / (1000 * 60 * 60 * 24);
var monthDays = 0;
if (monthLength == 28) {
monthDays = removeIndex;
}
else if (monthLength == 30) {
monthDays = removeIndex + 1;
}
else if (monthLength == 31 || monthLength == 29) {
monthDays = removeIndex + 2;
}
//matching the resultant issue array with resolve array & setting start date
var iDate = resolvedStartDate;
var tDate = '';
for (var i = 0; i < iDate.length; i++) {
if (iDate[i] == ',') {
tDate += '/';
}
else {
tDate += iDate[i];
}
}
if (removeIndex != 0) {
resolve2.splice(0, (removeIndex + 1));
var myDate = new Date(tDate);
myDate.setDate(myDate.getDate() + monthDays);
newDate = Date.UTC(myDate.getFullYear(), (myDate.getMonth() + 1), myDate.getDate());
} else {
var myDate = new Date(tDate);
newDate = Date.UTC(myDate.getFullYear(), (myDate.getMonth() + 1), myDate.getDate());
}
} else {
alert("Empty");
}
//updating chart here...
var chart = $('#performance-cart').highcharts();
chart.series[0].update({
pointStart: newDate,
data: issue2
});
chart.series[1].update({
pointStart: newDate,
data: resolve2
});
if (issueMaxVal > resolveMaxVal) {
chart.yAxis[0].setExtremes(0, issueMaxVal);
} else {
chart.yAxis[0].setExtremes(0, resolveMaxVal);
}
},
error: function (x, e) {
alert('There seems to be some problem while fetching records!');
} });}
Code from web api controller :
[HttpGet]
[CrossDomainActionFilter]
public Response<GraphIssueResolvedWrapper> GetQueryIssueResolvedData(string deptCode)
{
Response<GraphIssueResolvedWrapper> objResponse = new Response<GraphIssueResolvedWrapper>();
GraphIssueResolvedWrapper objGraphIssueResolvedWrapper = new GraphIssueResolvedWrapper();
try
{
....code.....
objResponse.isSuccess = true;
objResponse.errorDetail = string.Empty;
objResponse.data = objGraphIssueResolvedWrapper;
}
catch (Exception ex)
{
objResponse.isSuccess = false;
objResponse.errorDetail = ex.Message.ToString();
objResponse.data = null;
}
return objResponse;
}
Reponse Class :
public class Response<T>
{
public bool isSuccess { get; set; }
public string errorDetail { get; set; }
public T data { get; set; }
}
I am stuck at this for hours now. Any help will be appreciated.
I have solved my problem by using the following code : ( I guess it needed CORS support)
function isIE() {
var ua = window.navigator.userAgent;
var msie = ua.indexOf("MSIE");
if (msie > 0)
return true;
return false;
}
Then in document.ready function of my binding script :
$(document).ready(function () {
if (isIE())
$.support.cors = true;
});
Note : it still download Json stream as a file but now my AJAX call is successful upon each hit.
You've missed contentType: 'text/html' which is pretty important for IE7-8:
$.ajax(
{
type: "GET",
url: WebApiURL + "/api/home/GetQueryIssueResolvedData?deptCode=" + departCode,
dataType: "json",
contentType: 'text/html'
crossDomain: true,
async: true,
cache: false,
success: function (myData) {
var result = JSON.parse(myData);
///...code...
},
error: function (x, e) {
alert('There seems to be some problem while fetching records!');
}
}
);
To make it works in IE7-8 you also need to be sure that you've writing Conrent-Type Header into your response on server side. Add this line right before return statement;
response.Content.Headers.ContentType = new MediaTypeHeaderValue("text/html; charset=iso-8859-1");
And in code probably you will need to parse result in success method by using JSON.parse(myData);

How to know if all uploads completed within a loop?

I have a code that works well for sending multiple files via ajax with FormData and XMLHttpRequest;
for (var i=0, j=this.files.length; i<j; i++) {
file = this.files[i];
var formdata = new FormData();
formdata.append("images[]", file);
var xhr = new XMLHttpRequest(),
upload = xhr.upload,
id = Math.floor((Math.random() * 100000));
upload.addEventListener("loadstart", function(e){
showUploadedItem(file, this.id);
});
upload.id = id;
upload.onprogress = function(e) {
var done = e.position || e.loaded, total = e.totalSize || e.total;
)
};
upload.onload = function(e) {
if (this.status == 200) {
console.log('');
}
};
xhr.onreadystatechange = function(e) {
if ( 4 == this.readyState ) {
console.log('');
}
};
xhr.open('post', '<?php echo Yii::app()->createUrl('url') ?>', true);
xhr.send(formdata);
}
I am sending each file as a new XMLHttpRequest object inside the loop, so I do not know when I'm getting all requests ending.
Can anyone help?
Take a look at the documentation for XMLHttpRequest.
There are a couple of options that I can think of. You could use the "loadend" callback for each of them and increment a variable outside of the loop and check for the total amount of requests that were sent in each one. Once the count reaches the total number of requests, you could perform any logic or call a function that would want to call.
https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest?redirectlocale=en-US&redirectslug=DOM%2FXMLHttpRequest%2FUsing_XMLHttpRequest
Otherwise, setting the async parameter to false would work as well, but then you take a performance hit waiting for each one to finish before starting the others.
Based on your answer, my solution;
var x = 0;
var lenght = this.files.length;
for (var i=0, j=lenght; i<j; i++) {
// code here
var xhr = new XMLHttpRequest(),
// code here
xhr.onreadystatechange = function(e) {
if ( 4 == this.readyState && this.status == 200 ) {
x++;
if(x == lenght) {
window.setTimeout( function(){
alert('finish');
}, 1000 );
}
}
};
// code here
}
Though it is a trivial function, it works.

object parameters in Javascript

I'm having a bit of an issue with my javascript object. What I want to do is pass in an id and have it set a variable that is accessible to all of my functions.
Here's a small sample of what I have:
var myObject = function() {
var pageSize = 6;
var currentPage = 1;
var pagerPagesVisible = 5;
var pagerId = '#my-pager';
var entityId = '';
var doStuff = function() {
var endIndex = pageSize * currentPage;
var startIndex = endIndex - pageSize;
$.ajax({ type: "GET", url: "/items/" + this.entityId + "/entities/" + startIndex + "/" + pageSize + "/", dataType: "json", success: loadData, cache: false,
error: function(response, status, error) {
alert(response.responseText);
}
});
};
var loadData = function(data) {
var itemCount = data.length;
//build the html and write to the page
buildPager(itemCount);
};
var buildPager = function(itemCount) {
pager.build(pagerId, pageSize, itemCount, currentPage);
};
var attachEvents = function() {
//attach events to the pager
};
return {
init: function(entityId) {
this.entityId = entityId;
doStuff();
}
}
} ();
the issue is, in init, it sets the entityId instance that you see at the top. But when it hits doStuff() entityId is set back to ''.
You're mixing closure and object styles - you need to be consistent:
<script>
var myObject = function() {
var pageSize = 6;
var currentPage = 1;
var pagerPagesVisible = 5;
var pagerId = '#my-pager';
var entityId = '';
var doStuff = function() {
alert(entityId);
};
return {
init: function(myEntityId) {
entityId = myEntityId;
doStuff();
}
}
} ();
myObject.init(123);
</script>
Others have answered your question here, but I wanted to point out that you may want to use the prototype if you are going to be creating many of these objects.
When you enclose your methods you waste memory on every instantiation.
ClassName.prototype.methodname = function(){ ... }
That's because the entityId variable is local to the function and has nothing to do with the object you create at the end. Instead, put everything in that object at the end and not as locals in the function.
eg.
var myObject = function() {
var pageSize = 6;
var currentPage = 1;
var pagerPagesVisible = 5;
var pagerId = '#my-pager';
return {
doStuff: function() {
var endIndex = pageSize * currentPage;
var startIndex = endIndex - pageSize;
var self = this;
$.ajax( {
type: "GET",
url: "/items/" + this.entityId + "/entities/" + startIndex + "/" + pageSize,
dataType: "json",
success: function() { self.loadData(); },
cache: false,
error: function(response, status, error) {
alert(response.responseText);
}
} );
},
loadData: function(data) {
var itemCount = data.length;
this.buildPager(itemCount);
},
buildPager = function(itemCount) {
pager.build(pagerId, pageSize, itemCount, currentPage);
},
attachEvents: function() {
//attach events to the pager
},
entityId: '',
init: function(entityId) {
this.entityId = entityId;
this.doStuff();
}
};
}();

Resources