Caroline Beltran Caroline Beltran - 5 months ago 6
jQuery Question

Custom attr() method cannot be given a different name

I have the following perfectly working code (written by someone else). The problem is that if I simply rename the attr method, I get an error. For example, I rename the method to attrx and get this error:

TypeError: arg.attrx is not a function


Here is the working code:

function Action(name) {
this.attr = function(n) {
if (n=="name") {
return "action";
}
},
this.val = function() {
return name;
};
}

Action.prototype.toString = function() {
return "&" + this.attr("name") + "=" + this.val();
}


When a user triggers an event, the following function is called:

function serializeElements() {
var result = "";
for(var i = 0; i < arguments.length; i++) {
var arg = arguments[i];
result += (arg.attr("name") + "=" + arg.val() + "&");
}
return result;
}


Here is the identical code above but it has the attr method renamed to attrx:

function Action(name) {
this.attrx = function(n) {
if (n=="name") {
return "action";
}
},
this.val = function() {
return name;
};
}

Action.prototype.toString = function() {
return "&" + this.attrx("name") + "=" + this.val();
}

function serializeElements() {
var result = "";
for(var i = 0; i < arguments.length; i++) {
var arg = arguments[i];
result += (arg.attrx("name") + "=" + arg.val() + "&");
}
return result;
}


I cannot figure out the reason that the code does not work (see error at top of message) after I rename the method to attrx or anything else for that matter.

Note: The web page does include jQuery, but I don't think that is what causes the problem.

Here is the code used to call serializeElements:

function addStatesListener() {
$("#states").on("change", function(e) {
var form = $(this.form);
var url = form.attr("action");
var type = form.attr("method");
// pass 1) jQuery 'country' and 'state' objects and 2) a query string fragment, e.g.: '&action=change_state'
var data = serializeElements($("#countries"), $("#states"), new Action("change_state"));
e.preventDefault();
$.ajax({
url: url,
type: type,
data: data,
dataType: "html", // The type of data that you're expecting back from the server
success: function(result) {
$("#cities").html(result); // list of all cities, e.g.: <option value="Albany"</option>
}
});
});


}

Answer

Considering you are working on jquery objects, and if you want to clean your code, you could use .serialize() method instead of calling the couple .attr() and .val().

.serialize() is the jquery method to serialize form objects.

So you can change your code as follow:

function Action(name) {
    this.serialize=function() {
        return 'name='+encodeURI(name);
    }
}

And then your function serializeElements:

function serializeElements() {
    var args = Array.prototype.slice.call(arguments);
    return args.reduce(function(a, b){
       if (a) return a.serialize() + '&' + b.serialize();
       if (b) return b.serialize();
    });
}

Then you can call it so:

var data = serializeElements($("#countries,#states"), new Action("change_state"));

As you see, you could put form elements in a comma separated list on jquery selector.

That's it.