apply text-decoration: line through to generated checkboxes - javascript

Im finishing up the last bit of a todo list app I am creating. Basically users generate todo tasks which show up on the screen along with a checkbox and trash can icon to the right of it. For the most part the app is working as it should. The last thing I need to do is have it that when a user clicks a checkbox, text-decoration:line through effect takes place and crosses out the corresponding list item. I used to have this working but I had to shift around some things so resizing the screen would look better. Now my old way wont work. Ill post some code and if anyone knows how I can get this working I would really appreciate it. Thanks everyone!
The input:checked + li css below is what was originally working before I had to rearrange the order of how list items were generated.
ul {
text-align:right; /*This pushes the checkbox/trash can right while the <li> in the js file floats the todo text left*/
list-style-type:none;
padding-left:0px; /*Makes up for not having the bullet point spacing on smaller screens*/
font-size:24px;
color:white;
font-weight:600;
}
li {
text-align:left;
}
input:checked + li { /*<<<<<------This is what I was using before and it worked*/
text-decoration:line-through;
}
.todo-item::after {
content: "";
clear: both;
display: table;
}
.todo-item {
text-align: right;
}
.todo-item .todo-label {
display: block;
float: left;
max-width: 80%; /* you can increase the size */
text-align: left;
/* you can use this props if you don't want another line
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden; */
}
</style>
</head>
<body>
<div class="header">
<div class="container" style="padding-top:50px;">
<div class="row justify-content-center"> <!--Input Box-->
<div class="col-sm-12 col-lg-8">
<h1>To-Do List</h1>
<div class="form-group">
<input type="text" class="form-control" id="task">
</div>
</div>
</div>
<div class="row"> <!--Add Button-->
<div class="col"></div>
<div class="col-xs-2" style="margin-right:15px; margin-top:30px;">
<button id="add" style="border-radius:50%; font-size:35px; width:65px;" class="btn btn-danger">+</button>
</div>
</div>
</div>
</div>
<div class="container text" style="display:inline-block;"> <!--ToDos-->
<div class="row justify-content-center" style="margin-top:20px;">
<div class="col-sm-12 col-sm-8">
<div id="todos"></div>
</div>
</div>
</div>
<script src="todo.js"></script>
</body>
</html>
Here is the javascript used to develop items for the todo list. Prior to rearranging, the checkbox was generated before the todo list item. Now, it was shifted to after. I thought I could just rearrange my css order or perhaps take out the li section and replace it with a class. I havent had much luck here.
function show() {
var todos = get_todos();
var html = '<ul>';
for(var i=0; i < todos.length; i++) {
html += '<li class="todo-item">' +
'<span class="todo-label">' + todos[i] + '</span>' +
'<input class="checkBox" type="checkbox">' +
'<button class="remove" id="' + i + '">' +
'<i class="fa fa-trash" aria-hidden="true"></i>' +
'</button>' +
'</li>';
};
html += '</ul>';
document.getElementById('todos').innerHTML = html;
var buttons = document.getElementsByClassName('remove');
for (var i=0; i < buttons.length; i++) {
buttons[i].addEventListener('click', remove);
};
}

A fairly simple way of adding the line-through effect when the checkbox is clicked and removing the effect when the checkbox is unclicked is using the toggle method to toggle a premade class with the line-through effect. This class should not be on by default because you don't want the line-through effect right away. When you click the checkbox, it will toggle the class on. When you unclick the checkbox, it will toggle the class off.
HTML should be something like:
<ul>
<li> Todo Item <input .....> </li>
Then create a CSS class for your code to toggle:
.lineThrough {
text-decoration: line-through;
}
The jQuery code would look like this:
$("ul").on("click", "li", function(){
$(this).toggleClass("lineThrough");
});

Related

Jquery .on click not registering first few clicks mobile?

I'm trying to build a product configurator that shows the total weight of all selections.
I've noticed on IOS and phones the #2 button need to be clicked multiple time before registering and the #1 button a couple of times. I've added cursor:pointer but the problem remains.
Is this just the nature of Jquery and mobile touch/tap? If you can see any issues with the code or have any suggestions please let me know.
https://jsfiddle.net/pdrj5vmo/9/
// Matches and shows Butts to Car index order.
let $cars = $('.car');
$('.butts').on('click', e => {
let $target = $cars.eq($(e.target).index()).show();
$cars.not($target).hide();
});
// Finds all Butts and calls `sumBoxes` onclick
const boxes = document.getElementsByClassName("butts");
for (let butts of boxes){ butts.addEventListener("click", sumBoxes); }
// sumBox Calculates each visible Box
function sumBoxes(event) {
var total = 0;
$('.box:visible').each(function() {
total += parseInt($(this).text());
});
$('.sum').html("Total : " + total); // Replaces contents of `.sum`
}
body {background: #eeeeee;}
.car {display:none;}
.box {float: left;font: bold 17px arial;text-align: center;margin: 10px 10px 20px 0;padding: 10px 25.54px;background: #fff;color: blue}
.butts {cursor:pointer; width:200px;height:40px;background:#fff; margin-bottom:10px; margin-right:10px; float:left;border:1px solid blue;}
.sum {clear:both;margin-top:40px;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="butts-container" style="float: left;width: 100%;">
<div class="butts">1</div>
<div class="butts">2</div>
</div>
<div class="car-container">
<div class="car">
<div class="box">1 CarBox</div>
</div>
<div class="car">
<div class="box">2 CarBox</div>
</div>
</div>
<div class="box">100 Box</div>
<div class="sum">Total</div>

elements in list not staying together on resize

I posted this a little earlier but deleted it because I was able to figure a little of it out. Im having an issue when resizing a screen with this todo list project im working on. Im using a bit of javascript that creates a list item every entry. The person types in a todo task and then a check box and remove icon is added. My issue is that on smaller screens, the checkbox and remove icon is jumping up a layer when a long named task is given. Im using bootstrap 4 to hold it all in place on my html side. My image should help clarify what I'm talking about. I think the javascript may be the issue.
Here is the list when on a medium screen. Looks correct with the checkbox/trash icon being to the right of the item.
Here is the issue when the screen gets smaller. The checkbox/trash icon goes up a line as the text breaks down. How can I make it stay on the first line as the text? Ive tried setting the "li" element to width="90%;" with the checkbox/remove icon taking up the remaining 10. It looks worse then. I'm really not sure. Ill attach the relevant code.
function show() {
var todos = get_todos();
var html = '<ul>';
for(var i=0; i < todos.length; i++) {
html += '<span><input class="checkBox" type="checkbox"><li style="float:left;">' + todos[i] + '</li>' + '<button class="remove" id="' + i + '"><i class="fa fa-trash" aria-hidden="true"></i></button></span><br/>';
};
html += '</ul>';
document.getElementById('todos').innerHTML = html;
var buttons = document.getElementsByClassName('remove');
for (var i=0; i < buttons.length; i++) {
buttons[i].addEventListener('click', remove);
};
}
body, html { /*makes the background image stretch the whole screen*/
height:100%;
}
body {
background-image:url('campingBackground.jpg');
background-repeat:no-repeat;
background-attachment:fixed;
background-position:center;
background-size:cover;
}
.checkBox {
margin-right:10px;
height:18px;
width:18px;
}
.checkBox:hover {
background-color:#C0C0C0;
}
.remove { /*Trash can button*/
color:white;
font-size:24px;
border:0;
padding:0;
background-color:transparent;
}
.remove:hover {
color:#C0C0C0;
}
ul {
text-align:right; /*This pushes the checkbox/trash can right while the <li> in the js file floats the todo text left*/
list-style-type:none;
padding-left:0px; /*Makes up for not having the bullet point spacing on smaller screens*/
font-size:24px;
color:white;
font-weight:600;
}
li {
text-align:left;
}
<div class="header">
<div class="container" style="padding-top:50px;">
<div class="row justify-content-center"> <!--Input Box-->
<div class="col-sm-12 col-lg-8">
<h1>To-Do List</h1>
<div class="form-group">
<input type="text" class="form-control" id="task">
</div>
</div>
</div>
<div class="row"> <!--Add Button-->
<div class="col"></div>
<div class="col-xs-2" style="margin-right:15px; margin-top:30px;">
<button id="add" style="border-radius:50%; font-size:35px; width:65px;" class="btn btn-danger">+</button>
</div>
</div>
</div>
</div>
<div class="container text"> <!--ToDos-->
<div class="row justify-content-center" style="margin-top:20px;">
<div class="col-sm-12 col-sm-8">
<div id="todos"></div>
</div>
</div>
</div>
First, having an ul list with items like span as child nodes is not correct, according to the HTML Specification for a list (ul) element:
The ul element represents a list of items, where the order of the items is not important — that is, where changing the order would not materially change the meaning of the document.
The items of the list are the li element child nodes of the ul element.
The problem is given because according to the name of the todo item, there is no space for the todo to fit.
I recommend this changes to your code as a possible solution:
var todos = [
'Lorem ipsun dolor sit amet',
'Answer a question related to JavaScript on StackOverflow',
'Another todo',
'A really long long todo to show this code working for todo with long long long names'
];
var html = '<ul>';
for(var i=0; i < todos.length; i++) {
html += '<li class="todo-item">' +
'<span class="todo-label">' + todos[i] + '</span>' +
'<input class="checkBox" type="checkbox">' +
'<button class="remove" id="' + i + '">' +
'<i class="fa fa-trash" aria-hidden="true"></i>' +
'</button>' +
'</li>';
};
html += '</ul>';
document.write(html);
/* https://www.w3schools.com/howto/howto_css_clearfix.asp */
.todo-item::after {
content: "";
clear: both;
display: table;
}
.todo-item {
text-align: right;
}
.todo-item .todo-label {
display: block;
float: left;
max-width: 80%; /* you can increase the size */
text-align: left;
/* you can use this props if you don't wan another line */
/* white-space: nowrap; */
/* text-overflow: ellipsis; */
/* overflow: hidden; */
}

a robust way to toggle item display in Jquery

I want to toggle whether to display an item I should do the following:
$(item).css("display", "none")
$(item).css("display", "block")
But this method is not robust enough, given that the item might be "display: flex" or "display: table".
I think in react, I can just delete that element and re-render it when I need to, but is there any simple way to do that using jQuery besides directly modify the html to delete that element?
Thanks.
you should use toggleClass() in case you are working with flex then it would be a better approach to keep the flex properties in a separate class and add/remove or in easy words toggle the flex class if you want to hide or show that container with defaults set to display:none in a separate class, in this way either the container is flex or table it works either ways see the example below
$(".show").on('click', function() {
if ($(this).siblings('.my-item').css('display') == 'flex') {
$(this).siblings('.my-item').toggleClass('myflex');
} else {
$(this).siblings('.my-item').toggleClass('myTable');
}
})
.my-item {
display: none;
}
.myflex {
display: flex;
background-color: #f8f8f8;
}
.myTable {
display: block;
background-color: #d8d8d8;
}
.container {
margin-top: 10px;
border: 5px dashed #c8c8c8;
}
.show {
padding: 10px;
cursor: pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<a class="show">TOGLLE THIS ITEM</a>
<div class="my-item myflex">1
</div>
</div>
<div class="container">
<a class="show">TOGLLE THIS ITEM</a>
<div class="my-item myflex">2
</div>
</div>
<div class="container">
<a class="show">TOGLLE THIS ITEM</a>
<div class="my-item myTable">TABLE DISPLAY
</div>
</div>
<div class="container">
<a class="show">TOGLLE THIS ITEM</a>
<div class="my-item myflex">3
</div>
</div>
<div class="container">
<a class="show">TOGLLE THIS ITEM</a>
<div class="my-item myflex">4
</div>
</div>
<div class="container">
<a class="show">TOGLLE THIS ITEM</a>
<div class="my-item myflex">5
</div>
</div>
You could also add a custom css class and switch them using below. This would also give a bit more control over styling.
$(item).addClass('display-none');
$(item).removeClass('display-none');
$(item).removeClass('display-none display-flex'); // For removing multiple classes
and for example the css properties would be like
.display-none{
display: none !important;
}
Why not just use jQuery's show/hide functions?
$(item).hide();
$(item).show();
hide function is roughly equivalent to calling .css( "display", "none" ), except that the value of the display property is saved in jQuery's data cache so that display can later be restored to its initial value. (from jQuery documentation)
$('#btnToggle').click(function(){
if($('#item').is(':visible'))
{
$('#item').hide();
}
else
{
$('#item').show();
}
$('#log').html("Current display state: " + $('#item').css('display'));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="btnToggle">toggle</button>
<div id="item" style="display: flex;">
flex div
</div>
<div id="log">
</div>
You can do a
$(item).css("display", "none")
and assign the flex or table value of the display property to any custom attribute, e.g. $(item).attr("disp_prop","flex") and on returning back to display you can do a simple.
$(item).css("display", $(item).attr("disp_prop"))

Trying to get jQuery to change a different img src when clicked

I've got 2 seperate divs that change background img src when clicked which works fine, but I would like it to change the other image its present with. E.g. div 1 is pressed and becomes "open", if div2 is "open" it then becomes closed. My jQuery is rather limited and have it functioning where it can change the image, but need to figure out how to apply the "closed" class to images that haven't just been clicked. Ideally it would use the attr() so I can add more later.
jQuery
$(".box").on("click", function() {
// need to make this function select the other div.
if ($(this).hasClass("closed")) {
$(this).addClass("open").removeClass("closed");
} else {
$(this).addClass("closed").removeClass("open");
}
var id = $(this).attr("data-id");
$(this).toggleClass("open");
$(".hideDivs").hide();
$("#" + id).show();
});
.container {
width: 640px;
height: 450px;
background-color: #eee;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);
}
.text-primary {
font-size: 14px;
text-align: center;
margin-bottom: 5px;
}
.box {
cursor: pointer;
width: 90px;
height: 180px;
display:block;
margin:auto;
background-image: url("http://res.cloudinary.com/dez1tdup3/image/upload/v1499052120/closed_vo1pn2.png");
}
.open {
background-image: url("http://res.cloudinary.com/dez1tdup3/image/upload/v1499052120/open_ihcmuz.png");
}
.closed {
background-image: url("http://res.cloudinary.com/dez1tdup3/image/upload/v1499052120/closed_vo1pn2.png");
}
.hideDivs {
display: none;
}
.panel-body {
padding: 10px;
margin-top: 5px;
}
.title {
font-weight: bold;
font-size: 14px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<div class="row">
<div class="col-xs-6">
<div class="box" data-id="divId1">
</div>
</div>
<div class="col-xs-6">
<div class="box" data-id="divId2">
</div>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<div class="panel panel-default hideDivs" id="divId1">
<div class="panel-body">
<span class="title">Practices for safe packaging of cooked foods</span>
<ul>
<li>Label and date all food.</li>
<li>Package high-risk food in small batches for refrigeration and return to refrigerated storage as soon as possible (within 20 minutes).</li>
<li>Store packaging products in a clean environment and protect from contamination.</li>
</ul>
</div>
</div>
<div class="panel panel-default hideDivs" id="divId2">
<div class="panel-body">
<span class="title">Practices for safe freezing of cooked foods</span>
<ul>
<li>When packaging food for freezing, cover or wrap, label and date (production and freezing date) all foods.</li>
<li>Freeze food in small quantities to ensure food is frozen quickly.</li>
<li>Do not overload freezer units and ensure air can circulate.</li>
<li>Do not freeze foods that have been cooked then refrigerated and reheated.</li>
</ul>
</div>
</div>
</div>
</div>
</div>
Please check the jsfiddle and let me know if you are looking something like this.
https://jsfiddle.net/314sybno/2/
$(".box").on("click", function() {
var id = $(this).attr("data-id");
if( id === 'divId1') {
$('div[data-id="divId2"]').addClass('closed').removeClass('open');
} else {
$('div[data-id="divId1"]').addClass('closed').removeClass('open');
}
// need to make this function select the other div.
if ($(this).hasClass("closed")) {
$(this).addClass("open").removeClass("closed");
} else {
$(this).addClass("closed").removeClass("open");
}
$(".hideDivs").hide();
$("#" + id).show();
});
This might be a better approach:
$(".box").on("click", function() {
// Hide all detail divs
$(".hideDivs").hide();
if ($(this).is(".closed")) {
// Close other open boxes
$(".box.open").removeClass("open").addClass("closed");
// Open this box and show the corresponding details div
$(this).removeClass("closed").addClass("open");
var id = $(this).attr("data-id");
$("#" + id).show();
} else {
// Close this box
$(this).removeClass("open").addClass("closed");
}
});
Also, I would recommend changing your HTML to have your 'box' elements also have a 'closed' class, so you do not repeat/need the CSS background attribute on the 'box' class.
See it working on this fiddle

Dynamically created table supposed to break if too long

I have a simple Jquery code to call a bunch of AJAX ping methods to find out if the system modules are up. This is generating a table row-by-row on every AJAX call result. The table looks pretty simple.
Now my problem is that the number of callable methods is growing and it might end up in a lot of scrolling, so I thought i set:
body {
max-height: 500px;
}
but the table won't break, and I still end up in scrolling a lot. Any Idea to solve this?
I replaced the method calls with a random OK/ERROR so you can run it in JSFiddle here.
// instead of AJAX call result just append random result
for (i = 0; i < 50; i++) {
$( "#resultTable" ).append( '<tr><td> TestWS </td>' +
(Math.random()<.5 ?
'<td class="ok"> OK </td></tr>' :
'<td class="error"> ERROR </td></tr>'
)
);
}
This dummy JQuery code is not important, only an example to show the problem, what I am looking for is to make this table break if it's too long.
Any suggestions are welcome. Thanks!
For the easiest way would be is to use a scrollable vertical table. So, you'll have a scroll bar and you can scroll through the table data.
To create a scrollable vertical table. You'll need set the display and overflow property.
table {
display: block;
height: 200px;
overflow-y: scroll;
}
For your convenience, I modified your Fiddle so that you can have a look.
So far one of the best options to use seems to be this:
Putting the table in a container and setting:
#container {
column-count:3;
-moz-column-count:3;
-webkit-column-count:3;
}
So it shows the table in multiple columns without much (or no) scrolling needed.
Fiddle
Any backdraws or major browser compatibility issues?
Here is another approach. Possibly flexbox is a better solution, but fwiw:
// instead of AJAX call result just append random result
var pageHeight = 200, cnt=1, oldcnt=0;
var endStr = '';
for (i = 0; i < 50; i++) {
$( "#div"+cnt ).find('table.resultTable').append( '\
<tr><td> TestWS </td>' +
(Math.random()<.5 ?
'<td class="ok"> OK </td></tr>' :
'<td class="error"> ERROR </td></tr>'
)
);
if ( $( "#div"+cnt ).find('table.resultTable').height() > pageHeight){
oldcnt = cnt;
cnt++;
$( "#container").append('<div id="div'+cnt+'"><table class="resultTable"><tr><th>Service</th><th>Result</th></tr></table>');
}
}
body {width:100%;max-height: 200px;}
th, td{padding:2px;border:1px solid;xwidth:50px;}
.resultTable th{background-color:#CCCCCC;font-weight:bold;}
.resultTable td.ok{background-color:#E1FFD8;font-weight:bold;}
.resultTable td.error{background-color:#FFB5B5;font-weight:bold;}
#container{width:100%;overflow:auto;border:1px solid orange;}
[id^=div]{max-width:120px;width:120px;float:left;margin-right:7px;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<div id="container">
<div id="div1">
<table class='resultTable'>
<tr><th>Service</th><th>Result</th></tr>
</table>
</div>
</div>
jsFiddle Demo to play with
Here's an alternative. You can use the tools from jQuery mobile to create a nice feature: collapsible headers. That way your users can isolate specific test results in logically arranged groupings.
Click / press the header to toggle visibility of the content beneath.
You can organize things just the way you need them.
<script src="http://demos.jquerymobile.com/1.4.5/js/jquery.js"></script>
<script src="https://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.js"></script>
<link rel="stylesheet" href="http://demos.jquerymobile.com/1.4.0/css/themes/default/jquery.mobile-1.4.0.min.css" />
<style type="text/css">
li div { padding: 2px; border: 1px solid; float: left; width: 150px }
.ui-collapsible-content .ui-filterable{ display: none; }
li { background-color: #CCCCCC; font-weight: bold; }
li div.ok { background-color: #E1FFD8; font-weight: bold; }
li div.error { background-color: #FFB5B5; font-weight: bold; }
.ui-li-static.ui-collapsible > .ui-collapsible-heading { margin: 0; }
.ui-li-static.ui-collapsible { padding: 0; }
.ui-li-static.ui-collapsible > .ui-collapsible-heading > .ui-btn { border-top-width: 0; }
.ui-li-static.ui-collapsible > .ui-collapsible-heading.ui-collapsible-heading-collapsed > .ui-btn, .ui-li-static.ui-collapsible > .ui-collapsible-content { border-bottom-width: 0; }
</style>
<div data-role="collapsible" data-theme="b" data-content-theme- "b">
<h2>First Category</h2>
<ul data-role="listview" data-filter="true">
<li><div class="title">TestWS1</div>
<div class="ok"> OK </div>
</li>
<li><div class="title">TestWS2</div>
<div class="error"> ERROR </div>
</li>
<li><div class="title">TestWS3</div>
<div class="ok"> OK </div>
</li>
<li><div class="title">TestWS4</div>
<div class="error"> ERROR </div>
</li>
</ul>
</div>
<div data-role="collapsible" data-theme="b" data-content-theme- "b">
<h2>Second Category</h2>
<ul data-role="listview" data-filter="true">
<li><div class="title">TestWS10</div>
<div class="ok"> OK </div>
</li>
<li><div class="title">TestWS11</div>
<div class="error"> ERROR </div>
</li>
<li><div class="title">TestWS12</div>
<div class="ok"> OK </div>
</li>
<li><div class="title">TestWS13</div>
<div class="error"> ERROR </div>
</li>
</ul>
</div>

Categories

Resources