Does anybody know why the button wont react to input when clicked? I want the click to bring up a prompt and then use the text from the prompt and append it into the hmtl as a list item with the same css as the other list items.
$(".btn").click(function() {
var text = prompt('What do you need to do?')
var txt1 = $("<li id="
listItem "><p></p></li>").text(text);
$("#itemList").append(txt1);
});
body {
background: #bff0ff;
}
li {
display: inline-block;
float: left;
padding: 5px;
}
#list {
list-style-type: none;
}
#itemList {
list-style-type: none;
}
#listItem {
width: 250px;
height: 75px;
border-radius: 5px;
background: #5ABCB9;
}
#listItem p {
font-family: curive, sans-serif;
text-align: center;
font-size: 20px;
color: #
}
.btn {
height: 50px;
width: 50px;
border-radius: 50%;
border: 1px;
font-size: 40px;
background: #63E2C6;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.0/jquery.min.js"></script>
<input type="button" class="btn" value="+" />
<ul id="itemList">
<li id="listItem">
<p>
Study for exams.
</p>
</li>
</ul>
If you are trying to add more li elements to your existing ul, try the following ( since with your current implementation p element would be ignored when rendered ) :
$(".btn").click(function() {
var text = prompt('What do you need to do?')
var $li = $('<li/>',{ 'class' : 'listItem' })
var $p = $('<p/>', { 'text' : text })
$($li).append($p);
$("#itemList").append($li);
});
Example : https://jsfiddle.net/9av0c8z3/
There's a few things you need to do. First of those should be to clean up the errors in your JS, i.e. this isn't a proper string:
"<li id="listItem"><p></p></li>"
Once you hit the second double quote (") you're no longer working with a string and it thinks listItem is a variable.
I personally use single quotes for strings (').
'<li id="listItem"><p></p></li>'
Then you'll have to redo how you're using IDs in CSS. IDs should be unique and not re-used, that's what a class is for. So I've changed instances of id="listItem" to class="listItem" and updated the CSS from #listItem to .listItem.
Also, when you do this $( '<li id="listItem"><p></p></li>' ).text( text ); the text gets added to the li and the p is not created. So create the p first, add the text to it then append it to the li.
After that I think you're good to go.
var $itemList = $( '#itemList' );
$( '.btn' ).click( function( e ) {
var text = prompt( 'What do you need to do?' ),
p = $( '<p>', { text: text } ),
li = $( '<li>', { "class": 'listItem' } ).append( p );
$itemList.append( li );
} );
body {
background: #bff0ff;
}
#itemList,
#itemList li {
list-style: none;
}
li {
float: left;
padding: 5px;
}
.listItem {
width: 250px;
height: 75px;
border-radius: 5px;
background: #5ABCB9;
}
.listItem p {
font-family: curive, sans-serif;
text-align: center;
font-size: 20px;
}
.btn {
height: 50px;
width: 50px;
border-radius: 50%;
border: 1px;
font-size: 40px;
background: #63E2C6;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.0/jquery.min.js"></script>
<input type="button" class="btn" value="+">
<ul id="itemList">
<li class="listItem">
<p>
Study for exams.
</p>
</li>
</ul>
Related
I've got a few divs, and it's a dashboard kinda website so I need to update it everyday.
I can manually edit the HTML and all but that's you know...inefficient.
Each div has a ul element in it, and everyday I need to add a few li elements.
I've tried a JavaScript function that appends li elements and I'll add it in the code snippet too. But still, it's kinda temporary because if I delete that line of code in my js file the added li element will also disappear. So I'm looking for a way to append li elements to an unordered list permanently, and it would be nice to have a way to delete them too when they get really old.
function append(ul, data) {
try {
ul.appendChild(document.createElement("li")).innerHTML = data;
} catch (e) {
console.error(e);
console.log("error boi");
}
}
append(document.getElementById("ul-1"), "door")
div {
background-color: cyan;
height: 300px;
width: 500px;
}
<div id="1">
div 1
<br />
<ul id="ul-1">
<li>reeeeeeeee</li>
<li>ramen ramen ramen ramen</li>
<li>..........................</li>
<!-- have to append few li items every day-->
</ul>
</div>
<br>
<div id="2">
div 2
<br />
<ul id="ul-2">
<li>ok</li>
<li>ravioli ravioli ravioli ravioli</li>
<li>..........................</li>
</ul>
</div>
Note ↓:
This piece of code just shows an example of how you can add or remove items easily from and to the lists!
As #Chris G and #L.K. Kabilan mentioned, to store data you either need a Database or in the Local Storage. However, by storing data in the Local Storage you're taking a risk of losing the data because it's stored only in the browser.
// Get the elements
var input = document.getElementById('input');
var btn = document.getElementById('btn');
var select = document.getElementById('select');
var selected = select.options[select.selectedIndex].value;
// Delete the item of the clicked 'X' icon
function delLi(){
var del = document.querySelectorAll('li span');
for (var i = 0; i < del.length; i++){
del[i].addEventListener('click', (e) => {
e.target.parentElement.remove();
});
}
}
// Get the selected option
select.addEventListener('change', () => {
selected = select.options[select.selectedIndex].value;
});
// Wrap the input value in an item and append it to the selected list
btn.addEventListener('click', (e) => {
var val = input.value;
if(val == '' || val.length <= 0){
e.preventDefault();
} else {
var li = `<li><span>×</span><p>${val}</p></li>`;
document.getElementById(selected).innerHTML += li;
delLi();
}
});
delLi();
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.wrapper {
background-color: aqua;
width: 500px;
margin: 50px auto;
border-radius: 5px;
padding: 10px;
}
ul {
list-style-type: none;
line-height: 1.5;
}
ul::before {
content: attr(aria-label);
font-weight: bold;
font-size: 20px;
}
li {
display: flex;
align-items: center;
}
li span {
font-size: 18px;
font-weight: bold;
margin-right: 10px;
cursor: pointer;
}
form {
margin: 0 auto;
width: 500px;
background-color: rgb(233, 208, 17);
padding: 10px;
}
#input {
height: 30px;
width: 100%;
border-radius: 5px;
border: none;
padding: 0 10px;
display: block;
margin-bottom: 10px;
}
#btn {
width: 100px;
height: 34px;
background-color: green;
color: white;
border: none;
border-radius: 5px;
display: inline-block;
cursor: pointer;
}
<main>
<div class="wrapper" id="wrapper-1">
<ul id="ul-1" aria-label="List 1">
<li><span>×</span><p>Item 1</p></li>
<li><span>×</span><p>Item 2</p></li>
<li><span>×</span><p>Item 3</p></li>
<li><span>×</span><p>Item 4</p></li>
</ul>
</div>
<div class="wrapper" id="wrapper-2">
<ul id="ul-2" aria-label="List 2">
<li><span>×</span><p>Item 1</p></li>
<li><span>×</span><p>Item 2</p></li>
</ul>
</div>
<form action="">
<input id="input" type="text">
<select name="" id="select">
<option value="ul-1">List 1</option>
<option value="ul-2">List 2</option>
</select>
<input id="btn" type="button" value="Submit">
</form>
</main>
I guess u can use a JSON file to store and retrieve data, or u can go for PHP to get & retrieve data, yet u will be needing a Database, if I'm not wrong, using JSON would be more efficient.(If I'm wrong correct me)
check this link below https://www.w3schools.com/whatis/whatis_json.asp#:~:text=JSON%20stands%20for%20JavaScript%20Object,describing%22%20and%20easy%20to%20understand
Hope this answer helped u.
I am creating a way to edit dynamic content. I found a question on here that got me started in terms of changing text (spans in my case) into input fields.
Currently, I can't figure out the following issue. When you click "Edit" (on the right side) the input fields replace the span (this is what I want), but when when you click outside of the input the input fields add new span fields instead of replacing the input fields.
I am wanting the styling and the fields to constantly stay in their original place.
Does anyone see what I am doing wrong?
var projID = '';
//Obtaining ID and Editing the projects
$(document.body).on('click', '.recEdit', '[data-editable]', function() {
projID = $(this).parent().data('recid');
console.log('Project ID is..... ' + projID);
var $el = $(this).parent().children().find('span');
var $input = $('<input/>').val( $el.text() );
$el.replaceWith( $input );
var save = function(){
var $p = $('<span data-editable class="recBaseFormat" />').text( $input.val() );
$input.replaceWith( $p );
};
/**
We're defining the callback with `one`, because we know that
the element will be gone just after that, and we don't want
any callbacks leftovers take memory.
Next time `p` turns into `input` this single callback
will be applied again.
*/
$input.one('blur', save).focus();
});
.recentProjectCont {
width: 98%;
height: 85px;
border-bottom: 1px solid #ccc;
padding: 10px 0;
margin: 0 10px;
display: block;
position: relative;
}
.recentProjectImg {
width: 100px;
height: 85px;
display: inline-block;
vertical-align: top;
}
.recentProjectImg img {
width: 100%;
height: 100%;
object-fit: cover;
}
.recProjInfoCont {
display: inline-block;
vertical-align: top;
width: 80%;
height: 100%;
margin-left: 20px;
}
.recInfoCont1, .recInfoCont2 {
height: 100%;
display: inline-block;
vertical-align: top;
}
.recInfoCont1 {
width: 40%;
}
.recInfoCont2 {
width: 52%;
text-align: right;
}
.recBaseFormat, .projectViews {
letter-spacing: .1rem;
line-height: 1.4em;
color: #2f2f2f;
display: block;
margin-bottom: 5px;
}
.recProjName {
font-size: 1.1rem;
font-family: 'Muli', sans-serif;
}
.recInfoStat, .projectViews {
font-size: .7rem;
font-family: 'Nunito', sans-serif;
}
.recEdit {
position: absolute;
top: 20%;
left: 97%;
cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="recentProjectCont">
<div class="recProjInfoCont">
<div class="recInfoCont1">
<span class="recProjName recBaseFormat" data-editable>Name</span>
<span class="recInfoStat recBaseFormat recAlt" data-editable>Alt</span>
<span class="recInfoStat recBaseFormat recCat" data-editable>Category</span>
</div>
<div class="recInfoCont2">
<span class="recInfoStat recBaseFormat" data-editable>Status</span>
<span class="recInfoStat recBaseFormat" data-editable>Creator</span>
</div>
</div>
<div class="recEdit">Edit</div>
</div>
This code could definitely be optimized, but it should get you going in the right direction. There were a few issues with your code. The issue I mentioned above, which is that your selector was only targeting the last span element within the parent element. We can solve that by using the each method to loop over every span within the parent. Another issue is that you were losing the classes for your spans when you were replacing them with inputs. I've solved that by saving a list of classes for each span before replacing them with an input so that they can be reapplied when they are converted back to spans. Finally, you were firing the save function for all inputs on blur of any input, meaning that the user would only be able to edit one span and then when they clicked out, all inputs would have been converted back. Instead, now it will only convert back when you unfocus each specific input.
var projID = '';
//Obtaining ID and Editing the projects
$(document.body).on('click', '.recEdit', '[data-editable]', function() {
projID = $(this).parent().data('recid');
console.log('Project ID is..... ' + projID);
$(this).parent().children().find('span').each(function() {
var classList = $(this).attr('class');
$input = $('<input/>').val($(this).text());
$(this).replaceWith($input);
$input.on('blur',function() {
$(this).replaceWith('<span data-editable class="' + classList + '">' + $(this).val() + '</span>');
});
});
});
.recentProjectCont {
width: 98%;
height: 85px;
border-bottom: 1px solid #ccc;
padding: 10px 0;
margin: 0 10px;
display: block;
position: relative;
}
.recentProjectImg {
width: 100px;
height: 85px;
display: inline-block;
vertical-align: top;
}
.recentProjectImg img {
width: 100%;
height: 100%;
object-fit: cover;
}
.recProjInfoCont {
display: inline-block;
vertical-align: top;
width: 80%;
height: 100%;
margin-left: 20px;
}
.recInfoCont1, .recInfoCont2 {
height: 100%;
display: inline-block;
vertical-align: top;
}
.recInfoCont1 {
width: 40%;
}
.recInfoCont2 {
width: 52%;
text-align: right;
}
.recBaseFormat, .projectViews {
letter-spacing: .1rem;
line-height: 1.4em;
color: #2f2f2f;
display: block;
margin-bottom: 5px;
}
.recProjName {
font-size: 1.1rem;
font-family: 'Muli', sans-serif;
}
.recInfoStat, .projectViews {
font-size: .7rem;
font-family: 'Nunito', sans-serif;
}
.recEdit {
position: absolute;
top: 20%;
left: 97%;
cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="recentProjectCont">
<div class="recProjInfoCont">
<div class="recInfoCont1">
<span class="recProjName recBaseFormat" data-editable>Name</span>
<span class="recInfoStat recBaseFormat recAlt" data-editable>Alt</span>
<span class="recInfoStat recBaseFormat recCat" data-editable>Category</span>
</div>
<div class="recInfoCont2">
<span class="recInfoStat recBaseFormat" data-editable>Status</span>
<span class="recInfoStat recBaseFormat" data-editable>Creator</span>
</div>
</div>
<div class="recEdit">Edit</div>
</div>
Finally, as others have mentioned, another option would be to use the contenteditable attribute on your spans. This is an HTML solution for editing HTML elements that are not editable by default. It essentially does the same thing you're trying to do with Javascript, but it's much cleaner. It also has very good browser support. One drawback to this solution would be that it will not be immediately clear to the user that the element is editable like it would be with an actual button that says "Edit." But there are some solutions for that as well.
<span contenteditable="true">You can edit me</span>
You could use juste the contenteditable attribute toggle each click !
I have a custom drop down menu, in which I am using to fill a div with the selections when .is(":checked"). The divs are filling correctly, but I am having some trouble figuring out how to remove the selections in the div.
I think the reason I am having troubles is because the div is only filling with the inputs value. I am unsure of how to remove this value from the proposal-type div and then repopulate the drop list with the item removed, when clicking the x icon. So essentially, exactly the opposite as filling it.
Does anyone see what I have to do to remove the values in the proposal-type div, when clicking the x-icon for the drop-item-selected divs and then how to show the input again in the drop down?
Sorry if any of this is unclear. Please ask any questions if you need more clarity.
$( '#proposal-type' ).click( function () {
$( '#proposal-type-drop' ).addClass( 'active' );
} );
$( '.drop-item-input' ).on( 'change', function () {
var proposalVal = "";
var proposalHtml = "";
$( '.drop-item-input' ).each( function () {
if ( $( this ).is( ":checked" ) ) {
proposalVal += $( this ).val();
proposalHtml += '<div class="drop-item-selected"><span class="drop-item-close"></span>' + $( this ).val() + '</div>';
$( this ).closest( 'label' ).fadeOut();
};
$( '#proposal-type' ).val( proposalVal ).html( proposalHtml );
$( '#proposal-type-drop' ).removeClass( 'active' );
} );
//values
var type = $( '.drop-item-input:checked' ).map( function () {
return $( this ).val();
} ).get().join( ', ' );
console.log( type );
} );
//Uncheck/remove
$( '.drop-item-close' ).click( function () {
$( this ).is( ":checked" ) === false;
$( this ).closest( 'label' ).fadeIn();
$( this ).closest( '.drop-item-selected' ).fadeOut();
} );
#proposal-type {
border: 1px solid #858585;
height: 20px;
}
#proposal-type-drop {
width: 45%;
height
display: none;
position: absolute;
}
#proposal-type-drop.active {
background: rgba(0, 0, 0, 1);
display: block;
height: auto;
z-index: 1;
}
.drop-item {
color: #FFF;
font-size: .9rem;
padding: 5px;
background: #000;
display: block;
width: 100%;
cursor: pointer;
}
.drop-item-close {
display: inline-block;
background-image: url("https://www.wpclipart.com/signs_symbol/alphabets_numbers/outlined_alphabet/white_capitol/capitol_X_white.png");
background-size: 10px 10px;
background-repeat: no-repeat;
height: 10px;
width: 10px;
margin-right: 10px;
cursor: pointer;
}
.drop-item-input {
display: none;
}
.drop-item-selected {
background: blue;
padding: 5px;
font-size: .9rem;
width: auto;
display: inline-block;
margin: 0 3px;
}
.proposal-text {
width: 95%;
display: block;
height: 6em;
margin: 1.5% 2% 2.5% 2%;
!important
}
#proposal-check {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="proposal-type" name="proposal_type" class="proposal-input" data-text="Make Selection"></div>
<div id="proposal-type-drop">
<label class="drop-item">A<input type="checkbox" class="drop-item-input" value="A"></label>
<label class="drop-item">B<input type="checkbox" class="drop-item-input" value="B"></label>
<label class="drop-item">C<input type="checkbox" class="drop-item-input" value="C"></label>
</div>
Your code was too difficult to understand, so I simplified it a little bit.
converted the input blocks to regular html divs.
converted the checkboxes to spans
on click event, I populated a hidden input array.
disabled inputs won't send data to the server, so I used this as an advantage for this kind of situation.
// click event for selectable proposals, assigned them to document to keep the events after attach/detach
$(document).on("click", ".available-proposals .proposal", function(event) {
// after fadeout
$(this).fadeOut("medium", function() {
// set the new container
var newContainer = $(this).closest(".proposal-container").find(".selected-proposals");
// detach the item and move it to the container of the selected ones
$(this).detach().appendTo(newContainer).fadeIn().css("display", "inline-block");
// remove the disabled attribute, so it can send data
$(this).find("input[type='hidden']").removeAttr("disabled");
});
// remove sub event triggers
event.preventDefault();
});
// click event for the X close labels in the selected proposals
$(document).on("click", ".selected-proposals .proposal .close", function(event) {
// select the main proposal object, because the event sender is the close label.
var $this = $(this).parent(".proposal");
// find the new container (old container which has available items)
var newContainer2 = $this.closest(".proposal-container").find(".available-proposals");
// after fadeout
$this.fadeOut("medium", function() {
// detach the item and move it to the container of the selectable ones
$this.detach().appendTo(newContainer2).fadeIn().css("display", "block");
// add the disabled attribute to the input, so it can't send data to the server
$(this).find("input[type='hidden']").attr("disabled","disabled");
});
// remove sub event triggers.
event.preventDefault();
});
.available-proposals .close {
display: none;
}
.selected-proposals .close {
display: block;
font-size: 11px;
background: #eee;
color: #000;
font-weight: bold;
float: right;
padding: 2px;
border-radius: 10px;
}
.available-proposals .proposal {
background: darkblue;
color: white;
width: 100px;
height: 20px;
display: block;
}
.selected-proposals .proposal {
background: cyan;
color: black;
display: inline-block;
width: 100px;
height: 20px;
border: 1px solid black;
padding: 3px;
margin: 3px;
}
.available-proposals {}
.selected-proposals {
border: 1px solid black;
min-height: 20px;
position: relative;
}
.selected-proposals .proposal {
display: inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="proposal-container">
<div class="selected-proposals"></div>
<div class="available-proposals">
<div class="proposal">A<span class="close">X</span>
<input type="hidden" name="selected_proposals[]" value="A" disabled="disabled" />
</div>
<div class="proposal" data-value="B">B<span class="close">X</span>
<input type="hidden" name="selected_proposals[]" value="B" disabled="disabled" />
</div>
<div class="proposal" data-value="C">C<span class="close">X</span>
<input type="hidden" name="selected_proposals[]" value="C" disabled="disabled" />
</div>
</div>
</div>
I am trying to create a disappearing drop down menu that disappears into the top of the page, and you can only see the word 'open'. This opens the the menu, the word open changes to the word close which when clicked makes the menu disappear again. Help would be much appricated.
<html>
<head>
<title>dropdown</title>
<link rel="stylesheet" type="text/css" href="dropdown_css.css">
<script type = "text/javascript">
function navagate(menu) {
var panel = document.getElementById(menu),maxh = "-362px", navg = document.getElementById('navag');
if (panel.style.marginTop == maxh){
panel.style.marginTop = "0px";
navag.innerHTML = "Close";
}
else {
panel.style.marginTop = maxh;
navag.innerHTML = "Open";
}
}
window.onload = function(){panel.style.marginTop = "-362px";}
</script>
<body>
<div id = "panel">
<ul>
<li>CIT</li>
<li>Blackboard</li>
<li>Mcomms</li>
<li>Tables</li>
<li>Exams</li>
</ul>
<div id ="sections_button">
<a onclick = "navigate ('panel')" id = "navag">Open</a>
</div>
</div>
</body>
</body>
</html>
#panel {
width : 160px;
height: 130px;
background-color: gray;
margin-left: 30px;
margin-top:20px;
}
#panel li {
list-style-type: none;
}
Here, I've made a JS fiddle that may help you out: http://jsfiddle.net/942z0nhh/ I did not play around with the styling at all.
A few things I noticed:
You're making some mistakes that I think you wouldn't make if you indented properly. Take a look here, where you closed your body twice:
<a onclick = "navigate ('panel')" id = "navag">Open</a>
</div>
</div>
</body>
</body>
Second, you have some spelling mistakes:
<a onclick = "navigate ('panel')" id = "navag">Open</a>
vs
function navagate(menu) {
You can see there that your function would never be called because of it.
Lastly, your 'open' and 'close' a here:
<a onclick = "navigate ('panel')" id = "navag">Open</a>
Was within the div your function was overwriting. The function would change it to 'close'- but then it wouldn't be visible to the user anyway! I moved it above, which I hope makes sense.
Please let me know if you have any other questions, or if I misunderstood.
You could also do it only with CSS. It's the "css checkbox hack". I'm having it not like you want it but it is pretty close. Changing the text from open to close should be also possible.
At the moment, I don't know how to move the open/close label below the ul list.
*, html {
padding: 0px;
font-family: sans-serif;
}
/* Checkbox Hack */
input[type=checkbox] {
position: absolute;
display: none;
}
label {
display: block;
cursor: pointer;
content: "close";
}
/* Default State */
#wrapper {
display: block;
background: gray;
color: white;
text-align: center;
}
/* Toggled State */
input[type=checkbox]:checked ~ #menu {
display: block;
background: lightgray;
color: black;
top:0px;
}
.menuToggle ul{
display: none;
width: 100%;
}
#menu {
padding-top: 5px;
margin: 0px;
list-style: none;
}
<div id="wrapper">
<div class="menuToggle">
<label for="toggle-1">open</label>
<input type="checkbox" id="toggle-1"/>
<ul id="menu">
<li>CIT</li>
<li>Blackboard</li>
<li>Mcomms</li>
<li>Tables</li>
<li>Exams</li>
</ul>
</div>
</div>
With jQuery you could do it like the example below.
I think it is now almost like you wanted it. Maybe some styling improvements are required.
With the css hack I couldn't manage the text change. With js you have more possibilities. You could also improve/modify the animations.
$(function() {
var $menuButton = $('#openButton');
var $menu = $('#menu');
var btnToggleAnim = function() {
$menuButton.animate({opacity: 'toggle'}, "fast");
};
var menuToggleAnim = function() {
$('#menu').animate({
height:'toggle',
//opacity: 'toggle'
}, { duration: "slow" });
};
$('#closeButton,#openButton').on('click', function() {
menuToggleAnim();
btnToggleAnim();
});
});
*, html {
padding: 0px;
font-family: sans-serif;
}
a {
text-decoration:none;
}
#openButton {
display:block;
background: gray;
color: #fff;
text-decoration: none;
border: 2px solid lightgray;
border-radius: 15px;
}
#closeButton{
display: block;
background: gray;
color: #fff;
text-align: center;
border: 2px solid lightgray;
border-bottom-left-radius: 13px;
border-bottom-right-radius: 13px;
}
#wrapper {
display: block;
text-align: center;
}
#menu {
display: none;
background: lightgray;
color: black;
padding-top: 5px;
margin: 0px;
list-style: none;
}
#menu {
color: #000;
text-decoration: none;
border: 2px solid lightgray;
border-radius: 15px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="wrapper">
open
<ul id="menu">
<li>CIT</li>
<li>Blackboard</li>
<li>Mcomms</li>
<li>Tables</li>
<li>Exams</li>
<li>close</li>
</ul>
</div>
I've got a simple to-do list app. To-do items are inserted by jQuery as <li> items. When they're checked off, they're removed from #todolist and prepended to #donelist. I want to let the user replace to-do items they've accidentally checked off, hence the .on handler for #donelist .checkbox elements, but it's not working. I've been puzzling over this for an embarrassingly long amount of time. How can I get the click handler working for #donelist .checkboxes?
HTML:
<div id="topform">
<input type="text" id="task" placeholder=" New task...">
</div>
<ul id="todolist">
</ul>
<ul id="donelist">
</ul>
JS:
$('#todolist').on('click', '.checkbox', checkTask);
$('#donelist').on('click', '.checkbox', replaceTask);
$('input').keypress(function (e) {
if (e.which == 13) {
addTask(e);
}
});
function addTask(e) {
taskToAdd = $('#task').val();
var listItem = "<li><span class='todotask'>" + taskToAdd + "</span><div class='checkbox'></div></li>";
$('#todolist').prepend(listItem);
}
function checkTask() {
var listItem = $(this).parent();
listItem.remove();
$('#donelist').prepend(listItem);
}
function replaceTask() {
alert('hey buddy');
}
Full CSS:
html,
body {
margin: 0;
padding: 0;
background-color: #313131;
font-family: 'Helvetica', sans-serif;
}
#task {
width: 98%;
margin: 5px auto 7px auto;
padding: 0;
display: block;
height: 45px;
border: none;
border-radius: 2px;
font-size: 25px;
background-color: #F7F7F7;
}
ul {
margin: 0 auto 0 auto;
padding: 0;
width: 98%;
}
li {
list-style-type: none;
padding: 0;
margin: 5px auto 0 auto;
width: 100%;
height: 45px;
line-height: 45px;
position: relative;
font-size: 25px;
border-radius: 2px;
background-color: #F7F7F7;
}
#donelist li {
opacity: .5;
text-decoration: line-through;
}
.todotask {
margin-left: 7px;
}
.checkbox {
height: 31px;
width: 31px;
border-radius: 2px;
background-color: #C1C1C1;
position: absolute;
right: 7px;
top: 7px;
}
checkTask() works just fine, which is what really confuses me. checkTask() is called when the user clicks on a dynamically inserted element (a div in a li that's inserted by addTask(). Why doesn't replaceTask() fire as well?
Having the corresponding HTML in the OP would have helped, so I've had to guess a bit about how the structure, but here's a working example of what I think you're looking for:
HTML
<h1>ADD</h1>
<input id="task"></input>
<button id="add">Add</button>
<h1>TODO</h1>
<ul id="todolist">
<li><span class='todotask'>" Take out the garbage "</span><div class='checkbox'></div></li>
<li><span class='todotask'>" Do the dishes "</span><div class='checkbox'></div></li>
</ul>
<h1>DONE</h1>
<ul id="donelist">
</ul>
CSS
.checkbox{
width: 15px;
height: 15px;
background-color: black;
display: inline-block;
cursor: pointer;
}
JavaScript inside document.ready()
$('#todolist').on('click', '.checkbox', checkTask);
$('#donelist').on('click', '.checkbox', replaceTask);
$("#add").click(addTask);
function addTask(e) {
taskToAdd = $('#task').val();
var listItem = "<li><span class='todotask'>" + taskToAdd + "</span><div class='checkbox'></div></li>";
$('#todolist').prepend(listItem);
}
function checkTask() {
var listItem = $(this).parent();
listItem.remove();
$('#donelist').prepend(listItem);
}
function replaceTask() {
var listItem = $(this).parent();
listItem.remove();
$('#todolist').prepend(listItem)
}