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");
}
})
Related
I have to loop through a ol and then get each of the li and then remove the text and add "<a" element to it.
Following is the html that is rendered:
<ol class="progress">
<li class="list-group-item text-muted list-group-item-success active">
General Information<span>1</span>
</li>
</ol>
I want to remove all the classes except "active" and then wrap the text with General Information
Like below
<ol class="progress">
<li class="active">
General Information<span> 1</span>
</li>
</ol>
I have tried to loop through the Ol using the script below but it seems to not find anything
$('ol.progress').each(function (i, li) {
var listItem = li;
var lm = $(li).text();
console.log(lm);
});
I see you are using JQuery - so let's stick to this.
You are looping over the ol but you want to loop over the ol's lis.
So replace
$('ol.progress').each....
by
$('ol.progress li').each....
You can remove all classes with the .removeClass() without any parameters.
But as you want to preserve the active-class you have to preserve this attribute - in my version of the code (see below) I will use a variable for this.
In addition you want to replace the HTML-part and not the text-part - so your snippet would read
$('ol.progress li').each(function () {
var is_active = false;
is_active = $(this).hasClass('active');
$(this).removeClass();
if(is_active){
$(this).addClass('active');
}
var newcontent = '' + $(this).html() + "";
$(this).html(newcontent);
});
With vanilla js:
document
.querySelectorAll('ol.progress > *') // all children of <ol> with class .progress
.foreach(elem => {
elem.className = 'active'
elem.innerHTML = `${elem.innerHTML}`
})
With jquery, as you can see, I check if the element has a class, then I remove all the classes and add active if it had it.
$('ol.progress li').each(function(i, li) {
var listItem = li;
if ($(li).hasClass('active')) {
$(li).removeAttr('class');
$(li).addClass('active');
} else {
$(li).removeAttr('class');
}
});
.active {
color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ol class="progress">
<li class="list-group-item text-muted list-group-item-success active">
General Information<span>1</span>
</li>
<li class="list-group-item text-muted list-group-item-success">
General Information<span>2</span>
</li>
<li class="list-group-item text-muted list-group-item-success">
General Information<span>3</span>
</li>
</ol>
In your code you forgot li into selector so $('ol.progress li') instead of $('ol.progress')
I have two tabs like below image
On selection of tab i want to change the text of a div. If i select invoice i want to change value of credit card fee to 0 and if i select credit card it's value should revert back.(in above image it's $17.00)
Here is my html code
<ul class="nav nav-tabs payment-method-list" style="list-style-type: none;">
<li class="active" style="list-style-type: none;">
<a data-target="#payment-method-selector-creditcard" data-toggle="tab" data-type="creditcard" href="#">
Credit / Debit Card
</a>
</li>
<li class="" style="list-style-type: none;">
<a data-target="#payment-method-selector-invoice" data-toggle="tab" data-type="invoice" href="#">
Invoice
</a>
</li>
</ul>
<p>
Credit card fee code
<span class="pull-right cart-summary-handling-cost-formatted" id="service_charge">$17.00</span> //it's value will be dynamic
<span>Credit Card Fee </span>
Here is my jquery code
jQuery(document).ready(function() {
jQuery(".payment-method-list li a").click(function() {
var originaltext = jQuery("#service_charge").text();
if (jQuery('a[data-target="#payment-method-selector-invoice "]').parent().hasClass('active')) {
jQuery("#service_charge").text("0");
} else {
jQuery("#service_charge").text(originaltext);
}
});
});
But it's changing value to 0 when i click first invoice then credit card after that it's value is not changing back to original text.
As I'm new to jquery please help me what's wrong with this code.
jQuery(document).ready(function() {
jQuery(".payment-method-list li a").click(function() {
localStorage.setItem("originalBalance", jQuery("#service_charge").text());
if (jQuery('a[data-target="#payment-method-selector-invoice "]').parent().hasClass('active')) {
jQuery("#service_charge").text("0");
} else {
jQuery("#service_charge").text(localStorage.getItem("originalBalance"));
}
});
});
Try this. I am saving the original balance through localStorage.
Try check by data-type ,because your active class is changing when you clicked and checking your operator ...
jQuery(document).ready(function()
{
var originaltext= jQuery("#service_charge").text();
jQuery(".payment-method-list li a").click(function(){
if(jQuery(this).data("type") == "invoice")
{
jQuery("#service_charge").text("0");
}
else {
jQuery("#service_charge").text(originaltext);
}
});
});
You are getting the issue as once the text on input is updated when using .text(), next time it will return the updated text. You can to persist the originaltext in internal data cache using .data(), which can be fetched when required.
jQuery(document).ready(function() {
//Persists originaltext
var serviceChange = jQuery("#service_charge");
var originaltext = serviceChange.text();
serviceChange.data('originaltext', originaltext);
//Populate it using the method
//serviceChange.data('originaltext', getOriginalText());
jQuery(".payment-method-list li a").click(function() {
if (jQuery('a[data-target="#payment-method-selector-invoice "]').parent().hasClass('active')) {
serviceChange.text("0");
} else {
serviceChange.text(serviceChange.data('originaltext'));
}
});
});
On my product lister tempalte, I've got some filters ul.current-filters li which show currently selected product attributes. On click, the filter buttons should disapear ul.current-filters li. On clicking the "clear filter" button .clear-current-filters, all filters should be removed. If there is only one filter remaining, it should be removed, along with the clear filter button.
HTML
<div class="product-filter-buttons-container">
<!-- Product Filter list -->
<ul class="current-filters">
<div class="clear-current-filters">Clear Filtersx</div>
<!-- Product Filter Attributes -->
<li>Nikex</li>
<li>Adidasx</li>
<li>£90 - £100x</li>
</ul>
</div>
JQuery - This is what I currently have, unfortunately it does not work as intended. How do I reference the delgated element? It seems as though $(this) references the initial ul.current-filters li
$(".product-filter-buttons-container").on("click", "ul.current-filters li", function(event) {
event.preventDefault();
var a = $(this);
if ((a.length) > 0) {
a.hide();
} else {
a.hide();
$(".clear-current-filters").hide();
}
});
Something like this:
$('.current-filters > li > a').click(function(e){
var $this = $(this),
clearAll = $this.parent('li').hasClass('clear-current-filters'),
lastOne = $('.current-filters > li ').length == 2;
if(clearAll || lastOne){
$this.closest('ul').empty();
}else{
$this.parent().remove();
}
});
For this:
<div class="product-filter-buttons-container">
<!-- Product Filter list -->
<ul class="current-filters">
<li class="clear-current-filters">
Clear Filtersx
</li>
<li>
Nikex
</li>
<li>
Adidasx
</li>
<li>
£90 - £100x
</li>
</ul>
</div>
See it work in this demo
I am working on a site with an accordion style script i've found. I'm quite new to jquery/javascript, so please bear with me...
My basic page opens an accordion, where the first one is locked open, and the other ones opens/closes if pressed. What keeps my top panel locked open is a
<li class="locked">.
The other panels have only
<li>
no class. I guess I can call them
<li class="somethingelse">
I want a button in my top panel that changes all the
to
<li class="locked">, so that the user can view the entire site.
I have tried:
<div>
<ul>
<li class="locked">Something
<button onclick="myFunction()">Click me</button>
</li>
<li id="abcd" class="somethingelse">somethingelse</li>
<li id="abcd"class="somethingelse">somethingelse</li>
</ul>
</div>
<script>
function myFunction() {
document.getElementById("abcd").class = "locked";
}
</script>
In plain JavaScript, I'd suggest:
function myFunction() {
// retrieves a NodeList of all <li> elements that do not
// have the 'locked' class-name:
var liElements = document.querySelectorAll('li:not(.locked)');
// uses Array.prototype.forEach to iterate over the array-like
// NodeList:
Array.prototype.forEach.call(liElements, function (li, index, list) {
// first argument ('li' ): the current array-element,
// second argument ('index'): unused, the index of the current
// array-element in the array,
// third argument ('list'): the array itself
// adding the 'locked' class-name to the list of classes
// of the current node:
li.classList.add('locked');
});
}
li {
opacity: 0.3;
}
li.locked {
opacity: 1;
}
<div>
<ul>
<li class="locked">Something
<button onclick="myFunction()">Click me</button>
</li>
<li class="somethingelse">somethingelse</li>
<li class="somethingelse">somethingelse</li>
</ul>
</div>
<script>
function myFunction() {
var liElements = document.querySelectorAll('li:not(.locked)');
Array.prototype.forEach.call(liElements, function (li, index, list) {
li.classList.add('locked');
});
}
</script>
Further, I'd suggest binding the event-handling in JavaScript, rather than using in-line HTML attributes (onclick, etc), which makes for easier long-term maintenance (since everything's updated in the same place, and you don't have to remember where all the event-handling was assigned):
function myFunction() {
var liElements = document.querySelectorAll('li:not(.locked)');
Array.prototype.forEach.call(liElements, function(li, index, list) {
li.classList.add('locked');
});
}
// finding the first element that matches the CSS selector.
// adding the named function (myFunction) as a 'click'
// event-handler:
document.querySelector('li.locked button').addEventListener('click', myFunction);
li {
opacity: 0.3;
}
li.locked {
opacity: 1;
}
<div>
<ul>
<li class="locked">Something
<button onclick="myFunction()">Click me</button>
</li>
<li class="somethingelse">somethingelse</li>
<li class="somethingelse">somethingelse</li>
</ul>
</div>
References:
CSS:
Negation (:not()) pseudo-class.
JavaScript:
document.querySelector().
document.querySelectorAll().
EventTarget.addEventListener().
Element.classList.
You should be changing element class as below
document.getElementById("abcd").className = "locked";
If you want to select more then one element use class name:
var nodes = document.getElementsByClassName("somethingelse");
So your final function will look like:
function myFunction() {
var nodes = document.getElementsByClassName("somethingelse");
var arr = Array.prototype.slice.call(nodes);
arr.forEach( function(node) {
node.className = "locked";
});
}
li {
color: #000000;
}
li.locked {
color: #ff0000;
}
<div>
<ul>
<li class="locked">Something
<button onclick="myFunction()">Click me</button>
</li>
<li id="abcd" class="somethingelse">somethingelse</li>
<li id="abcd" class="somethingelse">somethingelse</li>
</ul>
</div>
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