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>
Related
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>
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>
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>
So i have multiple buttons that is showing when it's clicked.
But i'm having a hard time hiding the content if another button is clicked.
The Javascript code looks like this
function portFunction() {
var e = document.getElementById("test2").style;
if(!e.display | e.display == "none"){
e.display = "block";
}
else{
e.display = "none";
}
}
And the html
<nav>
<ul>
<li onclick="portFunction();">Portfolio</li>
<li onclick="blogFunction();">Blog</li>
</ul>
</nav>
How can i make it so if another button is clicked, it hides the content for the last button that was open and display the new button content?
EDIT
Snippet code, ok so if you click on Portfolio some text will be displayed. But if you click on Blog some other text will be displayed, but the text from Portfolio will still be displayed. What i want is, if you click the Portfolio button and then the Blog button, the text from portfolio should go away. And i want this for every button.
function blogFunction() {
var e = document.getElementById("test").style;
if(!e.display | e.display == "none"){
e.display = "block";
}
else{
e.display = "none";
}
}
function portFunction() {
var e = document.getElementById("test2").style;
if(!e.display | e.display == "none"){
e.display = "block";
}
else{
e.display = "none";
}
}
#import url(http://fonts.googleapis.com/css?family=Open+Sans);
.center{
font: 100% open sans, sans-serif;
margin:0;
padding:0;
}
#test{
display:none;
height:20%;
width:20%;
z-index:11;
position:absolute;
left:50%;
right: 50%;
}
.testText{
color:red;
z-index:11;
}
#test2{
display:none;
height:20%;
width:20%;
z-index:11;
position:absolute;
left:50%;
}
<nav>
<ul>
<li class="current">Home</li>
<li onclick="portFunction();">Portfolio</li>
<li onclick="blogFunction();">Blog</li>
<li>About</li>
<li>Contact</li>
<li>Preview</li>
</ul>
</nav>
<div class="center">
<div id="test">
<h1 class="testText">
Test
</h1>
</div>
<div id="test2">
<h1 class="testText">
Test2
</h1>
</div>
</div>
A simpler way to do this would be to use classes and jQuery's eq() something like this:
$('.section-link').click(function() {
var cur = $('.section-link').index($(this)); // get the index of the clicked link
$('.section-display').removeClass('active'); // hide all of the sections
$('.section-display').eq(cur).addClass('active'); // show the section at the same index of the clicked link
});
.section-display:not(.active) {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<nav>
<ul>
<li class="section-link">Portfolio
</li>
<li class="section-link">Blog
</li>
</ul>
</nav>
<br>
<br>
<div class="section-display active">Section One</div>
<div class="section-display">Section Two</div>
In response to your comment, Let's take the code line by line:
First, the CSS rule .section-display:not(.active) { display: none; } hides every element that has the class section-display, unless it also has the class active. This makes all of the divs hidden but allows you to add the classactive if you want a particular section to be shown by default.
In the jQuery, $('.section-link').click(function() { }); is a click handler. Basically, it says when someone clicks on an element that has the class section-link, run the code in this block
Inside the handler, the variable $(this) refers to a jQuery object that represents the element that was clicked (in your case a link).
The first line, var cur = $('.section-link').index($(this)); says, gather all of the elements that have the class section-link (all of you links) into an array and give me the index of the one that was clicked. So now we know that the user clicked the 2nd link for example.
The next line $('.section-display').removeClass('active'); removes the class active from all of the divs that have the class section-display which hides all the divs because of the css rule
On the next line $('.section-display').eq(cur).addClass('active');, $('.section-display') gathers all of the divs that have the class section-display into an array (these are the divs with the content). After that .eq(cur) selects the div from the array that is at the same index as the link that was clicked. And finally .addClass('active') adds the class active to the element which displays the4 element because of the css rule.
So now, clicking on the first section-link element will show the first section-display div and hide all others. Clicking on the second section-link element will show the second section-display div and hide all others. And so on...
I added a callLastFunc() function, it saves and calls previous function, to hide the content added by previous function call.
var lastCalled = null;
function callLastFunc(arg) {
if (arg[0])
return;
if (lastCalled)
lastCalled("byCallPrev");
lastCalled = arg.callee;
}
function blogFunction() {
var e = document.getElementById("test").style;
if(!e.display | e.display == "none"){
e.display = "block";
}
else{
e.display = "none";
}
callLastFunc(arguments);
}
function portFunction() {
var e = document.getElementById("test2").style;
if(!e.display | e.display == "none"){
e.display = "block";
}
else{
e.display = "none";
}
callLastFunc(arguments);
}
#import url(http://fonts.googleapis.com/css?family=Open+Sans);
.center{
font: 100% open sans, sans-serif;
margin:0;
padding:0;
}
#test{
display:none;
height:20%;
width:20%;
z-index:11;
position:absolute;
left:50%;
right: 50%;
}
.testText{
color:red;
z-index:11;
}
#test2{
display:none;
height:20%;
width:20%;
z-index:11;
position:absolute;
left:50%;
}
<nav>
<ul>
<li class="current">Home</li>
<li onclick="portFunction();">Portfolio</li>
<li onclick="blogFunction();">Blog</li>
<li>About</li>
<li>Contact</li>
<li>Preview</li>
</ul>
</nav>
<div class="center">
<div id="test">
<h1 class="testText">
Test
</h1>
</div>
<div id="test2">
<h1 class="testText">
Test2
</h1>
</div>
</div>
Hmm, you would be better to use a framework, but this is what you want right?
This example make use of vanillaJS Framework, which is very powerful out of the box ;)
// lib.js
sitesContent = {};
// blog.js
sitesContent['blog'] = "Blog content"; // You can use templates like handlebars
// portfolio.js
sitesContent['portfolio'] = "Portfolio content"; // Better to use templates
// app.js
function navAction(site) {
document.getElementById('content').innerHTML = sitesContent[site];
}
navAction('portfolio'); // Means load portfolio when loaded first time
<nav>
<ul>
<li><a onclick="navAction('portfolio')" href="#">Portfolio</a></li>
<li><a onclick="navAction('blog')" href="#">Blog</a></li>
</ul>
</nav>
<div id="content"></div>
I have 4 <li> and I like them to become the trigger of linked images. I use javascript here and this project does not allow jQuery. Please refer to the code snippet.
var children = document.querySelectorAll('#resistorContent > section[id]');
function showDetailContent(target) {
// Simply loop over our children and ensure they are hidden:
for (var i = 0, child; child = children[i]; i++) {
child.style.display = 'none';
}
// Now, show our child we want to show
document.getElementById(target).style.display = 'block';
}
/* Start Hidden, show first */
#resistorContent > section[id] {
width: 940px;
height: 400px;
overflow: hidden;
display:none;
}
#resistorContent > section[id]:first-child {
display: block;
}
<div id="resistorContent">
<section id="resistorDetail1"><img src="http://d3d71ba2asa5oz.cloudfront.net/40000483/images/pic1.jpg" alt=""></section>
<section id="resistorDetail2"><img src="http://d3d71ba2asa5oz.cloudfront.net/40000483/images/pic2.jpg" alt=""></section>
<section id="resistorDetail3"><img src="http://d3d71ba2asa5oz.cloudfront.net/40000483/images/pic3.jpg" alt=""></section>
<section id="resistorDetail4"><img src="http://d3d71ba2asa5oz.cloudfront.net/40000483/images/pic4.jpg" alt=""></section>
<ul>
<li onmouseover="showDetailContent('resistorDetail1')">Hover 1!</li>
<li onmouseover="showDetailContent('resistorDetail2')">Hover 2!</li>
<li onmouseover="showDetailContent('resistorDetail3')">Hover 3!</li>
<li onmouseover="showDetailContent('resistorDetail4')">Hover 4!</li>
</ul>
</div>
</section>
It works quite fine in jsfiddle and here in the code snippet. But if you paste them to your text editor and preview it in the browser, it renders different result. It creates a pile of all 4 images and it is not hiding the image as javascript intended. What did I do wrong here?
Thanks in advance.
I'm fairly certain the issue is that you are loading your script in the <head> element in your document. This causes an issue because your script tries to loop over the DOM and make changes, but if your script is in the <head> tag, it's executing before the DOM that contains the images is ready. That would be why the images are not being hidden and just stacking. Try running the script just before the closing </body> tag. Your file should look similar to this (but generally it's better to use external stylesheets and link to your javascript files):
<!DOCTYPE html>
<html>
<head>
<title>Testing DOM loading and script placement</title>
<style type="text/css">
/* Start Hidden, show first */
#resistorContent > section[id] {
width: 940px;
height: 400px;
overflow: hidden;
display:none;
}
#resistorContent > section[id]:first-child {
display: block;
}
</style>
</head>
<body>
<div id="resistorContent">
<section id="resistorDetail1"><img src="//placehold.it/940x450/5B696A/fff/&text=PIC+1" alt=""></section>
<section id="resistorDetail2"><img src="//placehold.it/940x450/4D686B/fff/&text=PIC+2" alt=""></section>
<section id="resistorDetail3"><img src="//placehold.it/940x450/415558/fff/&text=PIC+3" alt=""></section>
<section id="resistorDetail4"><img src="//placehold.it/940x450/345658/fff/&text=PIC+4" alt=""></section>
<ul>
<li onmouseover="showDetailContent('resistorDetail1')">Hover 1!</li>
<li onmouseover="showDetailContent('resistorDetail2')">Hover 2!</li>
<li onmouseover="showDetailContent('resistorDetail3')">Hover 3!</li>
<li onmouseover="showDetailContent('resistorDetail4')">Hover 4!</li>
</ul>
</section>
</div>
<script>
var children = document.querySelectorAll('#resistorContent > section[id]');
function showDetailContent(target) {
// Simply loop over our children and ensure they are hidden:
for (var i = 0, child; child = children[i]; i++) {
child.style.display = 'none';
}
// Now, show our child we want to show
document.getElementById(target).style.display = 'block';
}
</script>
</body>
</html>
Here's a demo that doesn't rely on the platform inserting the javascript in the right spot: http://jsbin.com/qulajeroru/2/edit?html,output (click "Run with JS")