I have an ajax function that posts an image, which works perfectly in Chrome and Firefox. Safari and iOS Safari both balk at it, though.
I'm creating and appending the value like this:
var ajaxImage = new FormData();
ajaxImage.append('file-0', $('.some-file-input')[0].files[0]);
I then call this image later, using ajaxImage.entries() to init the iterator for the FormData object, so that I can perform a validation on it. However, in Safari ajaxImage.entries() throws an entries is not a function TypeError.
I guess I could just do the validation before getting to this point as a workaround, but now it's bugging me so I wanted to see if anyone could shed some light on this.
Thanks!
Unfortunately, Safari doesn't support this part of the specification: https://developer.mozilla.org/en-US/docs/Web/API/FormData#Browser_compatibility, specifically the entries method.
I haven't tried it myself, but perhaps a polyfill like this one: https://github.com/francois2metz/html5-formdata might work?
But yes, you might be right -- doing validation before that point might be worth it.
I solved this by conditionally (if Safari is the browser) iterating through the elements property of the form. For all other browser, my wrapper just iterates through FormData entries(). The end result of my function, in either case, is a simple javascript object (JSON) which amounts to name/value pairs. That object can be passed directly to the data property of the JQuery ajax function (with contentType and processData not specified).
function FormDataNameValuePairs(FormName)
{
var FormDaytaObject={};
var FormElement=$('#'+FormName).get(0);
if (IsSafariBrowser())
{
var FormElementCollection=FormElement.elements;
//console.log('namedItem='+FormElementCollection.namedItem('KEY'));
var JQEle,EleType;
for (ele=0; (ele < FormElementCollection.length); ele++)
{
JQEle=$(FormElementCollection.item(ele));
EleType=JQEle.attr('type');
// https://github.com/jimmywarting/FormData/blob/master/FormData.js
if ((! JQEle.attr('name')) ||
(((EleType == 'checkbox') || (EleType == 'radio')) &&
(! JQEle.prop('checked'))))
continue;
FormDaytaObject[JQEle.attr('name')]=JQEle.val();
}
}
else
{
var FormDayta=new FormData(FormElement);
for (var fld of FormDayta.entries())
FormDaytaObject[fld[0]]=fld[1];
}
return FormDaytaObject;
}
where IsSafariBrowser() is implemented by whatever your favorite method is, but I chose this:
function IsSafariBrowser()
{
var VendorName=window.navigator.vendor;
return ((VendorName.indexOf('Apple') > -1) &&
(window.navigator.userAgent.indexOf('Safari') > -1));
}
Example usage with an ajax call:
var FormDaytaObject=FormDataNameValuePairs('FiltersForm');
$.ajax({url: 'AJAXDoSomethingWithFilters/',
method: 'POST',
data: FormDaytaObject,
dataType: 'text',
success: function(data)
{
console.log('AJAXDoSomethingWithFilters success:'+data);
},
error: function(JQXhr,Status,Err)
{
console.log('AJAXDoSomethingWithFilters error:'+Err);
}
});
Related
I am having a problem in my ajax or i don't know if it is a problem with ajax. I have an ajax code to get a value from label and concat it in my fresh data from database. Everytime i refresh the page, it outputs different. Sometimes it works fine, and sometimes it doesn't.
I am having my trouble in this part :
else {
value = value + "-"+init;
$('#checkID').text(value);
$("#checkID").css('visibility','visible');
}
sometimes it outputs 1-0 and sometimes the output became -0.
I am thinking of var value = $('#clinicID').html(); cannot concat with my -0 where the 1 of the output 1-0 is came from value variable
Here is my ajax full code :
function getcheckupID() {
var init = 0;
var value = $('#clinicID').html();
$.ajax ({
url: siteurl+"myclinic/getcheckID",
type: "GET",
dataType: "JSON",
success: function(data) {
if(data.length>0) {
$('#checkID').text(data[0]['check_up_id']);
$("#checkID").css('visibility','visible');
}
else {
value = value + "-"+init;
$('#checkID').text(value);
$("#checkID").css('visibility','visible');
}
}
})
}
my document ready code:
$(document).ready(function() {
get_clinicID();
show_patients();
checkupme();
});
where checkupme() function got a nested getcheckupID() runtime
I suggested another way to get data in #clinicID that you can use
When you refresh the page, insert your #clinicID like:
<span id="clinicID" data-value="1-0"><span> or whatever data you wanna input.
Then in getcheckupID function you'll call:
function getcheckupID() {
var init = 0;
var value = $('#clinicID').attr("data-value");
// Your code ajax
}
If it still have problem, please check your echo when page generated. Maybe there're not any value to print.
Hope this help.
In Backbone, I need to check if a model record already exists. Right now, I am doing it by fetching the model by id, and seeing if its "created_at" attribute is undefined. This feels brittle to me. Does anyone have any better recommendations?
var dealProgram = new WhiteDeals.Models.DealProgram({id: servant_id});
dealProgram.fetch({
success: function() {
var program = dealProgram.toJSON();
var datecheck = program.created_at
if(typeof datecheck === 'undefined'){
dealPrograms.create({
title: "",
servant_id: servant.servant_id,
servant_name: servant.name,
servant_master: servant.master
},
{
success: function () {
self.manageServants(servants);
}
}); // End of dealPrograms.create
} else if (datecheck !== undefined) {
console.log("is defined, success!")
self.manageServants(servants);
}; // End of if statement for non-existant dealPrograms
} // End of success
}); // End of dealProgram.fetch
You'll obviously have to check by using a request (whatever the form of the request, you'll have a low amount of data anyway). Guess you should still wonder if it wouldn't be worth fetching all your models at once in a collection so you can make the check client-side (or only the id if it'd be too big to fetch everything).
I'm making a fairly complex HTML 5 + Javascript game. The client is going to have to download images and data at different points of the game depending on the area they are at. I'm having a huge problem resolving some issues with the Data Layer portion of the Javascript architecture.
The problems I need to solve with the Data Layer:
Data used in the application that becomes outdated needs to be automatically updated whenever calls are made to the server that retrieve fresh data.
Data retrieved from the server should be stored locally to reduce any overhead that would come from requesting the same data twice.
Any portion of the code that needs access to data should be able to retrieve it easily and in a uniform way regardless of whether the data is available locally already.
What I've tried to do to accomplish this is build a data layer that has two main components:
1. The portion of the layer that gives access to the data (through get* methods)
2. The portion of the layer that stores and synchronizes local data with data from the server.
The workflow is as follows:
When the game needs access to some data it calls get* method in the data layer for that data, passing a callback function.
bs.data.getInventory({ teamId: this.refTeam.PartyId, callback: this.inventories.initialize.bind(this.inventories) });
The get* method determines whether the data is already available locally. If so it either returns the data directly (if no callback was specified) or calls the callback function passing it the data.
If the data is not available, it stores the callback method locally (setupListener) and makes a call to the communication object passing the originally requested information along.
getInventory: function (obj) {
if ((obj.teamId && !this.teamInventory[obj.teamId]) || obj.refresh) {
this.setupListener(this.inventoryNotifier, obj);
bs.com.getInventory({ teamId: obj.teamId });
}
else if (typeof (obj.callback) === "function") {
if (obj.teamId) {
obj.callback(this.team[obj.teamId].InventoryList);
}
}
else {
if (obj.teamId) {
return this.team[obj.teamId].InventoryList;
}
}
}
The communication object then makes an ajax call to the server and waits for the data to return.
When the data is returned a call is made to the data layer again asking it to publish the retrieved data.
getInventory: function (obj) {
if (obj.teamId) {
this.doAjaxCall({ orig: obj, url: "/Item/GetTeamEquipment/" + obj.teamId, event: "inventoryRefreshed" });
}
},
doAjaxCall: function (obj) {
var that = this;
if (!this.inprocess[obj.url + obj.data]) {
this.inprocess[obj.url + obj.data] = true;
$.ajax({
type: obj.type || "GET",
contentType: "application/json; charset=utf-8",
dataType: "json",
data: obj.data,
url: obj.url,
async: true,
success: function (data) {
try {
ig.fire(bs.com, obj.event, { data: data, orig: obj.orig });
}
catch (ex) {
// this enables ajaxComplete to fire
ig.log(ex.message + '\n' + ex.stack);
}
finally {
that.inprocess[obj.url + obj.data] = false;
}
},
error: function () { that.inprocess[obj.url + obj.data] = false; }
});
}
}
The data layer then stores all of the data in a local object and finally calls the original callback function, passing it the requested data.
publishInventory: function (data) {
if (!this.inventory) this.inventory = {};
for (var i = 0; i < data.data.length; i++) {
if (this.inventory[data.data[i].Id]) {
this.preservingUpdate(this.inventory[data.data[i].Id], data.data[i]);
}
else {
this.inventory[data.data[i].Id] = data.data[i];
}
}
// if we pulled this inventory for a team, update the team
// with the inventory
if (data.orig.teamId && this.team[data.orig.teamId]) {
this.teamInventory[data.orig.teamId] = true;
this.team[data.orig.teamId].InventoryList = [];
for (var i = 0; i < data.data.length; i++) {
this.team[data.orig.teamId].InventoryList.push(data.data[i]);
}
}
// set up the data we'll notify with
var notifyData = [];
for (var i = 0; i < data.data.length; i++) {
notifyData.push(this.inventory[data.data[i].Id]);
}
ig.fire(this.inventoryNotifier, "refresh", notifyData, null, true);
}
There are several problems with this that bother me constantly. I'll list them in order of most annoying :).
Anytime I have to add a call that goes through this process it takes too much time to do so. (at least an hour)
The amount of jumping and callback passing gets confusing and seems very prone to errors.
The hierarchical way in which I am storing the data is incredibly difficult to synchronize and manage. More on that next.
Regarding issue #3 above, if I have objects in the data layer that are being stored that have a structure that looks like this:
this.Account = {Battles[{ Teams: [{ TeamId: 392, Characters: [{}] }] }]}
this.Teams[392] = {Characters: [{}]}
Because I want to store Teams in a way where I can pass the TeamId to retrieve the data (e.g. return Teams[392];) but I also want to store the teams in relation to the Battles in which they exist (this.Account.Battles[0].Teams[0]); I have a nightmare of a time keeping each instance of the same team fresh and maintaining the same object identity (so I am not actually storing it twice and so that my data will automatically update wherever it is being used which is objective #1 of the data layer).
It just seems so messy and jumbled.
I really appreciate any help.
Thanks
You should consider using jquery's deferred objects.
Example:
var deferredObject = $.Deferred();
$.ajax({
...
success: function(data){
deferredObject.resolve(data);
}
});
return deferredObject;
Now with the deferredObject returned, you can attach callbacks to it like this:
var inventoryDfd = getInventory();
$.when(inventoryDfd).done(function(){
// code that needs data to continue
}
and you're probably less prone to errors. You can even nest deferred objects, or combine them so that a callback isn't called until multiple server calls are downloaded.
+1 for Backbone -- it does some great heavy lifting for you.
Also look at the Memoizer in Douglas Crockford's book Javascript the Good Parts. It's dense, but awesome. I hacked it up to make the memo data store optional, and added more things like the ability to set a value without having to query first -- e.g. to handle data freshness.
i have been trying to figure this out for the past couple hours and was hoping someone here could help out. I am using JQuery 1.6.4 to make an ajax call when a button is clicked and populate the contents of a table with the results. The code works as it should in all browsers except IE. When i run it in IE, some values are populated and the rest are not, very strange!
When i run the script and use IE's debugging tool i get the following error;
Unexpected call to method or property access (line 3)
Does anyone know what i'm doing wrong? Here is my code that runs the ajax;
$(document).ready(function(){
$("#find").click(function () {
//Set kinase
var kinaseEntry = $("#kinaseEntry").val();
var dataString = "kinaseEntry=" + kinaseEntry;
//Fetch list from database
$.ajax({
type : "GET",
url : "http://www.webaddress/php/post.php",
datatype: "json",
data: dataString,
success : function(datas) {
//SET VARIABLES TO BE USED THROUGHOUT PAGE
var kinaseName = (datas.skuName);
var molecularWeight = (datas.molecularWeight);
var kinaseConc = (datas.kinaseConc);
var anti1Name = (datas.antiName);
var anti2Name = (datas.antiName2);
var antiConc = (datas.antiConc);
var antiConc2 = (datas.antiConc2);
var tracerName = (datas.tracerName);
var tracerConc = (datas.tracerConc);
var tracerStockConc = (datas.tracerStockConc);
var tracerSku = (datas.tracerSku);
var kinaseSku = (datas.kinaseSku);
var antiSku = (datas.antiSku);
var antiSku2 = (datas.antiSku2);
var bufferName = (datas.bufferName);
var bufferSku = (datas.bufferSku);
//REAGENT NAMES
$(".kinaseName").html(kinaseName + " (" + molecularWeight + " kDa)");
$(".anti1Name").html(anti1Name);
$(".anti2Name").html(anti2Name);
$(".tracerName").html(tracerName);
$(".bufferName").html(bufferName);
//DEFAULT VALUES
$(".defaultKinaseConc").html(kinaseConc);
$(".defaultAntiConc").html(antiConc);
$(".defaultAnti2Conc").html(antiConc2);
$(".defaultTracerConc").html(tracerConc);
$("#molecularWeight").val(molecularWeight);
$("#tracerStockConc").val(tracerStockConc);
//INSERT DEFAULTS INTO INPUT
$("#userKinaseConc").val(kinaseConc);
$("#userAntibodyConc1").val(antiConc);
$("#userAntibodyConc2").val(antiConc2);
$("#userTracerConc").val(tracerConc);
},
error : function (XMLHttpRequest, textStatus, errorThrown) {
console.log("error :"+XMLHttpRequest.responseText);
}
});
return false;
}); });
The names populate fine and the first default value gets populated, but the rest breaks. Any help would be greatly appreciated.
Here are the results of my console.log();
antiConc
"2"
antiConc2
"2"
antiName
"Biotin-anti-His"
antiName2
"Eu-Streptavidin"
antiSku
"PV6089"
antiSku2
"PV5899"
bufferName
"Kinase Buffer A"
bufferSku
"PV3189"
cleanSKU
null
kinaseConc
"5"
kinaseSku
"P3049"
molecularWeight
"125.4"
skuName
"ABL1"
tracerConc
"100"
tracerName
"Kinase Tracer 1710"
tracerSku
"PV6088"
tracerStockConc
"25"
Are you sure it's working properly in other browsers, or are they just not breaking as significantly.
I'm guessing you have mixed updates happening here (a distinction presumed from val() and html() use). I notice a pattern whereby elements retrieved by id (e.g., #userKinaseConc) and those retrieved by class (e.g., .kinaseName) are using val() and html() respectively. However, #defAntiCon breaks that pattern. You're using html() for this element. Is this element an input or other form field? Should this be val()?
The experience you describe can be re-created by attempting to apply a value to an input field via html() setter rather than val(), with the exception that it still doesn't work for that specific field in all values... browsers other than IE just fail differently and the error becomes non-breaking. In IE, it will break execution. Is #defAntiCon actually being populated based on data returned in other browsers?
IE8 Is strict about HTML insertion. If your markup is invalid, or either have HTML5 specific tags, it will throw an error.
I have no real solution, but I'd follow this steps to make it works.
Make sure your datas contains valid HTML, make sure you have no extra closing tags or syntax error (you can use a validator if needed)
If you are using HTML5 tags, you could try to use html5shiv to make sure the browser will understand all the tags
Make sur you don't use .val() instead of .html() in some cases
You should replace .html(datas.foo) by .text(datas.foo) since you are passing string to the method.
In case you don't find any solutions, you could add a catch block in jQuery resolveWith method (referring to your comment) by doing the following changes :
replace this :
resolveWith: function ( context, args ) {
if ( !cancelled && !fired && !firing ) {
// make sure args are available (#8421)
args = args || []; firing = 1;
try {
while ( callbacks[ 0 ] ) { callbacks.shift().apply( context, args ); }
} finally {
fired = [ context, args ];
firing = 0;
}
}
return this ;
},
with this :
resolveWith: function ( context, args ) {
if ( !cancelled && !fired && !firing ) {
// make sure args are available (#8421)
args = args || []; firing = 1;
try {
while ( callbacks[ 0 ] ) { callbacks.shift().apply( context, args ); }
} catch (err) {
} finally {
fired = [ context, args ];
firing = 0;
}
}
return this ;
},
Bug on the try-finally in IE is reported here
Hope this helps.
Edit : As #Josh mentionned in the comment, the bug has been reported and resolved in this commit for jQuery 1.7.x. A simple update of your jQuery should works.
This is driving me nuts!
I'm getting some JSON from my server:
{"id262":{"done":null,"status":null,"verfall":null,"id":262,"bid":20044,"art":"owner","uid":"demo02","aktion":null,"termin_datum":null,"docid":null,"gruppenid":null,"news":"newsstring","datum":"11.06.2010","header":"headerstring","for_uid":"demo01"},
"id263":{"done":null,"status":"pending","verfall":null,"bid":20044,"id":263,"uid":"demo02","art":"foo","aktion":"dosomething","termin_datum":"11.06.2010","docid":null,"gruppenid":null,"datum":"11.06.2010","news":"newsstring","for_uid":"demo01","header":"headerstring"},
"id261":{"done":null,"status":null,"verfall":null,"id":261,"bid":20044,"art":"termin","uid":"demo02","aktion":null,"termin_datum":"25.06.2010","docid":null,"gruppenid":null,"news":"newsstring","datum":"11.06.2010","header":"headerstring","for_uid":null}}
This is how my JS looks like:
var user = 'demo02';
new Ajax.Request('myscript.pl?someparameter=value', { method:'get',
onSuccess: function(transport){
var db_json = transport.responseText.evalJSON(),
propCount = 0,
someArray1 = [],
someArray2 = [],
otherArray = [];
//JSON DEBUG
console.log('validated string:');
console.log(transport.responseText.evalJSON(true));
for(var prop in db_json) {
propCount++;
if ( (db_json[prop].art == 'foo') && (db_json[prop].for_uid == user) ) {
someArray1.push(db_json[prop]);
} else if( (db_json[prop].art == 'foo') && (db_json[prop].uid == user) ) {
someArray2.push(db_json[prop]);
} else if( db_json[prop].art == 'log' ) {
otherArray.push(db_json[prop]);
}
}
if(someArray1.length>0) {
someArray1.map(function(el){
$('someArray1target').innerHTML += el.done;
//do more stuff
});
}
if(someArray2.length>0) {
someArray2.map(function(el){
$('someArray2target').innerHTML += el.done;
//do more stuff
});
}
});
Sometimes, it works perfectly.
Sometimes, i get my JSON String (it appears in Firebug's "answer"-tab), but it won't log the JSON in console-log(). I'm not getting any errors and javascript is still working.
Next time after reloading, it might work, but it might not.
I cannot remotely imagine why this only happens sometimes!
You are calling evalJSON twice, actually with different parameters each time.
Normally, I wouldn't expect this to have any side-effects, and indeed the prototype documentations for this method don't mention any. However, I remember that earlier versions of firebug were known to manipulate the XMLHttpRequest in weird ways (in order to capture the data going in and out), so maybe this is still relevant today.
Try changing the log statement to this instead:
console.log(db_json);
I found the answer. It makes me want to slam my head. My $('someArray1target') div sometimes was not loaded yet.
I was so focused in finding something weird in my JSON instead of searching for the more obvious, "standard" errors.