jquery script works only on firefox - javascript

After 2 weeks of hard work on my first, simple site/database I'm stuck. Friend of mine helped me on adding jquery, but now it works only in Mozilla, and he dont have idea why. I dont know java at all (and barely php). Can you take a look?
Chrome console point an error at
Uncaught SyntaxError: Unexpected token =
at line 49 which is
self.dataAdapter = function(id = 0, imie = '', nazwisko = '', kredyt = 0)
Do you have any idea what is the most compatible syntax?
The whole script:
$(document).ready(function()
{
sui = new swiezakUI();
sui.getData();
});
function swiezakUI()
{
var self = this;
self.scriptURL = "/data.php";
self.send = function(key, stuff)
{
var post = {};
post[key] = JSON.stringify(stuff);
$.ajax({
type: "POST",
url: self.scriptURL,
data: post,
contentType: "application/x-www-form-urlencoded",
dataType: "json",
success: function(data)
{
self.getData();
self.cleanForm();
},
failure: function(errMsg)
{
alert('fail');
},
error: function(errMsg)
{
alert("Blad \n" + errMsg.responseText);
}
});
}
self.id2Id = function(id)
{
for(var i = 0; i < self.myData.length; i++)
{
if(id == self.myData[i].id)
return i;
}
}
self.dataAdapter = function(id = 0, imie = '', nazwisko = '', kredyt = 0)
{
var data = new Object();
data.id = id;
data.imie = imie;
data.nazwisko = nazwisko;
data.kredyt = kredyt;
return data;
}
self.dodajNowy = function()
{
return function()
{
var data = self.dataAdapter(null, $('#imie').val(), $('#nazwisko').val(), $('#kredyt').val().replace(/\D+/g,""));
self.send('nowy',data);
}
}
self.edytujWpis = function(id)
{
return function()
{
var data = self.dataAdapter(id, $('#imie').val(), $('#nazwisko').val(), $('#kredyt').val().replace(/\D+/g,""));
self.send('edycja',data);
}
}
self.kasujWpis = function(id)
{
return function()
{
var data = self.dataAdapter(id);
self.send('kasuj',data);
}
}
self.cleanForm = function()
{
$('#imie').val('');
$('#nazwisko').val('');
$('#kredyt').val('');
$('#bZapisz').unbind();
$('#bZapisz').click(self.dodajNowy());
}
self.editButtons = function()
{
$('.edit').click(function()
{
var did = $(this).attr('id').replace(/\D+/g,"");
id = self.id2Id(did);
$('#imie').val(self.myData[id].imie);
$('#nazwisko').val(self.myData[id].nazwisko);
$('#kredyt').val(self.myData[id].kredyt);
$('#bZapisz').unbind();
$('#bZapisz').click(self.edytujWpis(did));
});
}
self.delButtons = function()
{
$('.delete').click(function()
{
var id = $(this).attr('id').replace(/\D+/g,"");
console.log(id);
self.kasujWpis(id)();
});
}
$('#bZapisz').click(self.dodajNowy());
$('#bCzysc').click(function(){
self.cleanForm();
});
self.getData = function()
{
$('#lista').children('table').html("<tr><th>id</th><th>imie</th><th>nazwisko</th><th>kredyt</th>"+
"<th>edycja</th><th>usun</th></tr>");
$.getJSON(self.scriptURL, function(data)
{
console.log(data);
self.myData = data;
for(var i = 0; i < data.length; i++)
{
$('#lista').children('table').append(
'<tr><td>'+ data[i].id +'</td>'+
'<td>'+ data[i].imie +'</td>'+
'<td>'+ data[i].nazwisko +'</td>'+
'<td>'+ data[i].kredyt +'</td>'+
'<td><button class="edit" id="e#'+data[i].id+'">e</button></td>'+
'<td><button class="delete" id="d#'+data[i].id+'">d</button></td></tr>');
}
self.editButtons();
self.delButtons();
});
}
}

Default parameters are currently part of the ES6 draft. This feature is not part of the most recent final ECMAScript standard (5.1), hence browser support is currently minimal. As of this writing, only Firefox (experimentally) implements default parameters.
There are many ways to simulate default parameters. An alternative to ES6's default parameters would be comparing arg === undefined to set the default value for it:
//if the kredyt argument has not been passed or is undefined
if (kredyt === undefined) {
kredyt = 0;
}
When a function is called passing less arguments than its parameters count, the parameters without corresponding arguments are initialized to undefined.
This way, not passing a value for the argument as well as explicitly passing undefined as the argument value will use the default parameter value, the same behavior as ES6's default parameters.
So here's the complete example:
self.dataAdapter = function(id, imie, nazwisko, kredyt)
{
//default parameters
if (id === undefined) {
id = 0;
}
if (imie === undefined) {
imie = '';
}
if (nazwisko === undefined) {
nazwisko = '';
}
if (kredyt === undefined) {
kredyt = 0;
}
//function code
var data = new Object();
data.id = id;
data.imie = imie;
data.nazwisko = nazwisko;
data.kredyt = kredyt;
return data;
}
Another common approach is comparing arg == null, which has the same effect but also accepts passing null to use the default parameter value:
//if kredyt is null, undefined or not passed
if (kredyt == null) {
kredyt = 0;
}
This works because == does type coercion, and null coerces to, and only to, undefined (ES5#11.9.3).
Yet another common approach is to use the || as the "default operator" (see related question):
kredyt = kredyt || 0; //in the beginning of the function
//...
data.kredyt = kredyt;
Or if the parameter is used only in a single place, it is possible to inline it as well:
data.kredyt = kredyt || 0;
The benefit is basically shorter code, but note that it will use the default parameter value not only when the argument is undefined, but also null, false, 0, empty string or NaN. Hence this is not a viable approach when one of these values is an acceptable parameter value different from its default parameter value.
Lastly, for use cases that need to differentiate a null/undefined value from a not passed argument (which is rare and not the case here), it's possible to check the arguments object's length property:
if (arguments.length < 4) {
kredyt = 0;
}

Related

What does jQuery's $.each with three arguments do, and how can I translate it to pure JS?

I'm trying to remove JQuery from a project I inherited and I have stumbled upon this line of code which doesn't really make sense.
$.each(options.reservationOptions,this._addToSelect, [select]);
What does $.each() do when there are 3 things passed to it.
The first is an object, the second is a function, and the third is a var.
Here is the [select] init:
var select = L.DomUtil.create('select', 'booking-select ' + options.RoomName, reservationContainer);
Here is the function:
_addToSelect: function (select) {
try {
var value = this.value;
var text = this.text;
if (text) {
var option = $("<option>").addClass('booking-option').text(text);
//var option = L.DomUtil.create('option', 'booking-option');
//option.innerText = text;
if ( value )
option.val(value);
//option.value = value;
option.appendTo(select);
//select.appendChild(option.get());
//var optionsList = select.options || select;
//optionsList.add(option.get());
}
} catch (ex) {
console.log('could not add option to select ' + ex.message);
}
It iterates, the first argument is the array or object, the second is the callback, and the third is the arguments passed in to the callback. In a loop you'd do the same thing with (assuming array)
options.reservationOptions.forEach(function(item) {
this._addToSelect.apply(item, [select]);
}.bind(this));
Here's a short version of what jQuery does
$.each = function (obj, callback, args) {
var value,
i = 0,
length = obj.length,
isArray = isArraylike(obj);
if (args) {
if (isArray) {
for (; i < length; i++) {
value = callback.apply(obj[i], args);
if (value === false) {
break;
}
}
} else {
for (i in obj) {
value = callback.apply(obj[i], args);
if (value === false) {
break;
}
}
}
}
}
forEach takes 2 arguments, callback and context – https://developer.mozilla.org/pl/docs/Web/JavaScript/Referencje/Obiekty/Array/forEach
options.reservationOptions.forEach(function(option) {
this.options.reservationOptions(option);
}, this);

Get object caller name by function call JavaScript

I'm writing a piece of code to easily save error logs in an object for debugging.
What I'm trying to achieve is to get the Object name from the function it was called from like so:
var MainObject = {
test : function() {
return MainObject.test.caller;
// When called from MainObject.testcaller,
// it should return MainObject.testcaller.
},
testcaller : function() {
return MainObject.test(); // Should return MainObject.testcaller, Returns own function code.
},
anothercaller : function() {
return MainObject.test(); // Should return MainObject.anothercaller, Returns own function code.
}
}
However when I run this code it returns the function code from MainObject.testcaller.
JSFiddle example
Is there any way this is possible?
Update
After looking at Rhumborl's answer, I discovered that assigning the value through another function would lead it to point back at the function name without the object itself.
Code:
(function (name, func) {
MainObject[name] = func;
})('invalid', function() {
return MainObject.test("blah");
});
// This now points at invalid() rather than MainObject.invalid()
Updated fiddle
There is a non–standard caller property of functions that returns the caller function, however that is a pointer to a function object and doesn't tell you the object it was called as a method of, or the object's name. You can get a reference to the function through arguments.callee.
There is also the obsolete arguments.caller, but don't use that. It also provides a reference to the calling function (where supported).
Once you have a reference to the calling function (if there is one), you then have the issue of resolving its name. Given that Functions are Objects, and objects can be referenced by multiple properties and variables, the concept of a function having a particular name is alluvial.
However, if you know that the function is a property of some object, you can iterate over the object's own enumerable properties to find out which one it is.
But that seems to be a rather odd thing to do. What are you actually trying to do? You may be trying to solve a problem that can be worked around in a much more robust and simpler way.
Edit
You can do what you want in a very limited way using the method described above for the case in the OP, however it is not robust or a general solution:
var mainObject = {
test : function() {
var obj = this;
var caller = arguments.callee.caller;
var global = (function(){return this}());
var fnName, objName;
for (var p in global) {
if (global[p] === obj) {
objName = p;
}
}
for (var f in obj) {
if (obj[f] === caller) {
fnName = f;
}
}
return objName + '.' + fnName;
},
testcaller : function() {
return mainObject.test();
},
anothercaller : function() {
return mainObject.test();
}
}
console.log(mainObject.testcaller()); // mainObject.testcaller
console.log(mainObject.anothercaller()); // mainObject.anothercaller
but it's brittle:
var a = mainObject.anothercaller;
console.log(a()); // mainObject.anothercaller
var b = {
foo : mainObject.anothercaller
}
console.log(b.foo()); // mainObject.anothercaller
Oops.
You can use this trick at http://www.eriwen.com/javascript/js-stack-trace/ which throws an error, then parses the stack trace.
I have updated it for the latest versions of Firefox, Chrome and IE. Unfortunately it doesn't work well on my IE9 (and I haven't tested it on Opera).
function getStackTrace() {
var callstack = [];
var isCallstackPopulated = false;
try {
i.dont.exist += 0; //doesn't exist- that's the point
} catch (e) {
if (e.stack) { //Firefox/Chrome/IE11
var lines = e.stack.split('\n');
for (var i = 0, len = lines.length; i < len; i++) {
var line = lines[i].trim();
if (line.match(/^at [A-Za-z0-9\.\-_\$]+\s*\(/)) {
// Chrome/IE: " at Object.MainObject.testcaller (url:line:char)"
var entry = line.substring(3, line.indexOf('(') - 1);
// Chrome appends "Object." to the front of the object functions, so strip it off
if (entry.indexOf("Object.") == 0) {
entry = entry.substr(7, entry.length);
}
callstack.push(entry);
} else if (line.match(/^[A-Za-z0-9\.\-_\$]+\s*#/)) {
// Firefox: "MainObject.testcaller#url:line:char"
callstack.push(line.substring(0, lines[i].indexOf('#')));
}
}
//Remove call to getStackTrace()
callstack.shift();
isCallstackPopulated = true;
} else if (window.opera && e.message) { //Opera
var lines = e.message.split('\n');
for (var i = 0, len = lines.length; i < len; i++) {
if (lines[i].match(/^\s*[A-Za-z0-9\-_\$]+\(/)) {
var entry = lines[i];
//Append next line also since it has the file info
if (lines[i + 1]) {
entry += lines[i + 1];
i++;
}
callstack.push(entry);
}
}
//Remove call to getStackTrace()
callstack.shift();
isCallstackPopulated = true;
}
}
if (!isCallstackPopulated) { //IE9 and Safari
var currentFunction = arguments.callee.caller;
while (currentFunction) {
var fn = currentFunction.toString();
var fname = fn.substring(fn.indexOf("function") + 8, fn.indexOf('')) || 'anonymous';
callstack.push(fname);
currentFunction = currentFunction.caller;
}
}
return callstack;
}
var MainObject = {
test: function (x) {
// first entry is the current function (test), second entry is the caller
var stackTrace = getStackTrace();
var caller = stackTrace[1];
return caller + "()";
},
testcaller: function () {
return MainObject.test(1, null);
}
}
function SomeFunction() {
return MainObject.test("blah");
}
document.body.innerHTML += '<b style="color: red">' + MainObject.testcaller() + '</b>';
document.body.innerHTML += '<div>Calling SomeFunction() returns: <b style="color: red">' + SomeFunction() + '</b></div>';
MainObject.test() should return: <b style="color: blue">MainObject.testcaller()</b>
<hr />
MainObject.test() returns:
Updated fiddle here

Mutable variable is accessible from closure. How can I fix this?

I am using Typeahead by twitter. I am running into this warning from Intellij. This is causing the "window.location.href" for each link to be the last item in my list of items.
How can I fix my code?
Below is my code:
AutoSuggest.prototype.config = function () {
var me = this;
var comp, options;
var gotoUrl = "/{0}/{1}";
var imgurl = '<img src="/icon/{0}.gif"/>';
var target;
for (var i = 0; i < me.targets.length; i++) {
target = me.targets[i];
if ($("#" + target.inputId).length != 0) {
options = {
source: function (query, process) { // where to get the data
process(me.results);
},
// set max results to display
items: 10,
matcher: function (item) { // how to make sure the result select is correct/matching
// we check the query against the ticker then the company name
comp = me.map[item];
var symbol = comp.s.toLowerCase();
return (this.query.trim().toLowerCase() == symbol.substring(0, 1) ||
comp.c.toLowerCase().indexOf(this.query.trim().toLowerCase()) != -1);
},
highlighter: function (item) { // how to show the data
comp = me.map[item];
if (typeof comp === 'undefined') {
return "<span>No Match Found.</span>";
}
if (comp.t == 0) {
imgurl = comp.v;
} else if (comp.t == -1) {
imgurl = me.format(imgurl, "empty");
} else {
imgurl = me.format(imgurl, comp.t);
}
return "\n<span id='compVenue'>" + imgurl + "</span>" +
"\n<span id='compSymbol'><b>" + comp.s + "</b></span>" +
"\n<span id='compName'>" + comp.c + "</span>";
},
sorter: function (items) { // sort our results
if (items.length == 0) {
items.push(Object());
}
return items;
},
// the problem starts here when i start using target inside the functions
updater: function (item) { // what to do when item is selected
comp = me.map[item];
if (typeof comp === 'undefined') {
return this.query;
}
window.location.href = me.format(gotoUrl, comp.s, target.destination);
return item;
}
};
$("#" + target.inputId).typeahead(options);
// lastly, set up the functions for the buttons
$("#" + target.buttonId).click(function () {
window.location.href = me.format(gotoUrl, $("#" + target.inputId).val(), target.destination);
});
}
}
};
With #cdhowie's help, some more code:
i will update the updater and also the href for the click()
updater: (function (inner_target) { // what to do when item is selected
return function (item) {
comp = me.map[item];
if (typeof comp === 'undefined') {
return this.query;
}
window.location.href = me.format(gotoUrl, comp.s, inner_target.destination);
return item;
}}(target))};
I liked the paragraph Closures Inside Loops from Javascript Garden
It explains three ways of doing it.
The wrong way of using a closure inside a loop
for(var i = 0; i < 10; i++) {
setTimeout(function() {
console.log(i);
}, 1000);
}
Solution 1 with anonymous wrapper
for(var i = 0; i < 10; i++) {
(function(e) {
setTimeout(function() {
console.log(e);
}, 1000);
})(i);
}
Solution 2 - returning a function from a closure
for(var i = 0; i < 10; i++) {
setTimeout((function(e) {
return function() {
console.log(e);
}
})(i), 1000)
}
Solution 3, my favorite, where I think I finally understood bind - yaay! bind FTW!
for(var i = 0; i < 10; i++) {
setTimeout(console.log.bind(console, i), 1000);
}
I highly recommend Javascript garden - it showed me this and many more Javascript quirks (and made me like JS even more).
p.s. if your brain didn't melt you haven't had enough Javascript that day.
You need to nest two functions here, creating a new closure that captures the value of the variable (instead of the variable itself) at the moment the closure is created. You can do this using arguments to an immediately-invoked outer function. Replace this expression:
function (item) { // what to do when item is selected
comp = me.map[item];
if (typeof comp === 'undefined') {
return this.query;
}
window.location.href = me.format(gotoUrl, comp.s, target.destination);
return item;
}
With this:
(function (inner_target) {
return function (item) { // what to do when item is selected
comp = me.map[item];
if (typeof comp === 'undefined') {
return this.query;
}
window.location.href = me.format(gotoUrl, comp.s, inner_target.destination);
return item;
}
}(target))
Note that we pass target into the outer function, which becomes the argument inner_target, effectively capturing the value of target at the moment the outer function is called. The outer function returns an inner function, which uses inner_target instead of target, and inner_target will not change.
(Note that you can rename inner_target to target and you will be okay -- the closest target will be used, which would be the function parameter. However, having two variables with the same name in such a tight scope could be very confusing and so I have named them differently in my example so that you can see what's going on.)
In ecmascript 6 we have new opportunities.
The let statement declares a block scope local variable, optionally initializing it to a value.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let
Since the only scoping that JavaScript has is function scope, you can simply move the closure to an external function, outside of the scope you're in.
Just to clarify on #BogdanRuzhitskiy answer (as I couldn't figure out how to add the code in a comment), the idea with using let is to create a local variable inside the for block:
for(var i = 0; i < 10; i++) {
let captureI = i;
setTimeout(function() {
console.log(captureI);
}, 1000);
}
This will work in pretty much any modern browser except IE11.

JavaScript: Repeated code vs. extra functions when code length is same

After updating my code based on answers to this previous question, I came up with the following solution:
var Coder = (function() {
var controlWords = [
['ONE','OO'],
['TWO','TT'],
['THREE','RR'],
//['...','..'],
['END','NN']
],
map = {
'0':' ', '1':'_', '2':',',
'3':'.', '4':'?', '5':'!',
'6':'\'','7':'"', '8':'(',
'9':')', 'a':'o', 'b':'d',
'c':'a', 'd':'e', 'e':'p',
'f':'i', 'g':'f', 'h':'v',
'i':'u', 'j':'l', 'k':'m',
'l':'y', 'm':'q', 'n':'x',
'o':'b', 'p':'j', 'q':'t',
'r':'n', 's':'z', 't':'w',
'u':'k', 'v':'h', 'w':'s',
'x':'c', 'y':'r', 'z':'g'
},
reverseMap = (function() {
var j, tmp = {};
for (j in map){
if (Object.prototype.hasOwnProperty.call(map, j))
tmp[map[j]] = j;
}
return tmp;
})(),
value, i,
encode = function(data) {
var input = (typeof data == 'string' ? data : '');
console.log('Input to encode: '+input);
for (i = 0; i < controlWords.length; i++) {
value = new RegExp(controlWords[i][0],'g');
input = input.replace(value,controlWords[i][1]);
}
console.log('Encode step 1: '+input);
input = input.replace(/./g, function(c){
return reverseMap[c]
|| reverseMap[c.toLowerCase()].toUpperCase();
});
console.log('Encoding output: '+input);
return {length: input.length, data: input};
},
decode = function(data) {
var input = (typeof data == 'string' ? data : '');
console.log('Input to decode: '+input);
input = input.replace(/./g, function(c){
return map[c]
|| map[c.toLowerCase()].toUpperCase();
});
console.log('Decode step 1: '+input);
for (i = 0; i < controlWords.length; i++) {
value = new RegExp(controlWords[i][1],'g');
input = input.replace(value,controlWords[i][0]);
}
console.log('Decoding output: '+input);
return {length: input.length, data: input};
};
return {encode: encode, decode: decode};
})();
var str = 'ONE Hello, TWO JavaScript THREE World! END',
enc = Coder.encode(str).data,
dec = Coder.decode(enc).data;
As you can see, there's a lot of fully- or nearly-repeated code. The only meaningful differences are the order in which the two transformations happen, whether map or reverseMap is used, and which index of each control word array is used as the regex and which as the replacement value.
To abide by the concept of wrapping repeated code in a sub-function and calling that function, I made the following attempt. It defines the two transformations as internal functions, and then based on the value of the type argument, decides the rest.
var Coder = (function() {
var controlWords = [ /* same */ ],
map = { /* same */ },
reverseMap = /* same */,
code = function(data, type) {
var input = (typeof data == 'string' ? data : ''),
mapping, x, y, value, i,
transform = function() {
return input.replace(/./g, function(c){
return mapping[c]
|| mapping[c.toLowerCase()].toUpperCase();
});
},
replace = function() {
for (i = 0; i < controlWords.length; i++) {
value = new RegExp(controlWords[i][x],'g');
input = input.replace(value,controlWords[i][y]);
}
return input;
};
if (type == 'decode') {
mapping = map;
x = 1;
y = 0;
input = transform();
input = replace();
} else if (type == 'encode') {
mapping = reverseMap;
x = 0;
y = 1;
input = replace();
input = transform();
} else {
throw new Error('Invalid type argument!');
}
return {data: input, length: input.length};
};
return {code: code};
})();
var str = 'ONE Hello, TWO JavaScript THREE World! END',
enc = Coder.code(str, 'encode').data,
dec = Coder.code(enc, 'decode').data;
However, you might notice that this code is actually longer. It's still more easily extended, if I wanted to add more types than 'encode' and 'decode' (not going to). But currently less efficient?
I then went back to the version with two functions (to avoid the passing of and check of 'type'):
var Coder = (function() {
var controlWords = [ /* same */ ],
map = { /* same */ },
reverseMap = { /* same */ },
input, mapping, x, y, value, i,
transform = function() {
return input.replace(/./g, function(c){
return mapping[c]
|| mapping[c.toLowerCase()].toUpperCase();
});
},
replace = function() {
for (i = 0; i < controlWords.length; i++) {
value = new RegExp(controlWords[i][x],'g');
input = input.replace(value,controlWords[i][y]);
}
return input;
},
encode = function(data) {
input = (typeof data == 'string' ? data : '');
mapping = reverseMap;
x = 0;
y = 1;
input = replace();
input = transform();
return {length: input.length, data: input};
},
decode = function(data) {
input = (typeof data == 'string' ? data : '');
mapping = map;
x = 1;
y = 0;
input = transform();
input = replace();
return {length: input.length, data: input};
};
return {encode: encode, decode: decode};
})();
// Call methods same as first example
So lengthy post to basically ask, which is better, repeated code or extra functions/checks, when it doesn't really help code length and there's no plans to extend the code or release it as a public project? Which of these is the most elegant solution, or is there an even better?
EDIT
One way I thought of to clean it up in general is to remove the variable declarations of mapping, x, and y and just pass them as arguments to replace and transform. This would yield
decode = function(data) {
var input = (typeof data == 'string' ? data : '');
input = transform(map);
input = replace(1,0);
return {length: input.length, data: input};
}

need to pass variable to function

I am trying to pass a variable to a a function that I believe calls another function (I think) but am having problems. The variable I need to use in the second function is productid but several ways thAt I have tried have not worked. either a fix in javascript or Jquery will be great!!!
This is the line that I need the variable for
var error_url = '/ProductDetails.asp?ProductCode' + productid;
this is where the variable originates from...
var productid = form.elements['ProductCode'].value;
and here is the whole js code
function addToCart2(form, button) {
var softAdd = true;
var productid = form.elements['ProductCode'].value;
var qstr;
var bttnName = button.name;
button.disabled = true;
if (form.elements['ReturnTo']) {
form.elements['ReturnTo'].value = "";
}
qstr = serialize(form, bttnName + '.x', '5', bttnName + '.y', '5');
sendAjax('POST','/ProductDetails.asp?ProductCode=' + productid + '&AjaxError=Y', qstr , retrieveProductError2 ,displayServerError,false);
button.disabled = false;
return false;
}
function retrieveProductError2(result, statusCode) {
var ele = document.getElementById('listOfErrorsSpan');
var errorIndex = result.indexOf('<carterror>');
var productIndex = result.indexOf('<ProductIndex>')
if (errorIndex > -1 && productIndex == -1) {
var error_url = '/ProductDetails.asp?ProductCode' + productid;
window.location = error_url;
}
if (errorIndex != -1) {
//ele.innerHTML = result.slice(errorIndex + 11, result.indexOf('</carterror>'));
}
else {
ele.innerHTML = "";
if (productIndex == -1) {
sendAjax('GET','/AjaxCart.asp?GetIndex=True', '', showCart, null, false);
}
else {
productIndex = result.slice(productIndex + 14, result.indexOf('</ProductIndex>'));
sendAjax('GET','/AjaxCart.asp?Index=' + productIndex, '', showCart, null, false);
}
}
}
The easiest way is to just move your variable declaration outside of your method. So change the declaration of product id outside your addToCart2 method. So outside of that method you do this:
var product_id;
Then inside your method remove var from product_id and it will just be an assignment and not declaration.
Where you pass in retrieveProductError2 as your error callback for the sendAjax call, you could instead pass in:
function(result, statusCode) { retreiveProductError2(result, statusCode, productId);}
Then change the definition of your retreiveProductError2 function to accept the additional parameter.

Categories