I'm trying to make a to-do list with an edit button, that when clicked, will make added items editable, but am having trouble. I have the button created and everything, but when I click it nothing happens. Any advice would be greatly appreciated!
JavaScript
function editItem(){
var parent = $(this).parent();
if (!parent.hasClass('edit')) {
parent.addClass('edit');
}else if (parent.hasClass('edit')) {
var editTask = $(this).prev('input[type="text"]').val();
var editLabel = parent.find('label');
editLabel.html(editTask);
parent.removeClass('edit');
}
$(function(){
$(document).on('click', 'edit', editItem)
});
Looks like you are targeting <edit>, you are supposed to use .edit:
$(function(){
$(document).on('click', '.edit', editItem);
});
Working Snippet
$(function () {
function addItem () {
// append to the list
$("#todo-items").append('<li><span>' + $("#todo").val() + '</span> <small>Edit • Delete</small></li>');
// clear the text
$("#todo").val("");
}
$("#todo").keydown(function (e) {
// if enter key pressed
if (e.which == 13)
addItem();
});
// on clicking the add button
$("#add").click(addItem);
// delegate the events to dynamically generated elements
// for the edit button
$(document).on("click", 'a[href="#edit"]', function () {
// make the span editable and focus it
$(this).closest("li").find("span").prop("contenteditable", true).focus();
return false;
});
// for the delete button
$(document).on("click", 'a[href="#delete"]', function () {
// remove the list item
$(this).closest("li").fadeOut(function () {
$(this).remove();
});
return false;
});
});
* {font-family: 'Segoe UI'; margin: 0; padding: 0; list-style: none; text-decoration: none;}
input, li {padding: 3px;}
#todo-items small {display: inline-block; margin-left: 10px; padding: 2px; vertical-align: bottom;}
#todo-items span:focus {background-color: #ccf;}
<script src="https://code.jquery.com/jquery-1.11.3.js"></script>
<input type="text" id="todo" />
<input type="button" value="Add" id="add" />
<ul id="todo-items"></ul>
Related
I have a list to add a class, but just items after add by input works with toggle. The items in the code don't work.
I wonder if is something related to "this" property too.
Link to CodePen.
https://codepen.io/kennedyrmenezes/pen/BaQRXMq
li.addEventListener("click", function() {
var finished = this.classList.toggle("done");
var removeButton = document.createElement("button");
removeButton.classList.add("deleteButton");
if (finished) {
removeButton.appendChild(document.createTextNode("remove"));
removeButton.classList = "deleteButton";
li.appendChild(removeButton);
removeButton.addEventListener("click", function() {
this.parentElement.remove();
});
} else {
this.getElementsByClassName("deleteButton")[0].remove();
}
})
If you look at the code that you have written, you are only attaching the event handlers to the newly created li nodes.
To get around it, you can attach the event handers to all existing li elements on page load or you can bind the event handlers once using the concept of event delegation. I find the 2nd approach to be cleaner as you don't have to worry about adding handlers when after a new li element is added to the DOM.
I see the following issues in your code.
Not attaching the click handler to existing li elements.
Not removing the click handler for the li or the button when they are being removed ( this can cause memory leaks in the app ).
var button = document.getElementById("enter");
var input = document.getElementById("userinput");
var ul = document.querySelector("ul");
var $body = document.querySelector('body');
// attach event handlers using event delegation.
function removeButtonHandler() {
this.parentElement.remove();
}
$body.addEventListener('click', function(e) {
const $target = e.target;
// if target is not li, do nothing
if ($target.tagName !== 'LI') {
return;
}
var finished = $target.classList.toggle("done");
var removeButton = document.createElement("button");
removeButton.classList.add("deleteButton");
if (finished) {
removeButton.appendChild(document.createTextNode("remove"));
removeButton.classList = "deleteButton";
$target.appendChild(removeButton);
removeButton.addEventListener("click", removeButtonHandler);
} else {
var $liRemoveButton = $target.querySelector('button');
if($liRemoveButton) {
// Also remove the handler for the delete button
$liRemoveButton.removeEventListener("click", removeButtonHandler);
$target.removeChild($liRemoveButton);
}
}
});
function inputLength() {
return input.value.length;
}
function creatListElement() {
var li = document.createElement("li");
li.appendChild(document.createTextNode(input.value));
ul.appendChild(li);
input.value = "";
}
function addListAfterClick() {
if (inputLength() > 0) {
creatListElement();
}
}
function addListAfterKeypress(event) {
if (inputLength() > 0 && event.keyCode === 13) {
creatListElement();
}
}
button.addEventListener("click", addListAfterClick);
input.addEventListener("keypress", addListAfterKeypress);
li {
color: black;
}
h1,
p {
color: black;
}
button {
color: white;
background: #1C3144;
padding: 10px;
border-radius: 3px;
border-style: none;
}
input {
border-radius: 3px;
padding: 10px;
}
.testingIt {
text-decoration-line: line-through;
}
.deleteButton {
background-color: #A31420;
color: #fff;
border-radius: 3px;
margin: 20px;
border-style: none;
}
.done {
text-decoration: line-through #A31420;
}
<body>
<h1>Shopping List</h1>
<p id="first">Get it done today</p>
<input id="userinput" type="text" placeholder="enter items">
<button id="enter">Enter</button>
<ul>
<li>Notebook</li>
<li>Jello</li>
<li>Spinach</li>
<li>Rice</li>
<li>Birthday cake</li>
<li>Candles</li>
</ul>
</body>
That because you only listen click event for only dymanic added li element.
You should add event listenner for hard-code elements also. In example below I show a alert when click to li item
document.querySelectorAll('li').forEach(liItem => {
liItem.addEventListener("click", function() {
alert('click');
});
})
https://codepen.io/1412108/pen/OJbgJEW?editors=1010
I was creating a dropdown with jquery, HTML and CSS. I want to close the dropdown when the user clicks outside of dropdown. But it's not working fine.
JS
function _drpdntest() {
$(".drpdn-click").click(function(){
var _drpdn_container = $(this).attr("data-drpdn-click");
var _drpdn_content = $('[data-drpdn-content="'+_drpdn_container+'"]');
_drpdn_content.toggleClass("drpdn-show");
_drpdn_content.siblings().removeClass("drpdn-show");
$(document).click(function(event){
_drpdn_content.removeClass("drpdn-show");
});
$(this, _drpdn_content).click(function(event){
event.stopPropagation();
});
});
}
// Run Component Function
$(document).ready(function(){
_drpdntest();
});
HTML
<button class="drpdn-click" data-drpdn-click="main">CLICK</button>
<div class="drpdn-content drpdn-body" data-drpdn-content="main">
Main
</div>
CSS
.drpdn-content {
z-index: 1000;
position: absolute;
display:none;
overflow: hidden;
}
.drpdn-content.drpdn-show {
display: block;
}
This is because you have not added stopPropagation() for button click. Due to which on button click it is triggering document click.
Also $(this, _drpdn_content) should be $(_drpdn_content, this) or simply remove this while adding stopPropagation.
Here second parameter provides context in which selector search will get performed, in short second parameter is parent and you are saying to search all childs matching with selector provided in first parameter.
function _drpdntest() {
$(".drpdn-click").click(function(e) {
var _drpdn_container = $(this).attr("data-drpdn-click");
var _drpdn_content = $('[data-drpdn-content="' + _drpdn_container + '"]');
_drpdn_content.siblings().removeClass("drpdn-show");
_drpdn_content.addClass("drpdn-show");
$(_drpdn_content).click(function(event) {
event.stopPropagation();
});
$(document).click(function() {
_drpdn_content.removeClass("drpdn-show");
});
e.stopPropagation();
});
}
// Run Component Function
$(document).ready(function() {
_drpdntest();
});
.drpdn-content {
z-index: 1000;
position: absolute;
display: none;
overflow: hidden;
}
.drpdn-content.drpdn-show {
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button class="drpdn-click" data-drpdn-click="main">CLICK</button>
<div class="drpdn-content drpdn-body" data-drpdn-content="main">
Main
</div>
This should be what you want, based on what you said in the comment
It now shows on the first click, and it doesn't hide when you click on the option.
function _drpdntest() {
$(".drpdn-click").click(function() {
var $this = $(this)
var _drpdn_container = $(this).attr("data-drpdn-click");
var _drpdn_content = $('[data-drpdn-content="' + _drpdn_container + '"]');
_drpdn_content.toggleClass("drpdn-show");
$(document).click(function(event) {
if (event.target != $this[0] && event.target != _drpdn_content[0]) {
_drpdn_content.removeClass("drpdn-show");
}
});
$(this, _drpdn_content).click(function(event) {
event.stopPropagation();
});
});
}
// Run Component Function
$(document).ready(function() {
_drpdntest();
});
.drpdn-content {
z-index: 1000;
position: absolute;
display: none;
overflow: hidden;
}
.drpdn-content.drpdn-show {
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button class="drpdn-click" data-drpdn-click="main">CLICK</button>
<div class="drpdn-content drpdn-body" data-drpdn-content="main">
Main
</div>
I'm using Tooltipster to show a list of items that the user can click so as to enter the item into a textarea. When a tooltip is created, I get its list of items with selectors = $("ul.alternates > li");
However, each time a tooltip is opened the item clicked will be inserted a corresponding number of times; for example if I've opened a tooltip 5 times then the item clicked will be inserted 5 times. I've tried deleting the variable's value after a tooltip is closed with functionAfter: function() {selectors = null;} but that had no effect.
I have a Codepen of the error here that should make it clearer.
// set list to be tooltipstered
$(".commands > li").tooltipster({
interactive: true,
theme: "tooltipster-light",
functionInit: function(instance, helper) {
var content = $(helper.origin).find(".tooltip_content").detach();
instance.content(content);
},
functionReady: function() {
selectors = $("ul.alternates > li");
$(selectors).click(function() {
var sampleData = $(this).text();
insertText(sampleData);
});
},
// this doesn't work
functionAfter: function() {
selectors = null;
}
});
// Begin inputting of clicked text into editor
function insertText(data) {
var cm = $(".CodeMirror")[0].CodeMirror;
var doc = cm.getDoc();
var cursor = doc.getCursor(); // gets the line number in the cursor position
var line = doc.getLine(cursor.line); // get the line contents
var pos = {
line: cursor.line
};
if (line.length === 0) {
// check if the line is empty
// add the data
doc.replaceRange(data, pos);
} else {
// add a new line and the data
doc.replaceRange("\n" + data, pos);
}
}
var code = $(".codemirror-area")[0];
var editor = CodeMirror.fromTextArea(code, {
mode: "simplemode",
lineNumbers: true,
theme: "material",
scrollbarStyle: "simple",
extraKeys: { "Ctrl-Space": "autocomplete" }
});
body {
margin: 1em auto;
font-size: 16px;
}
.commands {
display: inline-block;
}
.tooltip {
position: relative;
opacity: 1;
color: inherit;
}
.alternates {
display: inline;
margin: 5px 10px;
padding-left: 0;
}
.tooltipster-content .alternates {
li {
list-style: none;
pointer-events: all;
padding: 15px 0;
cursor: pointer;
color: #333;
border-bottom: 1px solid #d3d3d3;
span {
font-weight: 600;
}
&:last-of-type {
border-bottom: none;
}
}
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.25.2/theme/material.min.css" rel="stylesheet"/>
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/235651/jquery-3.2.1.js"></script>
<script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/235651/tooltipster.bundle.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.25.2/codemirror.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.25.2/addon/mode/simple.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.25.2/addon/hint/show-hint.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.25.2/addon/scroll/simplescrollbars.js"></script>
<div class="container">
<div class="row">
<div class="col-md-6">
<ul class="commands">
<li><span class="command">Hover for my list</span><div class="tooltip_content">
<ul class="alternates">
<li>Lorep item</li>
<li>Ipsum item</li>
<li>Dollar item</li>
</ul>
</li>
</div>
</ul>
</div>
<div class="col-md-6">
<textarea class="codemirror-area"></textarea>
</div>
</div>
</div>
Tooltipster's functionReady fires every time the tooltip is added to the DOM, which means every time a user hovers over the list, you are binding the event again.
Here are two ways to prevent this from happening:
Attach a click handler to anything that exists in the DOM before the tooltip is displayed. (Put it outside of tooltipspter(). No need to use functionReady.)
Example:
$(document).on('click','ul.alternates li', function(){
var sampleText = $(this).text();
insertText(sampleText);
})
Here's a Codepen.
Unbind and bind the event each time functionReady is triggered.
Example:
functionReady: function() {
selectors = $("ul.alternates > li");
$(selectors).off('click').on('click', function() {
var sampleData = $(this).text();
insertText(sampleData);
});
}
Here's a Codpen.
You are binding new clicks every time.
I would suggest different code style but in that format you can just add before the click event
$(selectors).unbind('click');
Then do the click again..
I have a form that if you click on the input field giving it focus the submit button displays.
However the issue I'm having is that when you try to click on the submit button it disappears as the focus has been removed from the input.
Here is my code:
<form method="post" id="subForm" class="clearfix">
<input id="fieldEmail" placeholder="email address" type="email"/>
<button type="submit"><i class="arrow"></i></button>
</form>
$('#fieldEmail').focus(function () {
$(this).next().addClass('visible');
}).blur(function () {
$(this).next().removeClass('visible');
});
And here is a JSFiddle
What is the best way to keep the toggling of class 'visible' but allow me to click the submit button?
It has to do with the order of events.
You can use mousedown to detect where the focus moves to because it triggers before the blur:
(function () {
var submit_focus = false;
$('#fieldEmail').focus(function () {
$(this).next().addClass('visible');
}).blur(function () {
if (submit_focus) {
submit_focus = true;
} else {
$(this).next().removeClass('visible');
}
});
$('#submit').mousedown(function () {
submit_focus = true;
});
}());
http://jsfiddle.net/cnLon9k3/4/
I suggest to put a check inside the function which hides the button and see if the input field has some value (if yes, you wouldn´t want to hide the button, or?)
e.g:
$('#fieldEmail').focus(function () {
$(this).next().addClass('visible');
}).blur(function () {
if($(this).val() === ""){
$(this).next().removeClass('visible');
}
});
We can have a check that on blur of textfield, the new focused element is button or not.
$('#fieldEmail').focus(function () {
$(this).next().addClass('visible');
}).blur(function () {
if(!event.relatedTarget||event.relatedTarget.type!='submit')
$(this).next().removeClass('visible');
});
form {
color:#333;
position: relative;
}
input {
padding:0 5px 5px;
text-align: center;
border:none;
text-transform: uppercase;
font-size:12px;
width:170px;
margin-left:15px;
float:left;
letter-spacing: 2px;
}
button {
display: none;
background: #ff0000;
border:none;
}
.arrow {
background:#ff0000;
width:15px;
height:15px;
display: block;
}
.visible {
display:block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form method="post" id="subForm" class="clearfix">
<input id="fieldEmail" placeholder="email address" type="email"/>
<button type="submit"><i class="arrow"></i></button>
</form>
I would suggest to capture each click event on document and if the target of that event is not submit button or email input then hide the submit button as below and remove the blur event from input
$(document).on('click',function(e){
if(e.target.type!="submit" && e.target.type !="email")
{
$('#fieldEmail').next().removeClass('visible')
}
});
DEMO HERE
How can I activate a menu tab after refreshing?
Here are my code
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js"></script>
<style>
.menu{width: 600px; height: 25; font-size: 18px;}
.menu li{list-style: none; float: left; margin-right: 4px; padding: 5px;}
.menu li:hover, .menu li.active {
background-color: #f90;
}
</style>
</head>
<body>
<ul class="menu">
<li><a href='#'>One</a></li>
<li><a href='#'>Two</a></li>
<li><a href='#'>Three</a></li>
<li><a href='#'>Four</a></li>
</ul>
<script type="text/javascript">
var make_button_active = function()
{
//Get item siblings
var siblings =($(this).siblings());
//Remove active class on all buttons
siblings.each(function (index)
{
$(this).removeClass('active');
}
)
//Add the clicked button class
$(this).addClass('active');
}
//Attach events to menu
$(document).ready(
function()
{
$(".menu li").click(make_button_active);
}
)
</script>
Can anyone tell me How to resolve this issue ?
Just like #Johan said, store your last active tab in a localStorage or cookie. Since there is no noticeable difference in performance between the two. I suggest you use localStorage because it's much easier to use. Like this:
function make_button_active(tab) {
//Get item siblings
var siblings = tab.siblings();
//Remove active class on all buttons
siblings.each(function(){
$(this).removeClass('active');
})
//Add the clicked button class
tab.addClass('active');
}
//Attach events to menu
$(document).ready(function(){
if(localStorage){
var ind = localStorage['tab']
make_button_active($('.menu li').eq(ind));
}
$(".menu li").click(function () {
if(localStorage){
localStorage['tab'] = $(this).index();
}
make_button_active($(this));
});
});
Check out this fiddle.