iterate over array in jquery - javascript

I'm trying to do some validation on a user selecting items from a list. I want to make sure an item is not added twice by checking if the <li> is already in the array. This is what I'm trying and its not working.
$(".List").on("click", "li", function () {
var i = 0;
var checkArr = [];
var div = $("#AddedItems");
var parent = $(this).closest("ul");
var itemtoadd = parent.find("[data-id]").attr("data-id");
var name = parent.find("[data-name]").attr("data-name");
alert(itemtoadd + name);//checking
var itemtoadd = ("<li id = " + itemtoadd + " class = \"itemAdd\">" + name + "</li>");
checkArr.push(itemtoadd); //put one in to check against?
checkArr.forEach(item)
{
if (item == itemtoadd)
alert("this item has already been added");
else {
checkArr.push(itemtoadd);
alert(itemtoadd);
$(itemtoadd).appendTo(div);
}
}
// div.html(itemtoadd);
});

You have at least three problems here:
You aren't using Array.forEach correctly -- it takes a function that takes an item.
Immediately before you do your check, you're adding the item you're looking for. You will always hit the alert case.
You're using checkArr as a local variable -- you're getting an empty array each time you enter the function.
That all being said, you can accomplish your goal without keeping an array at all. I believe you can replace everything from your first alert down with this:
if ($('#' + itemtoadd, div).length == 0) {
itemtoadd = ("<li id = " + itemtoadd + " class = \"itemAdd\">" + name + "</li>");
div.append(itemtoadd);
}
else {
alert("this item has already been added");
}

Related

Unable to access options within select element

The Problem: I am able to retrieve the HTMLOptionsCollection object from the select element, but unable to get an accurate length or array from it.
For context, I am trying to make an array from the HTMLOptionsCollection object so I can loop through the options to add the selected attribute to one of the option elements. Also, I'm doing this for a chrome extension so I'm not sure if there would be any odd compatibility issues because of that.
Right now, I have this code:
var dropdown = document.getElementById("clients"); // Initially empty
fillDropdown(); // This does in fact fill the select element with option elements
console.log(dropdown) // Returns select element
console.log(dropdown.options); // Returns filled HTMLOptionsCollection object
console.log(dropdown.options.length); // Returns 0
// Make an array out of HTMLOptionsCollection object (taken from https://stackoverflow.com/questions/6138042/javascript-selecbox-options-to-array)
var arr = Array.apply(null, dropdown.options).map(function(el) { return el.value; });
console.log(arr); // Returns Array[0]
Here are the console.log results:
I did not expect the length to be inaccurate at all and can't figure out why this is. Any help is greatly appreciated!
EDIT: Here is my fillDropdown() function. It's ultimate goal is to append option elements to the select element. The extra jargon is to prevent options from getting too long word wise.
// Input: None
// Output: None
// Proceeds to fill the clients dropdown with clients from local storage
function fillDropdown() {
chrome.storage.local.get(function(data) {
if (typeof data.lastClientName !== "undefined") {
for (var i = 0; i < clients.length; i++) {
// Create an option element to add to the dropdown.
var clientOption = document.createElement("option");
// cutoff is an array which holds whole words. This is done to cleanly cut off a name.
var cutoff = clients[i].split(" ");
// A clients name may have no more than 4 words to its name.
if (cutoff.length > 4) {
cutoff = cutoff[0] + " " + cutoff[1] + " " + cutoff[2] + " " + cutoff[3] + " ...";
// The full name attribute is used to store the actual name.
clientOption.setAttribute("fullName", clients[i]);
// The value and innerHTML are both the same and are user visible.
clientOption.setAttribute("value", cutoff);
if (data.lastClientName === cutoff) {
dropdown.value = clientOption.value;
}
clientOption.innerHTML = cutoff;
}
else {
// fullName is added here for consistency
clientOption.setAttribute("fullName", clients[i]);
clientOption.setAttribute("value", clients[i]);
if (data.lastClientName === clients[i]) {
dropdown.value = cutoff;
}
clientOption.innerHTML = clients[i];
}
dropdown.appendChild(clientOption);
}
}
else {
for (var i = 0; i < clients.length; i++) {
// Create an option element to add to the dropdown.
var clientOption = document.createElement("option");
// cutoff is an array which holds whole words. This is done to cleanly cut off a name.
var cutoff = clients[i].split(" ");
// A clients name may have no more than 4 words to its name.
if (cutoff.length > 4) {
cutoff = cutoff[0] + " " + cutoff[1] + " " + cutoff[2] + " " + cutoff[3] + " ...";
// The full name attribute is used to store the actual name.
clientOption.setAttribute("fullName", clients[i]);
// The value and innerHTML are both the same and are user visible.
clientOption.setAttribute("value", cutoff);
clientOption.innerHTML = cutoff;
}
else {
// fullName is added here for consistency
clientOption.setAttribute("fullName", clients[i]);
clientOption.setAttribute("value", clients[i]);
clientOption.innerHTML = clients[i];
}
dropdown.appendChild(clientOption);
}
}
});
}
Also the only html to be concerned with here is
<select name="clients" id="clients"></select>
Try this:
const newArr = Array.from(dropdown.options);
console.log(newArr.length)
You can find other ways to do this here: https://hackernoon.com/htmlcollection-nodelist-and-array-of-objects-da42737181f9
I'm so sorry, I just realized that clients in fillDropdown() was not defined. Clients is supposed to be an array of business names that I would use to actually fill the dropdown. Now I'm curious as to why I didn't get an error for that in my console. I thought any undefined variable would show in the console.
On top of clients not being defined, I also had to make fillDropdown a callback function.
Thank you everyone for helping!

how to delete specific value from array jquery

Hello I can't find out how to delete a specific value from string when clicking on an element with the string value. its for my todo list.
if (window.localStorage.fullName !== undefined) {
alert('Your browser does not support localStorage');
} else {
$(function () {
console.log('localSorage compitability detected. proceeding...');
global vars & functions
var tdli = [];
add list items
$('#tdladd').click(function () {
$('.todolist ul ul').append("<li class='tdli'>" + $('#tdlinput').val() + "</li>");
tdli.push($('#tdlinput').val());
$('#tdlinput').val('');
var array = tdli + "";
localStorage.setItem('tdlis', array);
console.log(array);
$('#todolist').hide().fadeIn('fast');
});
remove list items
$('li').click(function () {
var itemtoRemove = $(this);
tdli.splice($.inArray(itemtoRemove, tdli), 1);
console.log(tdli);
});
$('#clearall').click(function () {
localStorage.clear();
location.reload();
});
load list items
var tdlitems = localStorage.getItem('tdlis');
var array = tdlitems.split(',');
tdli.push(array);
for (var i = 0; i < array.length; i++) {
array[i] + "<br>";
$('.todolist ul ul').append("<li>" + array[i] + "</li>");
};
console.log(array);
});
}
Assuming that tdli is a jQuery wrapped set (which itself is an array-like-object), it will have DOM nodes stored instead of another jQuery objects. That means, just go like
var itemtoRemove = this;
and you should be fine.
After you posted your complete code, we can see you're actually pushing string values into your tdli Array, but you try to .splice() objects respectively DOM nodes, which of course doesn't make any sense at all (comparing apples to oranges).

Implode array not working as expected

Take a look at my code :
// is_array function
function is_array(input){ return typeof(input)=='object'&&(input instanceof Array); }
// Check if cos_in is an array. If is not, create him
if(!is_array(cos_in))
{
var cos_in = new Array();
}
// Onclick function
function cos(pret,box,configuratie)
{
// Create a value (is different on every click; using different box)
cos_in[box] = box + '|||' + pret + '|||' + configuratie + '||||';
// Insert values from array in some div with #cos id
$("#cos").html(cos_in.join('||||'));
}
My problem is that the div with id #cos has from start value "test-empty", and for each time onclick function is executed, the div should have value from function. But is returns an empty div.
Some help please?
Although this code can be improved a lot I tried to fix your first immediate problem here.
Do you want to append the result every time you click? Where is the join for?
Are you trying to join the keys or the values? I assume for now you want the value and not the key.
window.cos_in = window.cos_in && window.cos_in instanceof Array ? window.cos_in : []
// Onclick function
function cos(pret,box,configuratie)
{
// Create a value (is different on every click; using different box)
cos_in.push(box + '|||' + pret + '|||' + configuratie + '||||');
// Insert values from array in some div with #cos id
$("#cos").html(cos_in.join('||||'));
}
Let me iterate a bit to get to something readable/understandable.
Here is a cleaner example of what you're doing. To improve it more I need to know where you're going with your links and parameters.
var cos = (function (cos_in) {
return function cos(pret, box, configuratie) {
// Create a value (is different on every click; using different box)
cos_in.push(box + '|||' + pret + '|||' + configuratie + '||||');
// Insert values from array in some div with #cos id
$("#cos").text(cos_in.join('||||'));
};
}([]));
Here is an example of an object version instead of an array...
var cos = (function (cos_in) {
return function cos(pret, box, configuratie) {
// Create a value (is different on every click; using different box)
cos_in[box] = (box + '|||' + pret + '|||' + configuratie + '||||');
// Insert values from array in some div with #cos id
$("#cos").text(Object.keys(cos_in).join('||||'));
};
}({}));
This is a simple wrapper you could use:
function join(input, str) {
if(typeof(input) === 'object') {
if(input instanceof Array) {
return input.join(str);
} else {
var tmp = [];
for(var x in input) {
if(input.hasOwnProperty(x)) {
tmp.push(input[x]);
}
}
return tmp.join(str);
}
}
return input;
}
/* ... */
$("#cos").html( join(cos_in, '||||') );
However, you really need to differ between languages. JavaScript might not work as you expect it, at least in comparison with PHP.

How can I use an array or another approach to improve since this list will grow?

This code works but will quickly be inefficient (already so?) as my var list grows.
I am adding Twitter streams to pages with their new API. That means I need to provide them some info manually and they return an ID string. That's OK, no workaround.
This example uses the info I need for just three streams but the list will quickly grow to dozens or even more.
function isValidTweets(ts_titletweets) {
var widgetid = $('#TweetStuff').attr('data-widget-id');
var jackID = '243441836335697920'; //IDs associated with streams
var jillID = '243398621595312128';
var harryID = '243398621595312130';
var ts_titletweets = title.toLowerCase(); //title is parsed from URL elsewhere
validtweets = "jack|jill|harry"; // if the title doesn't match then no streams should be used
if (validtweets.indexOf(ts_titletweets.toLowerCase() + "|") > -1) {
console.log('TweetsEnabled');
if (ts_titletweets == "jack")
{widgetid = jackID;
console.log(widgetid + title)}
else if (ts_titletweets == "jill")
{widgetid = jillID;
console.log(widgetid + title)}
else if (ts_titletweets == "harry")
{widgetid = harryID;
console.log(widgetid + title)};
$('#TweetStuff').html("<a class=\"twitter-timeline\" width=\"500\" height=\"600\" data-widget-id=" + widgetid + "></a>");
$("#newTweetsButton").delay(3000).show(0);
$("#filters").css({'margin' : '-30px 0px 0px 0px'});
return true;
} console.log('no Tweets');
return false;
}
I'm certain I'm manually reentering and want to avoid that as the list grows.
Any and all suggestions are much appreciated for a grateful newbie.
Thanks!
UPDATED TYPOS
I would create an object that has properties that correspond to the person's name. You then store the id against that. Next you can check whether it exists and execute your code.
http://jsfiddle.net/7PSNt/1/
var title = 'jill'; //hard coded for demo purposes
var myObject = {
'jack': 1,
'jill': 2,
'harry': 3
};
//I assume title is just one of the keys above (jack, jill, harry)
var ts_titletweets = title.toLowerCase();
//if the object contains a property for the title then we can proceed
var tweetID = myObject[ts_titletweets];
if (tweetID != undefined) {
widgetid = tweetID;
console.log(widgetid + ':' + title)
}
​
Not really sure what you are asking, but here's some stuff that might help:
// define an object with name: id pairs
var twitterIds = {
'jack': '243441836335697920',
'jill': '243398621595312128',
'harry': '243398621595312130'
};
foreach(var name in twitterIds) {
// name = jack
// twitterIds[name] = '243441836335697920'
}
function loadTweets ( name ) {
if( name && twitterIds[name] ) {
// load stream here. Use twitterIds[name] to get the twitter id
}
}
For efficiency, try this:
//cache of static jQuery objects
var $$ = {
'TweetStuff': $('#TweetStuff'),
'newTweetsButton': $("#newTweetsButton"),
'filters': $("#filters")
};
//define the ids in an outer scope - this gives isValidTweets less work to do each time it is called
var ids = {
jack: '243441836335697920',
jill: '243398621595312128',
harry: '243398621595312130'
};
function isValidTweets(title) {
var t = title.toLowerCase();
var widgetid = ids[t] || $$.TweetStuff.attr('data-widget-id');
$$.TweetStuff.html("<a class=\"twitter-timeline\" width=\"500\" height=\"600\" data-widget-id=" + widgetid + "></a>");
$$.newTweetsButton.delay(3000).show(0);
$$.filters.css({'margin' : '-30px 0px 0px 0px'});
console.log('Tweets: ' + (ids[t] ? (widgetid + ' - ' + title) : 'none'));
return !!ids[t];//true or false
}
I'm not sure I understand what's going on in the code, but what you could be using is a lookup-table.
var ids = {
'jack': '243441836335697920',
'jill': '243398621595312128',
'harry': '243398621595312130'
};
if (/*whatever*/) {
widgetid = ids[ts_titletweets];
console.log(widgetid + title);
}

PrototypeJS loop won't run

I have a loop which won't run using Prototype + Scriptaculous. It runs once for the first object in my array then stops.
var myMessages = new Object();
myMessages = ['success','info','warning','error']; // define the messages types
function hideAllMessages()
{
var messagesHeights = new Array(); // this array will store height for each
enter code here
// This one runs just once for the first item in the array
var i = 0;
myMessages.each(function(element) {
alert(element);
messagesHeights[i] = $('.' + element).getHeight();
i++;
$$('.' + element + ' message').invoke('hide');
});
//This won't run at all===============================
for (var index = 0; index < myMessages.length; index++)
{
messagesHeights[index] = $('.' + myMessages[index]).getHeight();
$('x').hide();
//$('.' + myMessages[i]).css('top', -messagesHeights[i]); //move element outside viewport
}
}
I'm not a prototype user, but here's what I see so far:
$ is for IDs. I believe you need $$ here:
$$('.' + element)
This returns an Array, so I think you need invoke() like this:
$$('.' + element).invoke('getHeight');
Also, .each() passes the index as the second argument to the callback, so you don't need to maintain your own i.
myMessages.each(function(element, i) {
Also, this:
$$('.' + element + ' message')
...would seem to be looking for elements with the tag named message. I assume you want a class instead.
$$('.' + element + ' .message').invoke('hide');

Categories