So I'm taking a form and using serializeArray() to get all the forms data. There are 10 text inputs. What I am trying to do is skip the forms that return a empty result or forms that have "" as value. Here is what I came up with and it returns the index of the forms with "" or empty results correctly.
$("#" + forms).on("submit", function(event) {
var allData = $(this).serializeArray();
event.preventDefault();
for (var key in allData) {
if (allData[key].value === "") {
allData.splice(key, 1);
}
}
});
But when I add allData.splice(key, 1); it doesn't remove all the values with "" as a result. I basically want to remove any input that isn't going to have a value.
Also the structure of the objec is as follows.
[0]
name: "emailone",
value "some#email.com"
[1]
name: "passwordone",
value: "123asd"
[2]
name: "emailtwo",
value "another#email.com"
[3]
name: "passwordtwo",
value: "asd123"
[4]
name: "emailthree",
value ""
[5]
name: "passwordthree",
value: ""
That happens because you are altering the array while traversing it...
When you key is 4 and the value is '' you remove that element (succesfully) but when you splice the array it becomes a smaller one.. so the element at position 5 is now at 4. Your key variable is increased to 5 but now there is no element 5 in your array..
You need to traverse it backwards
$("#" + forms).on("submit", function(event) {
var allData = $(this).serializeArray();
event.preventDefault();
for (var key = allData.length-1; key >= 0 ; key--) {
if (allData[key].value === "") {
allData.splice(key, 1);
}
}
});
By splicing an array as you iterate over it, you can accidentally skip values - in this case, by removing a value at index four, you decrease the index of the following value by one. The loop than increments to five, and the value that started at the fifth index is skipped.
A few other answers have posted reasonable ways to work around this. If you're working with a newer version of JavaScript or with a library like jQuery or underscore, you could alternatively do this:
allData = allData.filter(function(e) {
return e.value !== "";
});
With jQuery, this can be written as
allData = $.grep(allData, function(e) {
return e.value !== "";
});
and in underscore:
allData = _.filter(allData, function(e) {
return e.value !== "";
});
var arrLength = allData.length, i, cleanArray = [], serializedArr;
for(i = 0; i < arrLength; i += 1{
if(allData[i] != ""){
cleanArray.push(allData[i]);
}
}
serializedArr = cleanArray.serializeArray();
You simply use delete to achieve your need,
for (var key in allData) {
if (allData[key].value === "") {
delete allData[key];
}
}
additionally you don't need explicitly get the value by this toallData[key].value, toallData[key] will simply return the value associated with the particular key.
DEMO
Updated:
for (var i=0; i < allData.length ; I++) {
if (allData[i].value === "") {
allData.splice(i, 1);
i--;
}
}
You should decrement the value of the index by one, every time you are removing an object from the array.
Related
I am new to protractor and JavaScript and struggling trying to compare a delimited string to an array.
What I am trying to do is to find a list of all elements and then from each element, loop through the arrays to compare the text values to the delimited string but the delimited string values are 'undefined'
element.all(by.css('.itemField')).then(function (allFieldItems) {
var toCompare= ["AGO", "9"]
for (var i = 0; i < toCompare.length; i++) {
var valueToCompare = toCompare[i]
allFieldItems[i].getText().then(function (text) {
if(text != valueToCompare[i]){
console.log("Values don't match")
}
}.bind( i))
}
})
The problem is that the line "if(text != valueToCompare[i]) the "valueToCompare[i]" is always 'undefined' and I am looking for help on how to resolve this without using expect statements.
You can call getText() on the result of element.all() directly:
var toCompare = ["AGO", "9"];
element.all(by.css('.itemField')).getText().then(function (texts) {
for (var i = 0; i < toCompare.length; i++) {
if (texts[i] != toCompare[i]) {
console.log("Values don't match");
}
}
});
Or, you may even expect it like this (not sure if this is what you are actually trying to do):
expect($$('.itemField').getText()).toEqual(toCompare);
I am trying to delete objects from my array via javascript. Im building a simple mobile jquery application and want to delete items from an array. I use the following code. I have a list with checkboxes in it. Every checkbox has a value that belongs to the list item. So when multiple checkboxes are checked.. it should delete all these objects (items) from the array.
function deleteFunction()
{
objects = getObjects();
$("input:checked").each(function()
{
var inputValue = $(this).val();
for(i = getObjects().length; i >=0; i--)
{
if('{"title":"'+ inputValue + '"}' == JSON.stringify(objects[i]))
{
objects.splice(i, 1);
return true;
}
}
});
alert(JSON.stringify(objects));
window.location.reload();
}
The annoying thing is as follows:
When i slice the object from the array, the object is restored on the second iteration. So it always removes only 1 object from the array.
To test my output i used the following code within the if statement:
alert(i);
alert(JSON.stringify(objects[i]));
objects.splice(i, 1);
alert(i);
alert(JSON.stringify(objects));
return true;
The output is as follows
1
{"title":"hi2"}
1
[{"title":"hi1"}, {"title":"hi3"}]
2
{"title":"hi3"}
2
[{"title":"hi1"}, {"title":"hi2"}]
so i slice hi2, but has returned
Thanx for answer and respond
Solution Thanx to depperm + indubitablee:
function deleteFunction()
{
var objects = getObjects();
$("input:checked").each(function()
{
var inputValue = $(this).val();
for(i = objects.length -1; i >=0; i--)
{
if(objects[i].title == inputValue)
{
objects.splice(i, 1);
}
}
});
localStorage.setItem("objects", JSON.stringify(objects));
window.location.reload();
}
There are a few things I would change, first in the for loop no need to call getObjects() each time just use objects. Then in the if simply check if the objects[i].title is the same as the inputValue.
function deleteFunction()
{
objects = getObjects();
$("input:checked").each(function()
{
var inputValue = $(this).val();
for(i = objects .length; i >=0; i--)
{
if(objects[i].title==inputValue)
{
objects.splice(i, 1);
}
}
});
alert(JSON.stringify(objects));
window.location.reload();
}
use .splice() instead of .slice().
slice does NOT alter/manipulate the original array at all, it just creates another array based on your selection.
splice does alter the original array.
reference: http://www.devcurry.com/2010/12/slice-and-splice-in-javascript.html
The array method slice does not remove array elements. Use splice instead.
There are some problems with your code:
You missed the keyword var sometimes.
The variable i is equal to the length of the array in the first iteration. It should be one minus that.
Instead of converting to JSON to compare the objects, you could have just compared the value of the title property.
I'm trying to apply a constraint on combobox. It's half-working at the moment.
On the combobox, I have this listener:
[...]
listeners: {
'focus': function (combo, value) {
var orgComboVal = Ext.getCmp('Org1')
var getOrgValue = orgComboVal.getValue();
if (typeof getOrgValue !== undefined) {
reseaulist.clearFilter(true);
for (var q = 0, l = getOrgValue.length; q < l; q++) {
reseaulist.filter([
{property:'code_organisme', value: getOrgValue[q]}
]);
}
}
}
}
Ext.getCmp('Org1') defines another combobox.
When orgComboVal.getValue() is a single value, the filter is well applying.
but when it's an array of value, eg ["5", "9"], it's not working and the combobox supposed to be filtered shows no value (so I guess a filter is still applied but in an incorrect way).
I guess it's because the reseaulist.filter is called multiple time.
How can I achieve this ?
I saw the filterBy method but I don't know how to make it work.
Also, this post is interesting : How to filter a store with multiple values at once? but same, can't make it work since
getOrgValue.split(',')
is showing an error
(Object Array has no method split)
Any tips ? I'm using ExtJS 4.2.
EDIT
Thanks to #rixo, I've made it.
Also, I had to change some of the code he provided me, because the value of the Org1 combobox was always an array, even if empty, so the store filter was never cleared.
Here it is :
'focus': function (combo, value) {
var orgComboVal = Ext.getCmp('Org1')
var values = orgComboVal.getValue();
console.log(values)
if (values != null) {
reseaulist.clearFilter(false);
if (Ext.isArray(values)) {
if (0 < values.length) {
reseaulist.filterBy(function(record, id) {
return Ext.Array.contains(values, record.get('code_organisme'));
});
} else {
reseaulist.clearFilter(true);
}
}
}
}
Each filter is applied one after the other on the previously filtered data set, so your code implements a logical AND. That's why all values are filtered out...
Here's an example using filterBy to accept any value that is in your array:
function (combo, value) {
var orgComboVal = Ext.getCmp('Org1')
var values = orgComboVal.getValue();
if (values != null) {
store.clearFilter(false);
if (Ext.isArray(values)) {
store.filterBy(function(record, id) {
return Ext.Array.contains(values, record.get('code_organisme'));
});
} else {
record.get('code_organisme') === values;
}
} else {
store.clearFilter(true);
}
}
Or you could also use a regex with the filter method:
function (combo, value) {
var orgComboVal = Ext.getCmp('Org1')
var values = orgComboVal.getValue();
if (values != null) {
var filterValue = Ext.isArray(values)
? new RegExp('^(?:' + Ext.Array.map(values, function(value){return Ext.escapeRe(value)}).join('|') + ')$')
: values;
store.clearFilter(false);
store.filter('code_organisme', filterValue);
} else {
store.clearFilter(true);
}
}
Concerning your error, arrays indeed don't have a split method. Strings can be split into an array. Arrays, on their side, can be joined into a string...
Try This....
var getOrgValue = "5,9,4"; // array of value
reseaulist.filterBy(function(rec, id) {
return getOrgValue.indexOf(rec.get('code_organisme')) !== -1;
});
I've got an in page text search using JS, which is here:
$.fn.eoTextSearch = function(pat) {
var out = []
var textNodes = function(n) {
if (!window['Node']) {
window.Node = new Object();
Node.ELEMENT_NODE = 1;
Node.ATTRIBUTE_NODE = 2;
Node.TEXT_NODE = 3;
Node.CDATA_SECTION_NODE = 4;
Node.ENTITY_REFERENCE_NODE = 5;
Node.ENTITY_NODE = 6;
Node.PROCESSING_INSTRUCTION_NODE = 7;
Node.COMMENT_NODE = 8;
Node.DOCUMENT_NODE = 9;
Node.DOCUMENT_TYPE_NODE = 10;
Node.DOCUMENT_FRAGMENT_NODE = 11;
Node.NOTATION_NODE = 12;
}
if (n.nodeType == Node.TEXT_NODE) {
var t = typeof pat == 'string' ?
n.nodeValue.indexOf(pat) != -1 :
pat.test(n.nodeValue);
if (t) {
out.push(n.parentNode)
}
}
else {
$.each(n.childNodes, function(a, b) {
textNodes(b)
})
}
}
this.each(function() {
textNodes(this)
})
return out
};
And I've got the ability to hide columns and rows in a table. When I submit a search and get the highlighted results, there would be in this case, the array length of the text nodes found would be 6, but there would only be 3 highlighted on the page. When you output the array to the console you get this:
So you get the 3 tags which I was expecting, but you see that the array is actually consisting of a [span,undefined,span,undefined,undefined,span]. Thus giving me the length of 6.
<span>
<span>
<span>
[span, undefined, span, undefined, undefined, span]
I don't know why it's not stripping out all of the undefined text nodes when I do the check for them. Here's what I've got for the function.
performTextSearch = function(currentObj){
if($.trim(currentObj.val()).length > 0){
var n = $("body").eoTextSearch($.trim(currentObj.val())),
recordTitle = "matches",
arrayRecheck = new Array(),
genericElemArray = new Array()
if(n.length == 1){
recordTitle = "match"
}
//check to see if we need to do a recount on the array length.
//if it's more than 0, then they're doing a compare and we need to strip out all of the text nodes that don't have a visible parent.
if($(".rows:checked").length > 0){
$.each(n,function(i,currElem){
if($(currElem).length != 0 && typeof currElem != 'undefined'){
if($(currElem).closest("tr").is(":visible") || $(currElem).is(":visible")){
//remove the element from the array
console.log(currElem)
arrayRecheck[i] = currElem
}
}
})
}
if(arrayRecheck.length > 0){
genericElemArray.push(arrayRecheck)
console.log(arrayRecheck)
}
else{
genericElemArray.push(n)
}
genericElemArray = genericElemArray[0]
$("#recordCount").text(genericElemArray.length + " " +recordTitle)
$(".searchResults").show()
for(var i = 0; i < genericElemArray.length; ++i){
void($(genericElemArray[i]).addClass("yellowBkgd").addClass("highLighted"))
}
}
else{
$(".highLighted").css("background","none")
}
}
If you look at the code below "//check to see if we need to do a recount on the array length. ", you'll see where I'm stripping out the text nodes based off of the display and whether or not the object is defined. I'm checking the length instead of undefined because the typeof == undefined wasn't working at all for some reason. Apparently, things are still slipping by though.
Any idea why I'm still getting undefined objects in the array?
My apologies for such a big post!
Thanks in advance
I've modified your eoTextSearch() function to remove dependencies on global variables in exchange for closures:
$.fn.extend({
// helper function
// recurses into a DOM object and calls a custom function for every descendant
eachDescendant: function (callback) {
for (var i=0, j=this.length; i<j; i++) {
callback.call(this[i]);
$.fn.eachDescendant.call(this[i].childNodes, callback);
}
return this;
},
// your text search function, revised
eoTextSearch: function () {
var text = document.createTextNode("test").textContent
? "textContent" : "innerText";
// the "matches" function uses an out param instead of a return value
var matches = function (pat, outArray) {
var isRe = typeof pat.test == "function";
return function() {
if (this.nodeType != 3) return; // ...text nodes only
if (isRe && pat.test(this[text]) || this[text].indexOf(pat) > -1) {
outArray.push(this.parentNode);
}
}
};
// this is the function that will *actually* become eoTextSearch()
return function (stringOrPattern) {
var result = $(); // start with an empty jQuery object
this.eachDescendant( matches(stringOrPattern, result) );
return result;
}
}() // <- instant calling is important here
});
And then you can do something like this:
$("body").eoTextSearch("foo").filter(function () {
return $(this).closest("tr").is(":visible");
});
To remove unwanted elements from the search result. No "recounting the array length" necessary. Or you use each() directly and decide within what to do.
I cannot entirely get my head around your code, but the most likely issue is that you are removing items from the array, but not shrinking the array afterwards. Simply removing items will return you "undefined", and will not collapse the array.
I would suggest that you do one of the following:
Copy the array to a new array, but only copying those items that are not undefined
Only use those array items that are not undefined.
I hope this is something of a help.
Found the answer in another post.
Remove empty elements from an array in Javascript
Ended up using the answer's second option and it worked alright.
Extending a previous question about JavaScript and jQuery, I'm trying to make an array and then look into it, but the array contains dimensions and I can't get it right..
var markers = [];
$.getJSON('GetList', "id"= + data.id,
function(data){
$.each(data.list, function(index, data) {
}
markers.push( {
category:data.category,
id:data.id,
location:{
latitude:data.location.latitude,
longitude:data.location.longitude
}
});
});
});
return markers;
}
The first thing that strikes me is that every item will now be called "Object", while default, I'm still wondering if they can be labeled instead?
Further down the line, I try to access the id to compare it to a selection by the user,
but it doesn't work.
var selection = $(div_id).val();
var arr = $.inArray(selection, markersArray.id);
if( arr >= 0) {
return search(selection, div_id);
} else {
throw("selection not found in selectionSearch()");
}
What am I doing wrong here..?
To label the objects, add a toString function, like this:
markers.push({
toString: function () { return this.something; },
category:data.category,
id:data.id,
location:{
latitude:data.location.latitude,
longitude:data.location.longitude
}
});
To search the array, you'll need your own loop.
jQuery's $.inArray function searches the array for an exact match; it cannot be used to find an object with a matching property.
You can find a match yourself, like this:
for(var i = 0; i < markers.length; i++) {
if (markers[i].id === selection)
return search(selection, div_id);
}
throw("selection not found in selectionSearch()");
The type of each item is Object, there is nothing strange about that. There is no reason to try to change that.
To filter out items from an array based on a property in the item, you use the grep method:
var arr = $.grep(markers, function(e){ return e.id === selection; });
To check if the array is empty, you don't compare the array to a number, you use the length property:
if (arr.length > 0) {