I have a ul consisting of several li's in it. Now I wanted to add Edit And Delete option infront of every li so that it can be Edited or Deleted on click.
How can i do this ?
Thanks in Advance for any help :)
See this DEMO
$('ul li').each(function () {
$(this).append('<a class="delete" href="#">Delete</a> Edit')
});
$('ul li a.delete').on('click', function () {
$(this).parent().remove();
return false;
});
$('ul li a.edit').on('click', function () {
var val = $(this).siblings('span').html();
if (val) {
$(this).parent().prepend('<input type="text" class="txt" value="' + val + '" />');
$(this).siblings('span').remove();
$(this).html('Update');
} else {
var $txt = $(this).siblings().filter(function() { return $(this).hasClass('txt') });
$(this).parent().prepend('<span class="lead justified">' + $txt.val() + '</span>');
$txt.remove();
$(this).html('Edit');
}
return false;
});
I strongly suggest you use Jquery or another library to handle cross browser issues. Anyway, here is the solution with pure javascript... it should work in all modern browsers recent versions.
SOLUTION DEMO
HTML
<ul class="fa-ul">
<li>
<span> BE/ BTech/ MCS </span>
<button class="remove">Delete</button>
<button class="edit">Edit</button>
</li>
<li>
<span> Solid </span>
<button class="remove">Delete</button>
<button class="edit">Edit</button>
</li>
<li>
<span> Strong </span>
<button class="remove">Delete</button>
<button class="edit">Edit</button>
</li>
<li>
<span> Sharp </span>
<button class="remove">Delete</button>
<button class="edit">Edit</button>
</li>
<li>
<span> Ability</span>
<button class="remove">Delete</button>
<button class="edit">Edit</button>
</li>
<li>
<span> Deal problems</span>
<button class="remove">Delete</button>
<button class="edit">Edit</button>
</li>
<li>
<span> Strong </span>
<button class="remove">Delete</button>
<button class="edit">Edit</button>
</li>
<li>
<span> Excellent </span>
<button class="remove">Delete</button>
<button class="edit">Edit</button>
</li>
</ul>
JS
var removeClassElements = document.getElementsByClassName('remove');
for(var i = 0; i < removeClassElements.length; i++){
var element = removeClassElements[i];
element.addEventListener('click', remove);
}
var editClassElements = document.getElementsByClassName('edit');
for(var i = 0; i < editClassElements.length; i++){
var element = editClassElements[i];
element.addEventListener('click', edit);
}
function remove() {
var li = this.parentNode;
var ul = li.parentNode;
ul.removeChild(li);
}
function edit() {
var li = this.parentNode;
var span = li.children[0];
span.setAttribute('contenteditable', true);
span.focus();
}
PS: You don't need class="lead justified" in each li element. You can use a CSS rule like this:
.fa-ul li span:first-child {...}
You can use CSS trick to perform inplace edit on span's and jQuery#remove() for deleting li's.
Idea is to hide the text when Edit is clicked and show textbox and vice-versa on click of Delete.
$('button.edit').click(function(){
var label_element = $(this).parent().find('span'),
input_element = $(this).parent().find('input');
label_element.addClass('editing');
input_element.val(label_element.text());
input_element.addClass('editing');
});
$('button.delete').click(function(){
$(this).parent().remove();
});
$('input').blur(function(){
var label_element = $(this).parent().find('span');
label_element.text($(this).val());
$(this).removeClass('editing');
label_element.removeClass('editing');
});
Fiddle DEMO
<ul class="fa-ul">
<li><span class="lead justified"> BE/ BTech/ MCS </span>DeleteEdit</li>...
The function edit(this) is given incorrectly and this links to <a>Edit</a>.
You should add id property to the <span>.
<li><span class="lead justified" id="foo"> BE/ BTech/ MCS </span>DeleteEdit</li>
<script>
function edit(target) {
target.contenteditable = true;
}
</script>
You need do change some changes in your markups, You can take <div> instead of <span> and can apply HTML5's attribute contenteditable
Sample Markup
<li>
<div class="lead justified">BE/ BTech/ MCS</div>
Delete
Edit
</li>
Script
Edit
function edit(elem){
$(elem).siblings('div.lead').attr('contenteditable',true);
}
Delete
function remove(elem){
$(elem).closest('li').remove(); // Deletes li
return false;
}
Fiddle Demo
Related
I have this code that will console.log the innerHTML of the list element that is clicked, it works perfectly
But I wanted to only console.log the innerHTML of the span element with class "x" that is inside the list
how can I do this?
function myfunction() {
let items = document.querySelectorAll("#ol li"),
array = [];
for (var i = 0; i < items.length; i++) {
array.push(items[i].innerHTML);
}
for (var i = 0; i < items.length; i++) {
items[i].onclick = function() {
console.log(this.innerHTML)
}
};
}
<ol id="ol">
<li>
<span class="x">hello</span>
<span class="xx">testing</span>
</li>
<li>
<span class="x">hello2</span>
<span class="xx">testing2</span>
</li>
<li>
<span class="x">hello3</span>
<span class="xx">testing4</span>
</li>
<li>
<span class="x">hello4</span>
<span class="xx">testing4</span>
</li>
</ol>
<button onclick="myfunction()">click</button>
Rather than placing a listener on each li, you can take advantage of event delegation, placing a single handler on the ol:
<ol id="ol">
<li>
<span class="x">hello</span>
<span class="xx">testing</span>
</li>
<li>
<span class="x">hello2</span>
<span class="xx">testing2</span>
</li>
<li>
<span class="x">hello3</span>
<span class="xx">testing4</span>
</li>
<li>
<span class="x">hello4</span>
<span class="xx">testing4</span>
</li>
</ol>
<button id="button">click</button>
'use strict';
const button = document.querySelector('#button');
const findLI = el => {
if (el.tagName.toLowerCase() === 'li') {
return el;
}
return findLI(el.parentElement);
};
const registerItemsClickHandler = () => {
const ol = document.querySelector('#ol');
ol.onclick = event => {
const li = findLI(event.target);
console.log(li.innerHTML);
};
};
button.onclick = registerItemsClickHandler;
Notice that we only register a single click handler (on the ol) and that we can use event.target to determine the specific element onto which the event was dispatched. It's also worth noting that a child any depth of the tree can be a dispatch target, so we can use the recursive findLI() function to find the first parent that is an li, if el itself isn't one.
<li id="123">
<span id="tst">test</span>
</li>
I have the above code. I would like to get the li id on click on span id. Is it possible to do so?
Most easily to do with jQuery:
$('span').click(function() {
var parentId = $(this).closest('li').attr('id');
console.log(parentId);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<li id="123">
<span id="tst">test</span>
</li>
Or as plain vanilla js:
document.getElementById('tst').onclick = function() {
var parentId = this.parentElement.id;
console.log(parentId);
};
<li id="123">
<span id="tst">test</span>
</li>
I have my ul : li list with a span named as badge which contains the total number of unread messages. So i want to shuffle all the li items with the highest number on top of the list and lowest or none to the last. I tried many solutions but still can`t get it. Another point is the count gets update live so the list should also shuffle live. Here is the code that i tried till now.
My HTML Code
<li>
<span class="badge" style="display:none" id="61_T">0</span>
</li>
<li>
<span class="badge" style="display:none" id="62_T">5</span>
</li>
<li>
<span class="badge" style="display:none" id="63_T">10</span>
</li>
<li>
<span class="badge" style="display:none" id="64_T">0</span>
</li>
Here is my JS Code
var prev_index = 0;
var curr_index = 0;
var curr_val = 0;
var prev_val = 0;
var lists = $('#items li');
var msg_count = [];
$('#items li').each(function(){
var current_index = $(this).index();
var count = $(this).find('.badge').text();
msg_count.push([current_index,count]);
});
updateli();
function updateli(){
$.each(msg_count,function(key,value){
var str = value.join('-');
var sep = str.split('-');
curr_index = sep[0];
curr_val = parseInt(sep[1]);
if(curr_val > prev_val){
$("#items li:eq("+curr_index+")").siblings().eq(curr_index).after(lists.siblings(':eq('+prev_index+')'));
}
prev_index = curr_index;
prev_val = curr_val;
});
}
What i did here is created an array with li index and unread count number. After than looped the array and used jQuery function to swap the elements but nothing seems to work. Any help will really appreciated. Thanks in advance.
This sorts the list without using JQuery
function sortItems(containerSelector, itemSelector, countSelector, asc) {
let container = document.querySelector(containerSelector);
let items = [].slice.call(container.querySelectorAll(itemSelector));
items.sort(function(currItem, nextItem) {
var currCountElement = currItem.querySelector(countSelector);
var nextCountElement = nextItem.querySelector(countSelector);
if(!currCountElement) return 1;
if(!nextCountElement) return -1;
var currCount = parseInt(currCountElement.textContent || -1);
var nextCount = parseInt(nextCountElement.textContent || -1);
var order = currCount - nextCount;
return asc?-order:order;
});
items.forEach(function(item) { container.appendChild(item)});
}
// demo code
[].slice.call(document.querySelectorAll('.sortButton')).forEach(function(button) {
button.addEventListener('click', function(e) { sortItems('.items', 'li', '.badge', this.classList.contains('-desc')) });
});
<ul class="items">
<li>
2
<span class="badge" style="display:none" id="61_T">2</span>
</li>
<li>
5
<span class="badge" style="display:none" id="62_T">5</span>
</li>
<li>
10
<span class="badge" style="display:none" id="63_T">10</span>
</li>
<li>
1
<span class="badge" style="display:none" id="63_T">1</span>
</li>
<li>
0
<span class="badge" style="display:none" id="64_T">0</span>
</li>
<li>
none
<span class="badge" style="display:none" id="64_T"></span>
</li>
<li>
no badge
</li>
</ul>
<button class="sortButton">asc</button>
<button class="sortButton -desc">desc</button>
Edit: made it a method
try the code below please.jquery return a array-like object so you can sort elements by sort(..) method,and then replace all the li.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li>
<span class="badge" id="61_T">0</span>
</li>
<li>
<span class="badge" id="62_T">5</span>
</li>
<li>
<span class="badge" id="63_T">10</span>
</li>
<li>
<span class="badge" id="64_T">0</span>
</li>
</ul>
<script>
var badges = $('.badge').parent().sort(function (a, b) {
return parseInt($(b).find('span').text()) - parseInt($(a).find('span').text());
});
badges.closest('ul').empty().append(badges);
</script>
I have a component which have buttons and list both of which perform events on click. I need a common way to get the ancestor element for these elements. The structure looks like
<div class='a'>
<button class ='b' data-name="hello">
<span class ='c'>clickMe
<span>somehting</span>
</span>
<button>
<ul class ='d'>
<li data-name="about">
<span class ='e'>something here
<span>somehting</span>
</span>
</li>
<li data-name="home">
<span class ='e'>something elser here
<span>somehting</span>
</span>
</li>
</ul>
</div>
I try to get the element button and li because I need to get data-name information.
e.target is the element that was clicked
var targetel = goog.dom.getAncestorByClass(e.target,null,class??);
Not sure how to get the correct element irrespective if its a button or li. Do i need to add a unique class to all the elements ?
Just use e.currentTarget
var result = document.querySelector('#result');
var clickables = document.querySelectorAll('button, li');
//add click listener to elements
for (var i = 0, l = clickables.length; i < l; i++) {
clickables[i].addEventListener('click', getDataName);
}
function getDataName(e) {
var dataName = e.currentTarget.getAttribute('data-name');
result.textContent = dataName;
}
<div class='a'>
<button class ='b' data-name="hello">
<span class ='c'>clickMe
<span>somehting</span>
</span>
</button>
<ul class ='d'>
<li data-name="about">
<span class ='e'>something here
<span>somehting</span>
</span>
</li>
<li data-name="home">
<span class ='e'>something elser here
<span>somehting</span>
</span>
</li>
</ul>
</div>
<div id="result">data-name of clicked element goes here</div>
https://api.jquery.com/parents/
Use the jquery.parents("li") function. it will select all the parents that match your css filter. so you can do
var parentli = targete1.parents("li");
var button = targete1.parents("div").children[0];
Or something similar to that.
EDIT:
Not sure why i got downvoted, here is my idea in action.
maybe press f12 to inspect element and look at the console log.
var onClick = function () {
var parentEl = $(this).parents("button, li")[0];
console.log(parentEl);
$("#result")[0].innerText = parentEl.getAttribute("data-name");
};
$('span.c').click(onClick);
$('li span.e').click(onClick);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class='a'>
<button class='b' data-name="hello">
<span class='c'>clickMe
<span>something</span>
</span>
</button>
<ul class ='d'>
<li data-name="about">
<span class ='e'>something here
<span>somehting</span>
</span>
</li>
<li data-name="home">
<span class ='e'>something elser here
<span>something</span>
</span>
</li>
</ul>
</div>
<div id="result">result goes here</div>
I want to display a message when the <section> is “empty”. Inside the <section>, I can have an unknown number of <ul> and inside it an unknown number of <li>. When I click on “x” button it removes that <li>. Here’s the HTML:
<section>
<ul>
<li class="row row--half-padding-top-bottom">
<span>October 2013</span>
</li>
<li class="notification notification--new">
<span>
<span>Franck Ribery</span>
<span>Bayern Munich</span>
</span>
<span class="accept-ignore-container">
<button class="js-animate-onclick--parent" title="Accept">Accept</button>
<button class="js-connect-invite--ignore">×</button>
</span>
</li>
<li class="notification notification--new">
<span>
<span>Arjen Robben</span>
<span>Bayern Munich</span>
</span>
<span class="accept-ignore-container">
<button class="js-animate-onclick--parent" title="Accept">Accept</button>
<button class="js-connect-invite--ignore">×</button>
</span>
</li>
</ul>
<ul>
<li class="row row--half-padding-top-bottom">
<span>September 2013</span>
</li>
<li class="notification notification--new">
<span>
<span>Franck Ribery</span>
<span>Bayern Munich</span>
</span>
<span class="accept-ignore-container">
<button class="js-animate-onclick--parent" title="Accept">Accept</button>
<button class="js-connect-invite--ignore">×</button>
</span>
</li>
</ul>
</section>
I want to ignore the <li> element that shows the date (hence the “empty”, because it’s not really empty). To do that, I check if the <li> has a class .notification. If it has, increase the counter. I do that upon clicking the “x” button that has a class .js-connect-invite--ignore:
var counter;
$('.js-connect-invite--ignore').on('click touchstart', function() {
var ul = $(this).closest('section').children();
$(ul).each(function() {
var li = $(this).children();
counter = 0;
$(li).each(function() {
if ($(this).is('.notification')) {
console.log('yes');
counter ++;
}
})
})
console.log(counter);
})
See demo: http://jsfiddle.net/CCECK/
However, it’s not working properly as the logic is wrong. Do I need to add two counters?
How can upon clicking “x” check all the other elements and if that is the last <li class="notification"> display an alert? Thanks!
Basically you reset the counter within each ul, so you always end up with the number of li elements of the last ul, which is 1. So if you reset the counter before iterating all the ul elements and also remove the .notification element on clicking the button then you can figure out when only one has been left.
You can try the following,
http://jsfiddle.net/Gd2kS/
js
var counter;
$('.js-connect-invite--ignore').on('click touchstart', function() {
var ul = $(this).closest('section').children();
counter = 0;
$(ul).each(function() {
var li = $(this).children();
$(li).each(function() {
if ($(this).is('.notification')) {
console.log('yes');
counter ++;
}
});
});
console.log(counter);
if(counter==1){
alert("last one left!!");
}else{
$(this).parents('.notification').remove();
}
})
EDIT - response to comments (hiding element with class .visuallyhidden instead of removing element)
var counter;
$('.js-connect-invite--ignore').on('click touchstart', function() {
var ul = $(this).closest('section').children();
counter = 0;
$(ul).each(function() {
var li = $(this).children();
$(li).each(function() {
if ($(this).is('.notification')
&& !$(this).is('.visuallyhidden')) {/*<- modify the condition*/
console.log($(this));
console.log('yes');
counter ++;
}
});
});
console.log(counter);
if(counter==1){
alert("last one left!!");
}else{
/*modify the removal*/
//$(this).parents('.notification').remove();
$(this).parents('.notification').addClass("visuallyhidden");
}
})