vanilla javascript onload click simulation - javascript

I am trying to figure this...
I have a that is being fed by some javascript for a server, and when using jquery things don't work at all, so I have to stick to vanilla javascript ..
What I am trying to do is load a page which always defaults to the first tab out of three but instead of defaulting to the first tab, i want it to trigger a fake simulated click to load the 3rd tab.
<ul>
<li class="active">tab 1</li>
<li>tab 2</li>
<li>tab 3</li>
</ul>
the javascript that is been fed, automatically writes an inline style of "display:table-row" to the active panel, and a display:none to the panel 3 of the tab system.
So i can't figure out without using jquery how to simulate a fake click or force it to make tab 3 active, and to make panel 3 display;table row
Edit: I used this code
var simulateClick = function (elem) {
// Create our event (with options)
var evt = new MouseEvent('click', {
bubbles: true,
cancelable: true,
view: window
});
// If cancelled, don't dispatch our event
var canceled = !elem.dispatchEvent(evt);
};
var someLink = document.querySelector('#panel3');
simulateClick();
I forgot to add the java code i tried to use.

Clicking is not needed. Once the page is loaded and the server has done whatever it was tasked to do, run your script. This is normally done by placing a <script> tag before the closing </body> tag. Details are commented in demo.
const setActive = targetIndex => {
/*
Collect all <a> into a HTMLCollection then convert
to an Array.
*/
const linx = Array.from(document.links);
// Collect all panels into a NodeList
const panels = document.querySelectorAll('section');
/* Iterate through the NodeList...
A - for...of loop using .entries() which returns the
array [index, value] which we easily access by
destructuring
B - Find the current <li>
C - On each iteration if the current index does not
equal the given targetIndex then remove .active
class from <li> and set display: none to style of
current <section>
D - Otherwise add .active class and set style to
display: table-row
*/
for (let [index, link] of linx.entries()) { //A
let item = link.parentElement; //B
if (index != targetIndex) { //C
item.classList.remove('active');
panels[index].style.display = "none";
} else { //D
item.classList.add('active');
panels[index].style.display = "table-row";
}
}
return false;
}
setActive(2);
/* Added to prove .active (just for demo -- not required) */
.active {
outline: 3px dashed #f00
}
ul {
list-style: none
}
li {
display: inline-block;
margin: 0 5px
}
main {
display: table
}
section {
display: table-row
}
section * {
display: table-cell
}
<ul>
<li class="active">tab 1</li>
<li>tab 2</li>
<li>tab 3</li>
</ul>
<main>
<section id='panel1'>
<h3>Panel 1</h3>
</section>
<section id='panel2'>
<h3>Panel 2</h3>
</section>
<section id='panel3'>
<h3>Panel 3</h3>
</section>
</main>

Related

How to use for loop in JavaScript

Ok, so i have an unordered list and it has two items. Now in my javascript i am trying to add event listener to these items so that a CSS class can be applied to them once clicked. here is the code. can anyone fill the missing part in here.Thanks
html part:-
<body>
<h3>Simple Add/Remove Task</h3>
<h4>To do List</h4>
<ul>
<div>
<li class="todos">Wake up</li>
<li class="todos">Study</li>
</div>
<div>
<button>Delete</button><br>
<button>Delete</button>
</div>
</ul>
<script type="text/javascript" src="./script.js"></script>
</body>
Js part:-
var listItems = document.getElementsByClassName("todos");
for (var i = 0; i<listItems.length; i++){
listItems[i].addEventListener("click", function(){
})
}
Just add or toggle the desired class with classList.add() or classList.toggle().
Also (FYI):
Headings should not be used because of the way they style the text
within them. As with everything else in HTML, they are semantic. You
shouldn't have an h4 unless you want a new sub-section to an h3,
which you wouldn't have unless it was a sub-section of an h2 an so
on. You can (and should) do your formatting with CSS, not HTML.
It is also invalid to put a div directly inside of a ul. Only
li, script, or template elements can be children of a ul or
ol.
Don't use .getElementsByClassName(). Use .querySelectorAll() instead.
var listItems = document.querySelectorAll(".todos");
for (var i = 0; i<listItems.length; i++){
listItems[i].addEventListener("click", function(){
this.classList.toggle("active"); // each click toggles the use of the class
});
// While looping over the bullets, search for the button within each
// and set up a click handler for when the delete button gets clicked
// .closest() will look for the nearest ancestor that matches the selector.
listItems[i].querySelector("button").addEventListener("click", function(){
this.closest(".todos").remove();
});
}
h1 { font-size: 1.2em; }
h2 { font-size: 1em; }
.active { background-color:yellow; }
<h1>Simple Add/Remove Task</h1>
<h2>To do List</h2>
<ul>
<li class="todos">Wake up <button>Delete</button></li>
<li class="todos">Study <button>Delete</button></li>
</ul>
use this line in js to change the class:
listItems[i].className = 'cssClass';
and then make some 'cssClass' css. Unless you want to make the css created in js, in which case you would do this beforehand:
var style = document.createElement('style');
style.type = 'text/css';
style.innerHTML = '.cssClass { color: green; }';
Use for...of to iterate over the elements.
Use the event.currentTarget to get the selected element.
Use classList.add to add a class to an element
var listItems = document.getElementsByClassName("todos");
for (let listItem of listItems) {
listItem.addEventListener("click", event => {
event.currentTarget.classList.add('selected')
})
}
.selected {
background: green;
}
<body>
<h3>Simple Add/Remove Task</h3>
<h4>To do List</h4>
<ul>
<li class="todos">Wake up</li>
<li class="todos">Study</li>
</ul>
</body>

Is it possible to automatically declare thousands of variables in JavaScript?

I'm relatively new to JavaScript, so I'm not sure if I'm doing things conventionally here, of if there's a better way of doing what I'm trying to do.
I have a JavaScript function that takes about 3,600 sentences from a JSON document and inserts them automatically into my HTML code. A unique id is generated for each once in the HTML.
I want to create an onclick event for each sentence so that when it's clicked more information appears underneath about the sentence. This means I have to declare thousands of variables, one for each sentence and one for each information div associated with that sentence:
var sent1 = document.getElementById('s1');
var sent1info = document.getElementById('s1info');
var sent2 = document.getElementById('s2');
var sent2info = document.getElementById('s2info');
var sent3 = document.getElementById('s3');
var sent3info = document.getElementById('s3info');
...
This is way too much to do manually. Is there a way to automate the process of declaring these variables, or is there a better way to do what I'm doing?
For context, my intention with each variable is to feed it into this function:
sent1.onclick = function(){
if(sent1info.className == 'open'){
sent1info.className = 'close';
} else{
sent1info.className = 'close';
}
};
From here the CSS will reduce the info box to a hight of 0 when the className is 'close' and expand it when the className is 'open'. But, again, this will require me writing out this function thousands of times.
Is there a way to do this automatically also? Or am I going about this all wrong?
Edit to show HTML:
<!DOCTYPE html>
<html>
<head>...</head>
<body>
<div id="everything">
<header id="theheader" class="clearfix">...</header>
<div id="thebody" class="box clearfix">
<aside id="page" class="side">...</aside>
<div class="items">
<article id="content" class="article">
<img id="sentpic" src="sentpic.jpg">
<h1>Sentences</h1>
<div id="sentences">
*** This is where the JS inserts sentences and information ***
<ul id='sent1' class='sentcontent'><li class='number'>1.</li><li class='thesent'>...</li></ul>
<div id='sent1info' class='infobox'>
<ul class='sentinfo'><li class='information'>Info:</li><li class='infotext'><em>...</em></li></ul>
<ul class='sentinfo'><li class='information'>Line:</li><li class='line'>...</li></ul>
</div>
<ul id='sent2' class='sentcontent'><li class='number'>2.</li><li class='thesent'>...</li></ul>"
<div id='sent2info' class='infobox'>
<ul class='sentinfo'><li class='information'>Info:</li><li class='infotext'><em>...</em></li></ul>
<ul class='sentinfo'><li class='information'>Line:</li><li class='line'>...</li></ul>
</div>
*** it goes on like this for each sent inserted ***
</div>
</article>
</div>
</div>
<div class="associates clearfix">...</div>
<footer class="foot">...</footer>
</div>
<script type="text/javascript" src="index.js"></script>
</body>
</html>
Using HTML <details> element:
const json = [
{thesent:"Lol", info:"This is some info 1", line:"Whatever 1..."},
{thesent:"Lorem", info:"Some info 2", line:"Something here 2..."},
];
const template_sentence = (ob, i) => `
<details class="sentence">
<summary>${i+1} ${ob.thesent}</summary>
<h3>${ob.info}</h3>
<div>${ob.line}</div>
</details>`;
document.querySelector("#sentences").innerHTML = json.map(template_sentence).join('');
<div id="sentences"></div>
Otherwise, by using your current non-semantic markup:
Targeting by ID (in your specific case) is not needed. There's other methods like the + Next Adjacent sibling selector in CSS.
And here's a JS example - should be self-explanatory, but feel free to ask.
Use JS to toggle a class (.active in this example) to the clickable UL element
Use CSS and the Next adjacent sibling selector + to make the info DIV display: block
/* Just a sample... you'll know how to modify this with the right properties I hope */
const json = [
{thesent:"Lol", info:"This is some info 1", line:"Whatever 1..."},
{thesent:"Lorem", info:"Some info 2", line:"Something here 2..."},
];
// The toggle function:
const toggleInfobox = ev => ev.currentTarget.classList.toggle("active");
// A single sentcontent template
const template_sentence = (ob, i) =>
`<ul class='sentcontent'>
<li class='number'>${i+1}</li>
<li class='thesent'>${ob.thesent}</li>
</ul>
<div class='infobox'>
<ul class='sentinfo'>
<li class='information'>Info:</li>
<li class='infotext'><em>${ob.info}</em></li>
</ul>
<ul class='sentinfo'>
<li class='information'>Line:</li>
<li class='line'>${ob.line}</li>
</ul>
</div>`;
// Get target element
const el_sentences = document.querySelector("#sentences");
// Loop JSON data and create HTML
el_sentences.innerHTML = json.map(template_sentence).join('');
// Assign listeners
const el_sentcontent = el_sentences.querySelectorAll(".sentcontent");
el_sentcontent.forEach(el => el.addEventListener('click', toggleInfobox));
/* BTW, why do you use <ul> ? That's not a semantic list! */
.sentcontent { padding: 0; cursor: pointer;}
.sentcontent li { display: inline-block; }
/* Arrows are cool, right? */
.sentcontent:before { content: "\25BC"; }
.sentcontent.active:before { content: "\25B2"; }
/* Hide adjacent .infobox initially,
/* and show adjacent .infobox on JS click */
.sentcontent + .infobox { display: none; }
.sentcontent.active + .infobox { display: block; }
<div id="sentences"></div>
In this Stack overflow answer you can find out more about toggling an element on some button click.
This question is more of an architectural issue than a need for creating dynamic variables. Consider this example:
ids are removed (existing class names used)
This pattern scales for n sentence instances
In handleClick, we toggle the open class on the clicked element, which lets us leverage the adjacent sibling selector via CSS
No need for a close class, since the absence of the open class represents the closed state.
let outerUL = document.querySelectorAll('.sentcontent')
function handleClick() {
this.classList.toggle('open');
}
outerUL.forEach(ul => {
ul.addEventListener('click', handleClick);
})
.sentcontent {
cursor: pointer;
}
.sentcontent.open + .infobox {
display: block;
}
.infobox {
background-color: #eee;
display: none;
padding: .25em .5em;
}
<ul class='sentcontent'>
<li class='number'>1.</li>
<li class='thesent'>Sent</li>
</ul>
<div class='infobox'>
<ul class='sentinfo'>
<li class='information'>Info</li>
<li class='infotext'><em>Info text</em></li>
</ul>
<ul class='sentinfo'>
<li class='information'>Line info</li>
<li class='line'>Line</li>
</ul>
</div>
<ul class='sentcontent'>
<li class='number'>2.</li>
<li class='thesent'>Sent</li>
</ul>
<div class='infobox'>
<ul class='sentinfo'>
<li class='information'>Info</li>
<li class='infotext'><em>Info text</em></li>
</ul>
<ul class='sentinfo'>
<li class='information'>Line info</li>
<li class='line'>Line</li>
</ul>
</div>
https://jsfiddle.net/d91va7tq/2/
When you have a very large json data then its good idee to keep in mind too not render the whole data at once, it will effect the webbrowser performance. Instead render when needed. And that is when the user click for more information.
I did some example below, make sure too read the comment
const json = [
{thesent:"Lol", info:"This is some info 1", line:"Whatever 1..."},
{thesent:"Lorem", info:"Some info 2", line:"Something here 2..."},
];
const container = document.querySelector(".container");
json.forEach((item)=> {
let x= item;
let el = document.createElement("li");
el.innerHTML = x.thesent;
container.appendChild(el);
el.addEventListener("click",()=> {
var infoContainer= el.querySelector(".info");
// dont create all html element at once, instead create them
//when the user click on it. this is better when you have a very large data.
if (!infoContainer){ // not created, then create
infoContainer = document.createElement("div");
infoContainer.className="info";
var info = document.createElement("div");
var line = document.createElement("div");
info.innerHTML = x.info;
line.innerHTML = x.line;
infoContainer.appendChild(info);
infoContainer.appendChild(line);
el.appendChild(infoContainer);
} else if (infoContainer.style.display == "none") // created and hidden, then display it
infoContainer.style.display = "block";
else infoContainer.style.display= "none"; // already displayed then hide it
});
})
.container li >div.info >div:first-child{
font-size: 12px;
}
.container li >div.info >div:last-child{
font-size: 10px;
}
<ul class="container">
</ul>

Close elements by clicking anywhere on the page using pure Javascript

I have a menu which opens a sub-navigation on clicking a header which I am trying to get to close by clicking anywhere on the page except an open element.
My Code Snippet is as follows:
function showSubMenu(show, hide1, hide2, hide3, hide4) {
document.getElementById(show).className = "subNavShow";
document.getElementById(hide1).className = "subNavHide";
document.getElementById(hide2).className = "subNavHide";
document.getElementById(hide3).className = "subNavHide";
document.getElementById(hide4).className = "subNavHide";
}
.subNavHide {
display: none;
}
.subNavShow {
display: block;
}
<ul class="topnavList" id="siteTopnavList">
<li>
<a onclick="showSubMenu('text1','text2','text3','text4','text5')" href="javascript:void(0);">Nav 1</a>
<article id="text1" class="subNavHide">
<ul>
<li>Sub Nav 1</li>
</ul>
</article>
</li>
<li>
<a onclick="showSubMenu('text2','text1','text3','text4','text5')" href="javascript:void(0);">Nav 2</a>
<article id="text2" class="subNavHide"> text2 </article>
</li>
<li>
<a onclick="showSubMenu('text3','text1','text2','text4','text5')" href="javascript:void(0);">Nav 3</a>
<article id="text3" class="subNavHide"> text3 </article>
</li>
<li>
<a onclick="showSubMenu('text4','text1','text2','text3','text5')" href="javascript:void(0);">Nav 4</a>
<article id="text4" class="subNavHide"> text4 </article>
</li>
<li>
<a onclick="showSubMenu('text5','text1','text2','text3','text4')" href="javascript:void(0);">Nav 5</a>
<article id="text5" class="subNavHide"> text5 </article>
</li>
</ul>
Ideally I would like to use pure Javascript for this but if Jquery is absolutely necessary then I would be OK with that too
The easiest way to do this with your current implementation, in my opinion, is to add a click event listener to the document and use .closest to determine if the element clicked is the element open:
document.addEventListener(`click`, hideSubMenus);
function hideSubMenus(event) {
if (!event.target.closest(`.topnavList li a, .subNavShow`)) {
document.getElementById(`text1`).className = `subNavHide`;
document.getElementById(`text2`).className = `subNavHide`;
document.getElementById(`text3`).className = `subNavHide`;
document.getElementById(`text4`).className = `subNavHide`;
document.getElementById(`text5`).className = `subNavHide`;
}
}
closest is however not compatible with older browsers: https://developer.mozilla.org/en-US/docs/Web/API/Element/closest
But I would probably add classes to the links and add event listeners to them instead of using the "onclick" attribute. That way, for example, if you add the "subNavLink" class to each link, you can use a loop to deal with the links, instead of repeating the same line for each link:
let links, i, n;
links = document.getElementsByClassName(`subNavLink`);
for (i = 0, n = links.length; i < n; i++) {
links[i].addEventListener(`click`, showSubMenu);
}
function showSubMenu(event) {
let currentLink, i, link, n;
currentLink = event.currentTarget;
for (i = 0, n = links.length; i < n; i++) {
link = links[i];
if (link === currentLink) {
// this link was clicked, so we have to show its submenu
link.nextElementSibling.className = `subNavShow`;
} else {
// this link was not clicked, so we have to hide its submenu
link.nextElementSibling.className = `subNavHide`;
}
}
}
By doing this you can change the hideSubMenus function to:
function hideSubMenus(event) {
let i, n;
if (!event.target.closest(`.subNavLink, .subNavShow`)) {
for (i = 0, n = links.length; i < n; i++) {
links[i].nextElementSibling.className = `subNavHide`;
}
}
}
I've found that the easiest way to pull this off is to create a layer, underneath the menu (or more commonly a modal window). And then use that layer as the element to test if it has been clicked (versus the element sitting on top of it).
(The example uses a grayed out background to show the overlay's presence, but it could just as easily be a transparent DIV and still have the same effect)
// Get the elements that will show/hide
const overlay = document.getElementById('overlay');
const menu = document.getElementById('menu');
// Change the className to have the CSS that will hide
// the elements
// Since the 'menu' element is on top of the 'overlay'
// element, clicking on the 'menu' should not click
// through the 'overlay' -- thus ignoring this section
// of code to hide things
overlay.onclick = function(){
menu.className = 'hide';
overlay.className = 'hide';
};
// Quick and dirty code to reset the page and display
// the 'menu' and 'overlay' DIVs
function open(){
menu.className = '';
overlay.className = '';
}
#overlay{
display: block;
position: fixed;
top: 0; left: 0;
height: 100%; height: 100vh;
width: 100%; width: 100vw;
background-color: rgba( 0, 0, 0, 0.25 );
}
#overlay.hide{ display: none; }
#menu{
position: absolute;
background-color: white;
padding: 15px; border-radius: 5px;
}
#menu ul, #menu li{
margin: 0; padding: 0;
list-style: none;
}
#menu.hide{ display: none; }
OPEN
<div id="overlay"></div>
<div id="menu">
<ul>
<li>Menu Item</li>
<li>Menu Item</li>
<li>Menu Item</li>
<li>Menu Item</li>
</ul>
</div>
With the bubble and how elements are stacked, clicking on the menu won't close it -- but clicking anywhere outside of it will.
The more general the code is, the better.
Using an eventListener set on the document lets you listen to all "click" events (that bubbles up the DOM tree) on the page. You can close all articles no matter what, then display the clicked entry (and its ancestors) if appropriate.
The code below, yet short as many benefits:
It is dynamic. Meaning it can handle any amount of sub-levels. article elements neither require id attributes nor show/hide classes at first render. The code becomes loosly coupled.
Only a single handler function will live in memory instead of one per menu entry.
It will handle entries added later (after eventListener registration) to the menu.
Your code is factorized which makes it easier to read and reuse.
let topNavList = document.querySelector('#siteTopnavList');
document.addEventListener('click', function (e) {
let t = e.target;
// At this point, close menu entries anyway
topNavList.querySelectorAll('a ~ article').forEach(el => {
el.classList.add('subNavHide'); el.classList.remove('subNavShow');
});
// Drop clicks on the "active" link or any element that is outside the `#siteTopnavList` menu
if (!t.nextElementSibling || t.nextElementSibling.classList.contains('subNavShow')) {
return;
}
if (t.nodeName.toLowerCase() == 'a' && topNavList.contains(t)) {
topNavList.querySelectorAll('article').forEach(x => {
if(x.contains(t) || x === t.nextElementSibling) {
x.classList.remove('subNavHide');
x.classList.add('subNavShow');
}
});
// Prevent the browser to process the anchor href attribute
e.preventDefault();
}
});
#siteTopnavList article {display:none}
#siteTopnavList .subNavShow {display:block}
<ul class="topnavList" id="siteTopnavList">
<li>
Nav 1
<article>
<ul>
<li>Sub Nav 1</li>
</ul>
</article>
</li>
<li>
Nav 2
<article> TEXT2 </article>
</li>
<li>
Multi level
<article>
<ul>
<li>
Sub Nav 1
<article>
<ul>
<li>Deep 1</li>
<li>Deep 2</li>
<li>
Even deeper 3
<article>
<ul>
<li>Even deeper 1</li>
</ul>
</article>
</li>
</ul>
</article>
</li>
</ul>
</article>
</li>
</ul>

How to cancel a CSS style set by 'hover child' selector on event?

I am making a CSS based menu, with submenu items that pop up when the root element is hovered. the problem I have is that I want the CSS menu to close when I click an item in the list, but at that point I am still technically hovering over the top element, so I figured I had to use javascript to hide the menu. But when I set the display property, I set it forever and it overrides the hover selector of the parent node. And so the submenu doesn't show up anymore.
This must be pretty common, but I can't find any answers...
Any help much appreciated!
html:
<ul class="level1">
<li>one
<ul class="level2">
<li id="test">two</li>
<li>three</li>
</ul>
</li>
</ul>
css:
.level1 li:hover > ul {
display: inline;
}
.level2 {
display: none;
}
js:
document
.getElementById('test')
.addEventListener('click',function () {
this.parentNode.style.display = 'none';
// After this the menu doesn't open anymore
// because the style is overriden
});
Here's the jsfiddle
You can try this.
<ul class="level1">
<li class="hoverMe">one
<ul class="level2">
<li id="test">two</li>
<li>three</li>
</ul>
</li>
</ul>
.hoverMe:hover > ul {
display: inline;
}
var test = document.getElementById('test');
test.onclick = function () {
this.parentNode.parentNode.className = "";
};
var level1 = document.getElementsByClassName('level1')[0];
level1.getElementsByTagName("li")[0].onmouseover = function () {
if (this.className != "hoverMe") {
this.className = "hoverMe";
}
};

Show headers only for collections that are not empty

I have a couple of lists like this:
<ul>
<li class="list-header">Header</li>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
By some rules I hide and show <li> items so sometimes the list has visible <li> and sometimes it has no visible <li> elements at all except the one with list-header class, so <li class="list-header"> is still there. I want to hide that header if there are no <li> visible elements in it under header. Though I want the <ul> still to be visible.
How do I do that?
What you could do (demo):
$('ul').each(function() {
$ul = $(this);
$ul.find('.list-header').toggle($ul.has('li:not(.list-header):visible').length != 0);
});
Basically, what the above does is toggling the .list-header (I've wrapped it in the .each() in order to demo different lists) depending on whether the list .has() :visible li elements that are :not(.list-header).
UPDATE
Now it works. Sorry.
You could use the :visible and :not selectors to see if there are any elements present when you change the visibility. This example toggles the visibility when clicking the elements, and hides the header if there are no elements present:
$('li:not(".list-header")').click(function(){
$(this).toggle(10,function(){
var l = $(this).parent().children('li:visible:not(".list-header")').length
if (l>0) $(this).parent().children('li.list-header').show();
else $(this).parent().children('li.list-header').hide();
});
});
working example: http://jsfiddle.net/LDG4J/4/
There is no lh element in HTML. References: HTML5, HTML4.01, HTML 3.2. (You've removed the lh from the question.)
Instead, use an li with a class you style as you see fit (or if you're targeting recent-enough browses, no class required; just style li:nth-child(1) or li:first-child), and just don't hide that li (which will keep the ul visible):
<ul>
<li class='header'>Header</li>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
Update: I may have misunderstood. If you want to hide the header but keep the ul visible in some way:
A ul with no visible li elements will typically be invisible because it won't have any dimensions. You can override that with CSS, styling the ul to have a specific size (live example):
CSS:
ul.foo {
width: 5em;
height: 5em;
background-color: #eee;
border: 1px solid #aaa;
}
HTML:
<p><code>ul</code> with no visible children:</p>
<ul class='foo'>
<li style="display: none">This is hidden</li>
</ul>
<p><code>ul</code> with a visible child:</p>
<ul class='foo'>
<li>Visible child, note that it wraps</li>
</ul>
And of course you can apply that via jQuery rather than with a static CSS rule:
$("ul.foo").css({
width: "5em",
height: "5em",
backgroundColor: "#eee",
border: "1px solid #aaa"
});
...so you could do that when you're hiding all of the ul's elements, and undo it when showing at least one of them. After making a change:
var ul = $(/*...selector for the relevant list...*/);
if (ul.find('li:visible')[0]) {
// There's at least one visible `li` child
ul.css({/*...styles for when the list is not empty...*/});
}
else {
// There are no visible `li` children
ul.css({/*...styles for when the list is empty...*/});
}
...or better yet, add/remove a class.
try this:
$("ul li:not('.list-header')").each(function(index, val) {
if ($(this).text() == '') {
$(this).hide();
}
});
if (! ($('ul').has("li:visible:not('.list-header')").length)) {
$('li.list-header').hide();
}

Categories

Resources