Why is my JS/jQuery loop stopping after 2 loops? - javascript

So I have an array with a lot of repeat values. myArr = ['yeh','yeh','yeh','hey']. I have an HTML form that allows the user to type in a word and if that word is in the array it'll delete all the repeat values and print out the new myArr without those values. However, my loop keeps stopping after a few loops without finishing deleting the rest of the duplicates. like if I had ['yeh','yeh','yeh'] and typed "yeh" in the form, it only deletes two of the 'yeh'.
HTML
<form id="remove_user" action="#" method="post">
<label for="user_num">Remove user:</label>
<input type="text" id="user_num" name="user_num" placeholder="number">
<input type="submit" value="(-) remove">
</form><!-- #remove_user -->
<ul id="user_list"></ul><!-- #user_list -->
JS:
$('#remove_user').submit(function(){
id = $('#user_num').val();
$.each(myArr, function(i, value){
if (value == id){
myArr.splice(i, 1);
console.log(myArr);
}
});
console.log(myArr);
$('#user_list').html('');
for (var i=0; i < myArr.length; i += 1) {
console.log(myArr[i]);
$('#user_list').append('<li>' +myArr[i]+ '</li>');
};
return false;
});
UPDATED ANSWER (so as said below, I was modifying it while looping over it, so things were getting skipped. Instead of what I did before, I used grep to create a new array of all the values that didn't match the submitted value, then just went through diffValues elements one by one and printed each out):
$('#remove_user').submit(function(){
id = $('#user_num').val();
var diffValues = $.grep(myArr, function(value, i){
return value != id;
});
console.log(diffValues);
$('#user_list').html('');
for (var i=0; i < diffValues.length; i += 1) {
console.log(diffValues[i]);
$('#user_list').append('<li>' +diffValues[i]+ '</li>');
};
return false;
});

When you splice the array, you are changing that array. So basically your array is going through these steps:
['yeh','yeh','yeh','hey']
^^^
splice, move iterator forward
['yeh','yeh','hey']
^^^
splice, move iterator forward
['yeh','hey']
^^^
end loop - one of the 'yeh' is still there
You might be interested in .grep().

If you want to delete values in an array that you're actively looping with, you have to go through it backwards (as making the length of the array shorter that way wouldn't invalidate your loop).
id = $('#user_num').val();
for (var i = myArr.length - 1; i >= 0; i--) {
if (myArr[i] == id) {
myArr.splice(i, 1);
}
}

Related

How to sort pushed array by id?

I have two arrays. First one which comes from response is divided by pagination. When i remove items from second array, they should be placed back sorted by id in first array, instead they go to bottom of array and i have to scroll down to find certain element. This is my code for pushing elements from array vm.feeds to vm.rationList:
function addAll() {
var mList = JSON.parse(JSON.stringify(vm.feeds))
for (var i = 0; i < mList.length; i++) {
mList[i].is_selected = false;
vm.rationList.push(mList[i]);
}
vm.feeds = [];
vm.rationListSafe = vm.rationList;
if(vm.feeds.length == 0){
vm.currentPageMaster++;
vm.isPage = true;
vm.disableScroll = true;
getFeedsByTeam(vm.selectedTeam);
}
}
Second part is how i remove elements from array vm.rationList and push them back to first array - vm.feeds:
function removeAll() {
for (var i = 0; i < vm.rationList.length; i++) {
vm.feeds.push(vm.rationList[i])
}
vm.rationList = []
}
In removeAll() i have to add additional check which will sort them by ID on push. Any idea for this?
The Array.push method add item to the end of your list.
To put an element at a given position in an array, you may prefer using Array.splice.
First argument is the index, second is the number of items to delete (in your case, 0), and a third argument would be the item to add at the given index.
With that, you can replace the push in removeAll by
vm.feeds.splice(correctIndex, 0, vm.rationList[i]);
Question is : what is correctIndex ?
Well, for that, there might be many solutions depending on your architecture, but a simple one could be to loop on vm.feeds to find the first item with an id that is not lower than the one you want to add:
var correctIndex = 0;
for(var item of vm.feeds) {
if (item.id >= vm.rationList[i].id) {break;}
else {correctIndex++;}
}
vm.feeds.sort(function(a, b) {
return parseFloat(a.id) - parseFloat(b.id);
});
This is the solution I found and it works

JavaScript - Replacing for loop with array helpers

So today I was learning about some ES6 array helpers, and I wanted to change my existing for loops with them, but I can not get same result as i was taking with for loop
function comment(){
let index;
for(let i = 0; i < commentArray.length; i++){
if(commentArray[i]._id == req.params.commentId){
index = commentArray.indexOf(commentArray[i]);
}
}
return index;
}
var com = comment();
It is nodejs and I am trying to get element index from database, and than pull from it, my code works just fine, but I want to change it with array helper, I guess I need find helper, but I can not make it work!
You can replace your for loop with this one-liner which uses Array#findIndex:
let index = commentArray.findIndex(comment => comment._id === req.params.commentId);
When this line executes, it will assign the index of comment, which has _id attribute same as req.params.commentId.
If you want to find the index of the item in the array based on some condition, you can use findIndex function
commentArray.findIndex(comment => comment._id === req.params.commentId)
Also with your current code with for loop, I think you need return the index as soon as it is found and not let the loop iterate till the end.
for(let i = 0; i < commentArray.length; i++){
if(commentArray[i]._id == req.params.commentId){
return commentArray.indexOf(commentArray[i]);
}
}

Javascript autocomplete stop for in loop

I'm trying to build a simple autocomplete feature and I'm running into a problem with the following script
<input type="text" name="search" id="searchField" placeholder="search for something" />
<div class="results-list">
<ul id="searchResults"></ul>
</div>
<script>
var users = JSON.parse('{{ $accounts }}'); // json data from php script
// add event listener
Event.add('searchField', 'keyup', function(){
if(document.getElementById('searchField').value.length > 1) {
processSearch(users, 'searchField', 'searchResults');
}
else {
document.getElementById('searchResults').innerHTML = '';
}
});
function processSearch(data, field, result) {
if(document.getElementById(field).value.length == 0) {
document.getElementById(result).innerHTML = '';
}
else {
for (var k in data) {
if(data.hasOwnProperty(k)) {
if(data[k].indexOf(document.getElementById(field).value) != -1) {
var list = document.createElement('li');
list.innerHTML = data[k];
document.getElementById(result).appendChild(list);
}
}
}
}
}
</script>
Now I'm getting the right results but if I keep writing the results are getting reproduced and I end up with a lot of duplicate results like in the picture below
And when I'm deleting the results are still duplicating unless the length of the field is less than 1 and all results are getting deleted.
Would anyone be able to tell me how to stop getting the duplicates?
The problem is that as processSearch() is called on every keystroke, and you append the results all the time to previous results. You need the delete the previous results in the beginning callback, i.e. iterate over all children of the result element and remove them using removeChild(). And then you can add the new results.
You can use the for...in statement for enumerated objects, but for iterating arrays, for...in should be avoided. Instead use the standard for statement.
for (var k = 0; k < data.length; k++) {
if(data.hasOwnProperty(k)) {
if(data[k].indexOf(document.getElementById(field).value) != -1) {
var list = document.createElement('li');
list.innerHTML = data[k];
document.getElementById(result).appendChild(list);
}
}
}

Unsetting javascript array in a loop?

I have the following code:
$.each(current, function(index, value) {
thisArray = JSON.parse(value);
if (thisArray.ttl + thisArray.now > now()) {
banned.push(thisArray.foodID);
}
else{
current.splice(index,1);
}
});
There's a problem with the following line:
current.splice(index,1);
What happens is that it (probably) unsets the first case which fits the else condition and then when it has to happen again, the keys don't match anymore and it cannot unset anything else. It works once, but not in the following iterations.
Is there a fix for this?
You can use a regular for loop, and loop backwards:
for(var i=current.length-1; i>= 0; i--) {
var thisArray = JSON.parse(current[i]);
if (thisArray.ttl + thisArray.now > now()) {
banned.push(thisArray.foodID);
} else {
current.splice(i, 1);
}
});
Also it seems thisArray is actually an object, not an array...
you can use regular for loop, but after splice, decrease index by 1
for(var i=0; i<current.length; i++){
current.splice(i, 1); i--;
}
You should pay attention if you mutate an array (by moving objects) while it's being traversed because some element may get skipped like in your case.
When you call current.splice(index, 1) element index will be removed and element index+1 will take its place. But then index will be incremented, thus skipping one element.
A better solution is IMO the read-write approach. You keep one index as the "read pointer" and you always increment it, and another index (the "write pointer") that is incremented only when you decide an element should be kept in the array:
var wp = 0; // The "write pointer"
for (var rp=0; rp<a.length; rp++) {
if (... i want to keep element a[rp] ...) {
a[wp++] = a[rp];
}
}
a.splice(wp); // Remove all elements after wp
This is a o(N) operation and will move each element at most once. Other approaches like starting from the end and using the same splice(i, 1) approach instead will keep moving all elements after i each time an element needs to be removed.

Checking Postal Codes with JQuery

I try to build a form which checks if an entered zip code matches a zip code in a predefined array. I don't use a DB, it's all very basic and hardcoded, but should be sufficient in this case.
The problem is that only the first zip-code in the array ('83512') works. If i am entering the second one ('83533') the code spits out "no success".
What am I doing wrong?
Thanks in advance.
HTML:
<form action="javascript:alert('success.');" id="checkplz">
<label for="plz">ZIP:</label>
<input type="text" name="plz" id="plz" />
<button id="submit" >Check!</button>
<div id="output"></div>
</form>
JQuery:
$(document).ready(function(){
var list = ['83512','83533'];
$("#checkplz").submit(function() {
for (var i = 0; i < list.length; i++) {
if ($("#plz").val() == list[i]) {
$("#output").append("<strong class='success'>success!</strong>").show();
return true;
}
$("#output").text("no success!").show().fadeOut(10000);
return false;
}
});
});
The logic in your loop is off. See below:
$(document).ready(function(){
var list = ['83512','83533'];
$("#checkplz").submit(function() {
var match = false;
for (var i = 0; i < list.length; i++) {
if ($("#plz").val() == list[i]) {
$("#output").append("<strong class='success'>success!</strong>").show();
return true;
}
}
$("#output").text("no success!").show().fadeOut(10000);
return false;
});
});
The problem is within the logic of your loop. The loop will only run one time, because the loop will always return after the first iteration (true if it finds the first element in the list array, false for everything else), rather than continuing through all iterations. So, what is happening for the second element is that the loop is running, determining that the first element was not found and returning false and never even processing the second element.
A better way to do this would be to loop the list array until you find a matching element, and keep track of wether an match was found or not. This will make sure we don't drop out of the loop until we've processed all elements of the array (or found a match, in which case we can stop the loop to save on processing).
See below (http://jsfiddle.net/ryanbrill/Kws7A/) for some example code with a few comments about what is happening.
$(document).ready(function(){
var list = ['83512','83533'];
$("#checkplz").submit(function() {
var matched = false; // Set up variable to track if we find a match
$(list).each(function() {
// Inside the jQuery 'each' method, 'this' equals the current item in the iteration.
if(this == $("#plz").val()) {
matched = true; // set the 'matched' variable to true
$("#output").append("<strong class='success'>success!</strong>").show();
return; // Since we found a match, we can stop processing the array
}
});
// Outside of the loop, only display no success if we didn't find any matches.
if (!matched) {
$("#output").text("no success!").show().fadeOut(10000);
}
});
});
Try returning false outside the loop, so it will only happen once all values are checked:
$(document).ready(function(){
var list = ['83512','83533'];
$("#checkplz").submit(function() {
for (var i = 0; i < list.length; i++) {
if ($("#plz").val() == list[i]) {
$("#output").append("<strong class='success'>success!</strong>").show();
return true;
}
}
$("#output").text("no success!").show().fadeOut(10000);
return false;
});
});
Use jQuery.inArray()
var list = ['83512','83533'];
if($.inArray('83533', list) > -1){
// found
}
Docs here: http://api.jquery.com/jQuery.inArray/

Categories