$.each() function jQuery on an object - javascript

I have a form and I am trying to build a custom validation for it by iterating over the elements and do whatever needs to be done.
This is my js code so far
$('#createClient').click(function (event) {
var formData = {
'clientbrandname': $("#createClientBrand").val(),
'surveyReferral': $("#createSurveyReferral").val(),
'GuestReferral': $("#createGuestReferral").val(),
'email': $("#createInviteEmail").val(),
'phone': $("#createPhoneNumber").val(),
'xampAccNumber': $('#createUserLimit').val(),
'logo': $('#createClientLogo').val(),
'Template': $('#createRefPage').val(),
'xampClient': $('#createAmplifierClient').val(),
'xampActive': $('#createAmpMembership').val(),
'sReferralID': $('#sReferralID').val(),
'gReferralID': $('#gReferralID').val()
};
$(formData).each(function () {
alert($(this).val());
});
});
With this code I am running into an error (i.nodeName is undefined) which I suspect is coming from the part where I am trying to use $(this).val()
Anyone can suggest a solution for this issue?

You are iterating over an object. Therefore you need to call the name value pair in the function.
The $.each() function is not the same as $(selector).each(), which is
used to iterate, exclusively, over a jQuery object. The $.each()
function can be used to iterate over any collection, whether it is an
object or an array.
JsFiddle
$.each( formData, function( name, value ) {
alert(name); //Alerts clientbrandname
alert(value); //Alerts the value from "$("#createClientBrand").val()"
});

Referring to the jQuery docs located HERE, it states
A generic iterator function, which can be used to seamlessly iterate
over both objects and arrays. Arrays and array-like objects with a
length property (such as a function's arguments object) are iterated
by numeric index, from 0 to length-1. Other objects are iterated via
their named properties.
You're trying to use this on an associative array, which cannot be itereated via a a numeric index.
The following is pulled from the jQuery docs page noted above..
var obj = { one: 1, two: 2, three: 3, four: 4, five: 5 };
$.each( obj, function( i, val ) {
$( "#" + i ).append( document.createTextNode( " - " + val ) );
});

What you really want is this:
$.each(formData, function(key, value) {
// ...
});
The function $ like in $(...) expects a node or an array of nodes. Then the object it returns has the method #each which iterates over the nodes.
Now there's a general purpose iterator - which the method mentioned above uses - that is $.each. This function expects any array-like object.
The {} object in JavaScript can behave like an array for this purpose.
Now I wonder, did you consider using serializeArray ?

When you pass your JavaScript object to the jQuery constructor ($(...)) you are creating a jQuery object instance. This instance has a length property, which causes the object to act array-like.
According to the jQuery documentation for $.each,
Arrays and array-like objects with a length property (such as a function's arguments object) are iterated by numeric index, from 0 to length-1.
This solution won't work for you because you don't have numerical indices.
Instead, you need to use the other form of the $.each function, which can be seen below:
//Just a generic representation of your JavaScript object.
var obj = {
myKey: 'myValue'
};
$.each(obj, function (key, value) {
console.log(key); //Outputs 'myKey'
console.log(value); //Outputs 'myValue'
});
Here, obj has not yet been turned into a jQuery object before iterating over it. It doesn't have a length property, so it won't be treated like an array. Now, the property name will be sent to the callback function as the first parameter, and the value of the property will be sent as the second parameter.

Related

What are the valid [].forEach.call function argument?

What are the valid [].forEach.call function argument? In the code below el appears to be a Nodelist or an element of the nodelist?
[].forEach.call(
document.getElementById('menu').querySelectorAll('.custom-can-transform'),
function(el){
el.classList.toggle('pure-menu-horizontal');
}
);
)
Function.prototype.call replaces the this variable of the function with its first argument, and then calls the function with all remaining arguments given to .call().
This means that the code above evaluates to this:
document.getElementById('menu').querySelectorAll('.custom-can-transform').forEach(function(el){
el.classList.toggle('pure-menu-horizontal');
});
Note that the this variable of forEach without use of the .call() method would be [], as it prefixes the forEach call.
As to what the arguments of forEach on an array are?
It only accepts 2 arguments. The first argument is the function callback that gets called for each element of the array. The second (optional) argument is used to inject a this variable into the function-body of the callback method. source
Many of the Array methods are generic by design. It means that their internal implementation doesn't rely in this to be Array instance. Basically, such implementation only requires this object to have numeric indexes and length property. Such objects are called "array-like objects".
There are many objects that conform this requirements. For example NodeList observed by you as document.getElementById('menu').querySelectorAll. This is array-like object because you can access individual Nodes by their indexes, and such node list have length property.
Any string is array-like object too. For example, string "hello world". you can access character "w" as str[t]. And str.length is equal to 11.
Requirement of numeric indexes and length property allows method implementation to iterate through all individual element of collection without need to know what this collection is actually is.
It also make it possible to use generic methods on different objects:
const obj = {0: 'one', 1: 'two', length: 2};
Array.prototype.forEach.call(obj, (el, index) => {
console.log(`${index}: ${el}`)
})
Or, the most common use for such "borrowed" other prototype methods is using array methods on non arrays, usually DOM elements:
const items = document.querySelector('ul > li')
const ids = [].map.call(items, li => li.id)
Here I should note, that spread operator from ES2015 spec, makes such borrowing methods less needed.

How to update object properties within a loop?

I have found a behavior I did not expect when trying to use a loop in order to change the value set for a property in an object.
Basically, I declare my object outside the loop.
Then I loop on an array of numeric values, which values are used to update the object property.
Inside the loop, I store the current object state inside an external array.
The result is that instead of having an array containing a series of objects with different numeric values, I end up having the same numeric values in each object stored.
Here is the fiddle http://jsfiddle.net/fAypL/1/
jQuery(function(){
var object_container = [];
var numeric_values = [1, 2 , 3, 4];
var my_object = {};
jQuery.each(numeric_values, function(index, value){
my_object['value'] = value;
object_container.push(my_object);
});
jQuery.each(object_container, function(index, value){
jQuery('#content').prepend(value['value']);
});
});
I would expect to get 1 2 3 4 as values stored in each object, however, what I get is 4 4 4 4, which does not make sense to me.
Any hint on this behavior is more than welcome, thanks
When your code calls .push() and passes my_object, what's being passed is a reference to the object. No copy is made.
Thus, you've pushed four references to the exact same object into the array.
JavaScript objects always participate in expressions in the form of references. There's no other way to deal with objects. Thus when you create a variable, and set its value to be an object, you're really setting its value to be a reference to the object. Same with parameter passing, and anywhere else an object can appear in an expression.
In this case, you can create new objects pretty easily; just dispense with my_object and push a fresh one on each iteration:
object_container.push( { value: value } );
You are not creating a new object each time around the loop - you are just updating the same existing object and pushing references of that to the object array. To create a new object you want to do something like:
my_object = { 'value': value };
object_container.push(my_object);
In this case you now will get something more like what you were looking for. See the updated fiddle here: http://jsfiddle.net/fAypL/2/.
Best of luck!
One more thought (Clone!) - If you are really tied to using the same object each time, just clone the object before you add to the array. There is a great solution for that here.
You are using jQuery so if what you want is to merge without effecting the original look at :
var both_obj = $.extend( {}, default_obj , adding_obj );
This will leave your original object changed, also good to use for a copy.
jquery docs - extend()
An alternate version is to use an object with a constructor and the new keyword:
var object_container = [];
var numeric_values = [1, 2 , 3, 4];
function MyObject(value)
{
this.value = value;
}
jQuery.each(numeric_values, function(index, value){
object_container.push(new MyObject(value));
});
jQuery.each(object_container, function(index, value){
jQuery('#content').prepend(value['value']);
});
Fiddle

Difference in Jquery.each() and Array.prototype.forEach() method [duplicate]

This question already has answers here:
jQuery.each implementation differs from native Array.forEach
(3 answers)
Closed 9 years ago.
Is there any difference between Jquery.each() and Array.prototype.forEach() method since array.forEach() method can also be used to loop over array-like objects with length property.The only difference i see is placement of arguments ,what else can be the difference in them?
I found this:
var obj = { one:1, two:2, three:3, four:4, five:5 };
jQuery.each(obj, function(i, val) {
$("#" + i).append(document.createTextNode(" - " + val));
});
What i wan to know is ,do jquery.each() invokes function for object without length property??
Placement of arguments in the callback.
Quantity of arguments in the callback (The .forEach() gives you get a reference to the original collection.)
Default this value in the callback. (In jQuery it's the current item, in .forEach() it's the JavaScript default)
Ability to manually set the this value in the callback. (jQuery doesn't give this option, .forEach() lets you via a third argument.)
Avoidance of non-defined properties on sparse Arrays. (The .forEach() avoids them, jQuery includes them.)
They're very differently behaving methods. jQuery's doesn't make any attempt to be compliant with or complimentary of the standard behaviors.
In addition to Crazy Train's answer:
What i wan to know is ,do jquery.each() invokes function for object without length property??
Read the source:
// args is for internal usage only
each: function( object, callback, args ) {
var name, i = 0,
length = object.length,
isObj = length === undefined || jQuery.isFunction( object );
if ( args ) {
...
// A special, fast, case for the most common use of each
} else {
if ( isObj ) {
for ( name in object ) {
}
...
}
}
return object;
},
So you can see if there is no length property, or it has the value undefined, then jQuery thinks it's a plain object and will do a for..in loop over the enumerable properties with no guard against inherited properties.

JavaScript array of objects - 0th element undefined but stringify shows objects

I am pulling an object from backbone.js and when I stringify the object I see string literal
'[{"Name":"Testname","Address":"Testaddress","id":"444444444444444"}]'
However, when I assign the non-serialized object to a variable and try to access the 0th element, I get undefined. I would expect to get object
{"Name":"Testname","Address":"Testaddress","id":"444444444444444"}
Is JavaScript not treating
[{"Name":"Testname","Address":"Testaddress","id":"444444444444444"}]
as an indexed array of objects?
To access elements of Backbone.Collection by index, use the Collection#at method:
var first = collection.at(0);
Alternatively, you can use the Collection#first method, which is actually part of the underscore library, but is proxied to Backbone collections for syntactic sugar:
var first = collection.first();
The reason you're seeing the array representation in the serialized JSON is that by convention JSON.stringify looks for a method called toJSON on the object you give to it to stringify, and if one is found, the return value of that method will be used instead. The implementation of Collection#toJSON returns a clone of the collection's internal array of models, and thus the JSON output is an array.
Just tried
var arr = JSON.parse( '[{"Name":"Testname","Address":"Testaddress","id":"444444444444444"}]' );
and
console.log( arr[0] ); // => object
What you've described should work.

jQuery: Using string passed by $.each

This is my code:
<div class='a'>
<div class='b'>Test</div>
</div>
and
$(['.b']).each(function () {
console.log($('.a').find(this).text()); // Expecting to print "Test"
});
I expect the console.log to print Test, but it doesn't! Is this a jQuery bug?
There are a few problems here.
When you call jQuery with an array (like you're doing), jQuery expects it to be an array of DOM elements.
If you want to use $.each, use the static version that iterates over generic objects or arrays.
With both of those things said, there's stil an issue with using $.each with an array containing primitive values. The following code exhibits the same problem you were seeing:
$.each([".b"], function () {
console.log($('.a').find(this).text()); // Expecting to print "Test"
});
Inside the callback function for .each, this is a String object and not a string primitive. To understand this, we need to look at what .each is doing under the hood:
for (; i < length;) {
if (callback.apply(object[i++], args) === false) { // <----
break;
}
}
The important bit is the call to apply. According to the ECMAScript specification, when a primitive value is passed to apply, the value's toObject method is called:
If thisArg is null or undefined, the called function is passed the global object as the this value. Otherwise, the called function is passed ToObject(thisArg) as the this value.
This explains why your code was not working-- .find expects a string primitive and not a String object.
This is why the documentation for $.each actually mentions using this with primitive values:
(The value can also be accessed through the this keyword, but Javascript will always wrap the this value as an Object even if it is a simple string or number value.).
Therefore the way to fix the problem with your code is to leverage the element argument that's passed to the callback function:
$.each([".b"], function (_, item) {
console.log($('.a').find(item).text()); // Expecting to print "Test"
});
Don't use this inside each when looping over an array. It works fine on objects or collection of elemnts but fails with arrays.
Use second argument of each to access array element
$(['.b']).each(function (index, item) {
console.log($('.a').find(item).text()); // Expecting to print "Test"
});
DEMO http://jsfiddle.net/KbuZK/
That's because you're on the dark side of JavaScript.
In JavaScript, this is always made into an Object so that typeof this === "object", no matter what this was actually bound to. Even when a primitive string is bound to the this context (which you'd expect to give typeof this === "string"), this is actually a String object and typeof this === "object". Here's a more thorough explanation of this behaviour.
When iterating over arrays of non-objects, you should use the second argument of your callback function as value.
$(['.b']).each(function (index, value) {
console.log($('.a').find(value).text()); // Expecting to print "Test"
});

Categories