How do you properly delete list item by clicking on it?
I have been using the following line for code to delete an item but instead this deletes the entire list itself:
var list = document.getElementById("shoppinglist");
list.onclick = function() { list.parentNode.removeChild(list);}
I have been searching online on how to do this and the same kind of code keeps appearing and I am not sure how to solve this. I assumed that the list item generated was a child of the "shoppinglist".
I am very new to Javascript and I know this is a rookie mistake but I would really appreciate any help. Thank you.
<!doctype html>
<html dir="ltr" lang="en-gb">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<style>
body {
/* Sets the width then uses the margin auto feature to centre the page in the browser */
width:800px;
margin: 0px auto; /*0px top/bottom auto left/right */
font-size:10px; /* By default fonts are usually 16px but may not be in some browsers */
}
p, li {
font-size:1.5em; /* Set all text to be 1.5 * overall font size = 15 pixels */
}
section {
/* each of the two sections will use just under half the width of the width of the body */
width:395px;
display:block;
}
#choices {
/* float the choices list to the left of the page */
float:left;
background-color: #FFFF99;
}
#cart {
/* float the shopping cart to the right of the page */
float:right;
background-color: #7FFF00;
}
.cartlist {
/* Simplify the display of the lists, removing default bullet points and indentation */
list-style-type:none;
margin:0px;
padding:0px;
width:inherit;
}
.cartlist li {
/* Set each list item to be 2* the height of the text */
height:2em;
}
.cartlist li:nth-child(odd) {
/* Colour odd list items ie first, third, fifth etc, a different colour */
background-color:#eee;
}
#outputinfo {
/* prevents the DIV from joining the floating behaviour so it displays below the lists */
clear:both;
}
</style>
</head>
<body>
<section id="choices">
<p>Available Choices</p>
<ul id="sourcelist" class="cartlist">
<li data-value="2.99">£2.99 : Chocolate</li>
<li data-value="3.49">£3.49 : Cereal</li>
<li data-value="0.98">£0.98 : Milk</li>
<li data-value="0.89">£0.89 : Bread</li>
<li data-value="3.79">£3.79 : Coffee</li>
<li data-value="2.53">£2.53 : Strawberries</li>
<li data-value="3.89">£3.89 : Cheesecake</li>
</ul>
</section>
<section id="cart">
<p>Shopping Cart</p>
<ul id="shoppinglist" class="cartlist"></ul>
</section>
<div id="outputinfo">
<p><button id="calctotal">Calculate Total</button> : <span id="totalresult"></span></p>
</div>
</body>
<script>
function getTargetElement(e) {
var targetelement=null;
targetelement=(e.srcElement || e.target || e.toElement)
return targetelement;
}
function calcTotal() {
var shoppinglist=document.getElementById("shoppinglist");
var total=0;
for(i=0;i<shoppinglist.children.length;i++) {
total+=parseFloat(shoppinglist.children[i].getAttribute("data-value"));
}
var totalresult=document.getElementById("totalresult");
totalresult.innerHTML="£"+total.toFixed(2);
}
function handleEvent(e) {
var listclicked=getTargetElement(e);
var newlistitem=document.createElement("li");
var datavalue=listclicked.getAttribute("data-value");
newlistitem.setAttribute("data-value",datavalue);
newlisttext=document.createTextNode(listclicked.innerHTML)
newlistitem.appendChild(newlisttext);
var shoppinglist = document.getElementById("shoppinglist");
shoppinglist.appendChild(newlistitem);
var list = document.getElementById("shoppinglist");
list.onclick = function() { list.parentNode.removeChild(list);}
console.log(listclicked);
}
function removeItem(e){
var listclicked=getTargetElement(e);
var node = document.getElementById('shoppinglist');
listclicked.parentNode.removeChild(listclicked);
}
document.onreadystatechange = function(){
if(document.readyState=="complete") {
var sourcelist=document.getElementById("sourcelist");
for(i=0;i<sourcelist.children.length;i++) {
if(document.addEventListener) {
sourcelist.children[i].addEventListener("click", handleEvent, false);
} else {
sourcelist.children[i].attachEvent("onclick", handleEvent);
}
var totalbutton=document.getElementById("calctotal");
if(document.addEventListener) {
totalbutton.addEventListener("click",calcTotal,false);
} else {
totalbutton.attachEvent("onclick",calcTotal);
}
}
}
}
</script>
</html>
You don't want to remove the entire list, just the clicked LI element.
As you don't seem to have nested elements, event delegation becomes a little easier
var list = document.getElementById("shoppinglist");
list.addEventListener('click', function(evt) {
list.removeChild(evt.target);
},false);
FIDDLE
For the future, if you wanted nesten elements, you could use element.closest()
var list = document.getElementById("shoppinglist");
list.addEventListener('click', function(evt) {
var p = evt.target.closest('li');
list.removeChild(p);
}, false);
Note the somewhat lacking support in older browsers for closest(), but there are several polyfills available if needed.
Also note that you're binding event handlers inside event handlers, which is a big no-no, your code does the equivalent of
var sourcelist = document.getElementById("sourcelist");
for(i = 0; i < sourcelist.children.length; i++) {
sourcelist.children[i].addEventListener("click", handleEvent, false);
...
// and then
function handleEvent(e) {
var list = document.getElementById("shoppinglist");
list.addEventListener('click', function(evt) {
list.removeChild(evt.target);
},false);
....
so every time you add another list item to the list, you bind a new event handler, and it adds up, but you only need one single event handler, having multiple event handlers will just try to remove the same element over and over again, but it's removed the first time.
list.onclick = function() { list.parentNode.removeChild(list);}
list is the whole list (<ul id='list'>). You're listening for a click on the whole list. Then grabbing the whole list's parent node with list.parentNode ( which gives you <section id="cart">) and deleting the list from it.
Your code is doing exactly what you told it to do.
Like this:
list.removeChild(list.childNodes[indexToRemove])
You need to specify what node to remove. You can test this in chrome by opening up the console and pasting the following:
var list = document.getElementById("shoppinglist");
console.log('List:', list)
console.log('List children:', list.childNodes)
var indexToRemove = 0;
list.removeChild(list.childNodes[indexToRemove]);
console.log('List:', list)
console.log('List children:', list.childNodes)
You can use this:
var list = document.getElementById("shoppinglist");
list.onclick = function(e) { e.target.parentNode.removeChild(e.target);}
You can read more about target and currentTarget and checkout this example http://fiddle.jshell.net/hidoos/Lpz917vo/
Related
I am trying to figure out how to attach button 'Delete' to the each list element making so in advance that I will be able to make more buttons for additional list elements later.But when I create buttons,they appear without the text,just tiny rectangle box near the text.I wanted to fix through command 'document.getElementByClassName[list_number + "_button"].placeholder = "Delete",but I got an error even earlier trying to attach classnames to the buttons:
Uncaught TypeError: Cannot read property 'classList' of undefined
at addButton (script.js:74)
at script.js:82
But what's strange is that this error shows only at the [1] list object,not the the [0].For some reason with [0] object everything goes OK,although I didn't succeed in attaching name to it.I thought that the problem laid in list numeration,because the first button is actually "Send',but when I changed the value of var list_number = 0 from 0 to 1,it only got worse and gave an error right away.
How do I attach text in the buttons so they will look normal?
Note:the commands related to the buttons are at the end,everything earlier are command to add new elements to the list trhough input and make the elements line-through
CODE
var button = document.getElementById("button");
var modify_list = document.getElementById("userinput");
var ul = document.querySelector("ul");
var li = document.querySelectorAll("li");
var all_buttons = document.querySelectorAll("button");
var i = 0; //Attach classes to the li
while (li.length > i) {
li[i].classList.add(i);
li[i].classList.add('done');
li[i].classList.add('cursor');
i++
}
//Toggle the line-through function(later we will cal the function that will toggle once more when clicked on element of the list.
var n = 0
while (li.length > n) {
li[n].classList.toggle("done");
n++
}
//Command to add new elements to the list and make line-thorugh when clicked.
function inputLength() {
return modify_list.value.length;
}
function addToTheList() {
var li = document.createElement("li");
li.appendChild(document.createTextNode(modify_list.value));
ul.appendChild(li);
modify_list.value = '';
}
function addAfterClick() {
if (inputLength() === 0) {
alert("Please,don\'t enter the empty list");
} else {
addToTheList();
}
}
function addAfterEnter(key) {
if (key.keyCode === 13 && inputLength() > 0) {
addToTheList();
}
}
button.addEventListener("click", addAfterClick);
modify_list.addEventListener("keypress", addAfterEnter);
function toggle(number) {
li[number].classList.toggle("done");
}
ul.addEventListener("click", whenClicked);
function whenClicked(event) {
var li_number = event.target.className[0];
//In JS it doesn't matter in some occasions if it's a string or number,I suppouse.
// var li_number = Number(li_number_string);
// console.log(li_number);
toggle(li_number);
}
// Create buttons and their functions
function addButton(list_number) {
var button = document.createElement("button");
li[list_number].appendChild(button); //append button near the respective li objects
all_buttons[list_number].classList.add(list_number + "_button") //create class for the button
console.log(all_buttons[list_number].classList);
// document.getElementByClassName[list_number + "_button"].placeholder = "Delete"
}
var list_number = 0 // because under number 0 we have "Send" button
while (li.length > list_number) {
addButton(list_number);
list_number++;
}
// console.log(list_number);
.done {
color: red;
text-decoration: line-through;
}
.cursor {
cursor: pointer;
}
<!DOCTYPE html>
<html>
<head>
<title>DOM</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<h1>What plans do I have till the end of the summer?</h1>
<p>They are:</p>
<input type="text" name="add activities" id="userinput" placeholder="add activities">
<button id="button">Send</button>
<ul>
<li>Learn German</li>
<li>Learn Japanese</li>
<li>Learn Java Script</li>
<li>Physical activities</li>
</ul>
<script type="text/javascript" src="script.js"></script>
</body>
</html>
The text you want to be displayed on a programatically generated HTMLButtonElement can be set using it's .innerText property. The .placeholder property serves a different purpose.
Let's take a closer look at your addButton function:
function addButton(list_number){
var button = document.createElement("button");
li[list_number].appendChild(button); //append button near the respective li objects
all_buttons[list_number].classList.add(list_number + "_button") //create class for the button
console.log(all_buttons[list_number].classList);
// document.getElementByClassName[list_number + "_button"].placeholder = "Delete"
}
The first two lines are okay. Trouble starts here:
all_buttons[list_number].classList.add(list_number + "_button");
all_buttons is a HTML collection of buttons you initialized before you started adding dynamically generated button elements to the DOM thus it just contains the buttons set up via HTML. That means this array is outdated and would need to be updated every time you add or remove buttons.
Furthermore you don't need to use that array at all if you want to manipulate properties of your freshly generated button - you can directly access it using the variable button. I'd also recommend giving those buttons an unique id, so you can reference them later on and give it a click event listener for example. Also since there is already a global variable named button you should give the variable inside the function a different name e.g. localButton.
Here's an example:
var button = document.getElementById("button");
var modify_list = document.getElementById("userinput");
var ul = document.querySelector("ul");
var li = document.querySelectorAll("li");
var all_buttons = document.querySelectorAll("button");
var i = 0; //Attach classes to the li
while (li.length > i) {
li[i].classList.add(i);
li[i].classList.add('done');
li[i].classList.add('cursor');
i++
}
//Toggle the line-through function(later we will cal the function that will toggle once more when clicked on element of the list.
var n = 0;
while (li.length > n) {
li[n].classList.toggle("done");
n++;
}
//Command to add new elements to the list and make line-thorugh when clicked.
function inputLength() {
return modify_list.value.length;
}
function addToTheList() {
var li = document.createElement("li");
li.appendChild(document.createTextNode(modify_list.value));
ul.appendChild(li);
modify_list.value = '';
}
function addAfterClick() {
if (inputLength() === 0) {
alert("Please,don\'t enter the empty list");
} else {
addToTheList();
}
}
function addAfterEnter(key) {
if (key.keyCode === 13 && inputLength() > 0) {
addToTheList();
}
}
button.addEventListener("click", addAfterClick);
modify_list.addEventListener("keypress", addAfterEnter);
function toggle(number) {
li[number].classList.toggle("done");
}
ul.addEventListener("click", whenClicked);
function whenClicked(event) {
var li_number = event.target.className[0];
//In JS it doesn't matter in some occasions if it's a string or number,I suppouse.
// var li_number = Number(li_number_string);
// console.log(li_number);
toggle(li_number);
}
// Create buttons and their functions
function addButton(list_number) {
var localButton = document.createElement("button");
localButton.innerText = "Delete";
localButton.id = "myButton" + list_number;
li[list_number].appendChild(localButton);
}
var list_number = 0 // because under number 0 we have "Send" button
while (li.length > list_number) {
addButton(list_number);
list_number++;
}
.done {
color: red;
text-decoration: line-through;
}
.cursor {
cursor: pointer;
}
<h1>What plans do I have till the end of the summer?</h1>
<p>They are:</p>
<input type="text" name="add activities" id="userinput" placeholder="add activities">
<button id="button">Send</button>
<ul>
<li>Learn German</li>
<li>Learn Japanese</li>
<li>Learn Java Script</li>
<li>Physical activities</li>
</ul>
I work on a website, and I have a js problem.
I resume the situation:
I made a dynamic form with some tabs in.
I can switch tabs with a js click function
When I click on the "+" tab , it creates a new tab ( new <li> on the <ul>, and new <div> on main div )
But when I want to go on the new tab freshly created, the click function don't answer.
I put a console.log on the first line of the click function, and no log output.
the click function works well with static content, but with fresh content don't work.
How can I make it works with dynamic content ?
http://jsfiddle.net/npx2mes2/
http://jsfiddle.net/npx2mes2/1/
$("#tabs_menu_n1").on('click', 'a', function(e)
the problem was on registering the event, you should attach it to parent first, and then on every child.
change the line $(".tabs_menu_n1 a").click(function(e) { to $(document).on('click', ".tabs_menu_n1 a", function (e) {
Demo
Explanation.
when the elements are being added to DOM dynamically you must register the for the events every time the element is added. So instead of doing this process every time simply register events like below, therefore you don't want to register the events fro dynamically created elements
$(document).on('click', ".selector", function (e) {));
Now i can add elements with selector class dynamically and can handle click event on the element without registering the click event every time i add the element.
Note: You can use parent selector in place of document
A bit simplified sample without jQuery.
But idea same: add click handler to ul and check inside that clicked a tag.
var x = 2;
var original = document.getElementById('H1_n1');
function a(content, href) {
var link = document.createElement("a");
link.textContent = content;
link.setAttribute('href', href);
return link;
}
function li_a(id, content, href) {
var listItem = document.createElement("li");
listItem.setAttribute('id', id);
listItem.appendChild(a(content, href));
return listItem;
}
function div(id, textContent) {
var d = document.createElement("div");
d.setAttribute('class', 'tab_content_n1')
d.setAttribute('id', id)
d.textContent = textContent;
return d;
}
function add_rec() {
var i = x++;
var mdiv = document.getElementById("tab_n1");
mdiv.appendChild(div('H1_n' + i, '\nHello world from n' + i + '.\n'));
pbtn = document.getElementById('pbtn');
var ul = document.getElementById("tabs_menu_n1");
ul.insertBefore(li_a("hn" + i, "H" + i, "#H1_n" + i), pbtn);
}
document.getElementById('tabs_menu_n1').addEventListener('click', function(e) {
var el = e.target;
if (el.nodeName !== 'A') return;
if (el.hash == "#+") add_rec();
else {
e.preventDefault();
var current = document.querySelectorAll("#tabs_menu_n1 .current, #tab_n1 .current");
for (var i = 0, len = current.length; i < len; i++) {
current[i].classList.remove('current');
}
el.classList.add('current');
document.querySelector(el.hash).classList.add('current');
}
}, false);
.tab_content_n1 {
display: none;
}
.tab_content_n1.current {
display: block;
animation: fadeIn 1s;
}
a.current {
color: red;
}
#keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
<div class="tab_space">
<ul id="tabs_menu_n1" class="nav nav-tabs tabs_menu_n1 tab_body">
<li><a class="current" href="#M_n1">mai</a>
</li>
<li>red
</li>
<li id="hn1">hor
</li>
<li id="pbtn">+
</li>
</ul>
</div>
<div id="tab_n1" class="tab_n1">
<div class="tab_content_n1 current" id="M_n1">mai</div>
<div class="tab_content_n1" id="R_n1">red</div>
<div class="tab_content_n1" id="H1_n1">hor</div>
</div>
I have a div set as contenteditable and everything inside of that div can be edited. Now when I click on the div I automatically add a class selected (If visible prior I remove it and add it to the new selection) I have next and forward buttons so I can change my selection if I'm on using a tablet or smart phone.
Now here's where I need help.
So I selected the middle div and as I move my cursor to another child of #dynamic-storage I'm left with the problem of removing the class selected and adding it to the new child that's selected. (Not the span in the example as it's parent is a div. That's what I want selected as the div's in this example are the children of #dynamic-storage (ex. #dynamic-storage > div)
The snippet provided at the bottom of this post does not contain the arrows or menubar provided in the screenshot and fiddle links above as that code is not necessary at the given time of posting. I'm keeping this post focused on the one task being handling the .selected class for the focused child of #dynamic-storage.
$(document).ready(function() {
// Select Elements
var SelectElements = function() {
$("#dynamic-storage").children().on("mouseup touchend", function() {
if ( $(".selected").is(":visible") ) {
$(".selected").removeClass("selected");
}
$(this).addClass("selected");
});
};
// Clear Selection
var ClearSelection = function() {
$(".selected").removeClass("selected");
};
SelectElements();
// Handles Hotkeys
$(document).keyup(function(e) {
// Up & Down Arrow Keys To Select/Deselect Element in Editable
if (e.which === 38 || 40 ) {
if ( $(".selected").is(":focus") ) {
alert("correct");
} else if ( $(".selected").is(":blur") ) {
alert("incorrect");
}
}
});
});
/* Body */
#dynamic-storage {
position: absolute;
top: 0;
left: 0;
right: 0;
z-index: 0;
outline: 0;
}
#dynamic-storage .selected {
outline: 2px dotted #69f;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=9" />
<link type='text/css' rel='stylesheet' href="http://ajax.googleapis.com/ajax/libs/jqueryui/1/themes/smoothness/jquery-ui.css" />
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js"></script>
</head>
<body>
<div id="dynamic-storage" contenteditable="true">
<div class="header" align="center">
<h1>Welcome</h1>
<h5>My name is Michael.</h5>
<span>Hello world</span>
</div>
<div class="header selected" align="left">
<h1>Welcome</h1>
<h5>My name is Michael.</h5>
</div>
<div class="header" align="right">
<h1>Welcome</h1>
<h5>My name is Michael.</h5>
</div>
</div>
</body>
</html>
Fiddle: http://liveweave.com/uyz4VK
Fiddle: http://jsbin.com/kujuxofeju/1/edit?html,js,output
Element with attribute contenteditable='true' has all its content editable as in a single textarea. That is the reason why focus/blur event will not happen when you move cursor. Everywhere inside element with contenteditable='true' you are still in the same textarea not leaving or entering it.
The solution here is to deal with coursor positioning similar to textarea.
To get an object that represents current selection we use function:
var getSelection;
if (window.getSelection) {
// IE 9 and non-IE
getSelection = function() {
var sel = window.getSelection(), ranges = [];
if (sel.rangeCount) {
for (var i = 0, len = sel.rangeCount; i < len; ++i) {
ranges.push(sel.getRangeAt(i));
}
}
return ranges;
};
} else if (document.selection && document.selection.createRange) {
// IE <= 8
getSelection = function() {
var sel = document.selection;
return (sel.type != "None") ? sel.createRange() : null;
};
}
Then we need to do the next operations: remove class .selected from the first level children of #dynamic-storage, get element with cursor, and go up the DOM to find its parent closest to #dynamic-storage to add class .selected:
// Handles Hotkeys
$(document).keyup(function(e) {
// Up & Down Arrow Keys To Select/Deselect Element in Editable
if (e.which === 38 || 40 ) {
$('#dynamic-storage > div').removeClass('selected');
var selectedElem = getSelection()[0].commonAncestorContainer.parentElement;
$(selectedElem).closest('#dynamic-storage > div').addClass('selected');
}
});
Here is the working fiddle
Something along the lines of (try this in your main jQuery function) :
$("#dynamic-storage").children().each(function() {
$(this).on("focus", function() {
$(this).addClass("selected");
});
$(this).on("blur", function() {
$(this).removeClass("selected");
});
});
But if you edit the contents, you will loose the event handlers bound to them ...
I have a dynamically created navigation, where i can not make parent/child list for navigation.
I want to add a link named "More..." at the end of the list, according to available space. And then show all remaining elements as child of More...
For example if i have elements list1, list2, list3, ..... list10.
It will be displayed as list1, list2, list3, more... and rest of the links will be child of more...
I tried creating a script for this, and i think i am very close. But i have following 2 issues:
How to add UL around child list.
Sometimes "More..." is broken to next line.
Following is my JS code:
$(document).ready(function() {
var nav = $('ul');
var more = '<li>More...</li>';
nav.prepend( more );
var availableSpace = nav.innerWidth();
var list = 0;
var countedSpace = 0;
$('li').each(function(){
var current = $(this);
countedSpace = countedSpace+current.outerWidth();
if (countedSpace < availableSpace) {
list++;
}
})
var showInList = list; //Space available for xx no. of items.
var newList = [];
// Start at 2, don't include dynamically added more link.
for (i = 2; i < showInList; i++) {
newList.push($(nav).find("li:nth-child("+i+")"));
}
newList.push(more);
var childList = [];
for (i = showInList; i <= nav.children().length; i++) {
childList.push($(nav).find("li:nth-child("+i+")"));
}
//nav.empty();
nav.html(newList);
$(nav).find("li:last-child").append(childList);
});
jsfiddle: http://jsfiddle.net/alokjain_lucky/Lhh019ru/
1. How to add UL around child list.
Try creating a jquery UL object and then appending the li items to it. Like this:
var ulChildren = $("<ul/>").append(childList);
$(nav).find("li:last-child").append(ulChildren);
2. Sometimes "More..." is broken to next line.
This is happening because the li children are visible and stacking to the right, try adding
li ul{
display:none;
}
to test the correct layout, after step 1.
Here is an example of the above on JSFiddle, click on "More..." to toggle children visibility
Example code
I think this will accomplish what you're looking for:
var availableWidth= $('ul').innerWidth();
var totalWidth= $('<li class="more">More</li>').appendTo($('ul')).outerWidth();
$('li').each(function(index) {
totalWidth+= $(this).outerWidth();
if(totalWidth >= availableWidth) {
$('ul li:eq('+(index-2)+')').after(
$('.more').click(function() {
$('ul li:gt('+(index-1)+')').toggle()
})
);
$('ul li:gt('+(index-1)+')').css({
display: 'none'
});
return false;
}
});
var availableWidth= $('ul').innerWidth();
var totalWidth= $('<li class="more">More</li>').appendTo($('ul')).outerWidth();
$('li').each(function(index) {
totalWidth+= $(this).outerWidth();
if(totalWidth >= availableWidth) {
$('ul li:eq('+(index-2)+')').after(
$('.more').click(function() {
$('ul li:gt('+(index-1)+')').toggle()
})
);
$('ul li:gt('+(index-1)+')').css({
display: 'none'
});
return false;
}
});
ul {
padding:0px;
margin:0px;
border:1px solid #ccc;
overflow:hidden;
width: 500px;
}
li {
list-style:none;
float:left;
margin:10px;
border:1px solid #f1f1f1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li>a Home</li>
<li>b Services</li>
<li>c Meet our team</li>
<li>d work process</li>
<li>e About us</li>
<li>f Contact us</li>
<li>g Meet out team</li>
<li>h work process</li>
<li>i About us</li>
<li>j Contact us</li>
</ul>
totalWidth is initialized as the width of the More list item. I gave it a class of more, so it could be referred to within each.
When totalWidth is greater-or-equal-to availableWidth, .more is inserted in the appropriate position (index) of the ul.
The click handler toggles the display of list items at higher positions. Those higher-positioned list items are then hidden.
return false prevents each from continuing to run once this is done.
I have a list of photo on the page, each have an unique id, user can click on them to toggle select the photo, when they click the submit button, I need to send the array of selected photo ids to the back end, in the order that the photo was selected.
I think that the fastest way to track if a photo is selected is to use an object that use photo id as key, like:
var selected = {
"6272861": true,
"6272888": true
}
when the user unselect a photo, I just need to delete selected["6272861"].
But this will ignore the order, if I use an array to keep the selected photos:
var selected = ["6272861", "6272888"];
then when I need to unselect a photo, I have to loop through the array and delete the item.
Is there better ways? thanks.
Here is some JavaScript that does what you say:
window.addEventListener("load", function () {
"use strict";
var imgClick = function (elemSelected, elemThis) {
var idIndex;
if ((idIndex = imgSelected.indexOf(elemThis.id)) === -1) {
imgSelected.push(elemThis.id);
elemThis.className = "selected"
} else {
imgSelected.splice(idIndex, 1);
elemThis.className = "unselected";
};
console.log(elemSelected);
}
var imgDiv = document.getElementById("imgDiv");
var imgChildren = imgDiv.children;
var imgElements = [];
var imgSelected = [];
var i;
for (i = 0; i < imgChildren.length; i += 1) {
imgElements.push(imgChildren[i]);
imgChildren[i].addEventListener("click", function () {imgClick(imgSelected, this)});
}
});
Here is the associated HTML:
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<script type="text/javascript" src="imageSelect.js"></script>
<style type="text/css">
img.unselected {
border-color: black;
border-width: 1px;
border-style: solid;
}
img.selected {
border-color: red;
border-width: 3px;
border-style: solid;
}
</style>
<body>
<div id="imgDiv">
<img class="unselected" id="img01" src="intrepidWidgets.ico" title="Unselected"/>
<img class="unselected" id="img02" src="300px-Java_logo_svg.png" title="Unselected"/>
</div>
</body>
</html>
Here is a link that discusses the indexOf property of the Array global object. It may have compatibility problems with Internet Explorer before IE 9, but they have code to fix that:
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/indexOf
Here is a link to the working code. You need to open the console to see the resulting log (press F12 in Chrome):
http://www.quirkscode.com/flat/forumPosts/imgSelect/imageSelect.html
MDN also discusses addEventListener (search for that element name). It is the preferred way now of adding event listeners, but has compatibility issues with IE < 9:
As you seem to already know, objects do not keep the order so if the order is important, then you will want to use an array.
You can add an item to the end of the array with:
selected.push("6272898");
You can remove an item with a simple function:
function removeSelected(item) {
for (var i = selected.length - 1; i >= 0; i--) {
if (selected[i] === item) {
selected.splice(i, 1);
}
}
}
Note: This searches the array from back to front so when an item is removed, we don't have to correct/change the loop index.