Moving around between <nav>, <section> and <main>

466 views Asked by At

I am able to divide the whole page into 4 regions and they are:-

[header] (on the very top), [nav] (right below the header), [section] (on the bottom left) and [main] (on the bottom right).

In the [nav] portion, I have a list of hyperlinked items (like “item-A”, “item-B”, etc).

The task is to:-

When “item-A” is selected, the corresponding sub-list containing “A1”, “A2”, “A3” etc should be displayed on the [section] part. Similarly, if “item-B” is selected, the sub-list “B1”, “B2” should also be displayed on the [section] part (overwriting the previous content, of course).

“B2” again is hyperlinked to the file “B.html” which, when called, should be executed on the [main] portion.

How can I do all of the above?

P.S. I can finish the above if I use [frame] and [frameset]. Unfortunately, these become obsolete in HTML5.

enter image description here

The widths and heights of each region can be defined inside the CSS setup.

4

There are 4 answers

10
Neptotech -vishnu On BEST ANSWER

Stack Blitz code: https://stackblitz.com/edit/web-platform-uwbmw4?devtoolsheight=33&file=index.html


Because it needs a1,a2,b1,b2 HTML files and stuffs it does not work here(below)(other parts work other than iframe stuff) please try above stackblitz for testing

const itemAOptions = [
  {
    name: 'A1',
    data: 'A1.html',
  },
  {
    name: 'A2',
    data: 'A2.html',
  },
];

const itemBOptions = [
  {
    name: 'B1',
    data: 'B1.html',
  },
  {
    name: 'B2',
    data: 'B2.html',
  },
];

const dataContainer = document.querySelector('#display');
const menuContainer = document.querySelector('#menu');
const navContainer = document.querySelector('#navBar');

navContainer.addEventListener('click', (e) => {
  e.stopPropagation();
  if ('nochange' in e.target.dataset) {
    e.preventDefault();
    const toLoad = e.target.dataset.nochange;
    let data = '';
    if (toLoad === 'loadA') {
      data = constructData(itemAOptions);
    } else {
      data = constructData(itemBOptions);
    }
    menuContainer.innerHTML = data;
    display.innerHTML = ``;//emptydata means clear or empty screen as you requested
  }
});

menuContainer.addEventListener('click', (e) => {
  e.stopPropagation();

  e.preventDefault();
  const toLoad = e.target;
  let data = '';

  data = `<iframe src="https://web-platform-uwbmw4.stackblitz.io/${toLoad.innerHTML}.html" name="targetframe" allowTransparency="true" scrolling="no" frameborder="0" >
      </iframe>`;//use src="Your.Website.address.or.directory/${toLoad.innerHTML}.html"

  console.log(toLoad.innerHTML);
  display.innerHTML = data;
});

function constructData(item) {
  let innerData = '';
  item.forEach((i) => {
    innerData += `<li class="li"><a href=# class="a">${i.name}</a></li>`;
  });
  return `<ul class="ul">${innerData}</ul>`;
}

function constructDataIframe(item) {
  let innerData = '';
  item.forEach((i) => {
    innerData += `<iframe src="https://web-platform-uwbmw4.stackblitz.io/${i.data}" name="targetframe" allowTransparency="true" scrolling="no" frameborder="0" >
    </iframe>`;
  });
  return `${innerData}`;
}
h1 {
  text-align:center;
}
#navBar{
  background-color: transparent;
  border: 5px solid black;
  text-align: center;
}
.lk{
  text-decoration: none;
}
.uli{
  display: flex;
  justify-content: flex-end;
}
.lik{
  list-style: none;
  padding-right:15px;
}
.a{
  text-decoration: none;
}
.li{
  list-style: none;

}
.ul{
  float:left;
  padding-left: 10px;
}
#secHolder{
  width: 100%;
  background-color: transparent;
  border: 5px solid black;
  text-align: center;
}

#display{
  width: 100%;
  background-color: transparent;
  border: 5px solid black;
  text-align: center;
}
#Holder{
  width: 100%;
  display: flex;
  flex-direction: row;
  justify-content: center;
}
<html>
  <head>
    <meta charset="UTF-8">
    
    <link rel="stylesheet" type="text/css" href="styles.css"> 
  </head>
  <body>
   <h1>Header</h1>
  <nav id="navBar">
  
  <ul>
    <div class="uli">
    <li class="lik"><a href="#" data-nochange="loadA" class="lk">Item A</a></li>
    <li class="lik"><a href="#" data-nochange="loadB" class="lk">Item B</a></li>
  </div>
  </ul>
</nav>
<div id="Holder">

<div id="secHolder">
<h3>Section</h3>
<section id="menu"></section>
</div>
<main id="display"></main>
</div>
<script src="script.js"></script>
  </body>
</html>

enter image description here

P.S I have tried my best on answering but I don't have regular practice on commenting please try to understand, ask for doubts.

I cannot understand what you mean by I cannot use frame its obsolete in html5, I have used iframe is it ok?

1
lokprakash On

I didn't concentrate on stylings. It is recommended to use iframe instead of object tag. You can try exploring that as well.

const itemAOptions = [{
  name:"A1",
  data:"A1.html"
}, {
  name:"A2",
  data:"A2.html"
}];

const itemBOptions = [{
  name:"B1",
  data:"B1.html"
}, {
  name:"B2",
  data:"B2.html"
}];

const dataContainer = document.querySelector("#display");
const menuContainer = document.querySelector("#menu");
const navContainer = document.querySelector("#navBar");

navContainer.addEventListener("click", (e)=>{
  e.stopPropagation();
  if("nochange" in e.target.dataset){
    e.preventDefault();
    const toLoad = e.target.dataset.nochange;
    let data = '';
    if(toLoad === "loadA"){
      data = constructData(itemAOptions);
    }
    else{
      data = constructData(itemBOptions);
    }
    menuContainer.innerHTML = data;
  }
});

menuContainer.addEventListener("click", (e)=>{
  e.stopPropagation();
  if("spaload" in e.target.dataset){
    e.preventDefault();
    const data = e.target.dataset.spaload;
    dataContainer.innerHTML=`<object type="text/html" data=${data} ></object>`;
  }
});

function constructData(item){
  let innerData = '';
  item.forEach((i)=>{
    innerData+=`<li><a href=${i.data} data-spaload=${i.data}>${i.name}</a></li>`;
  });
  return `<ul>${innerData}</ul>`;
}
<nav id="navBar">
  <ul>
    <li><a href="#" data-nochange="loadA">Item a</a></li>
    <li><a href="#" data-nochange="loadB">Item B</a></li>
  </ul>
</nav>
<h3>Section</h3>
<section id="menu"></section>
<main id="display"></main>

5
AudioBubble On

You can use buttons instead of a hyperlink and get the same output.

Below is my solution:

const displayItemA = () => {
    document.getElementById("item-A").style.display = 'grid';
    document.getElementById("item-B").style.display = 'none';
}
const displayItemB = () => {
    document.getElementById("item-B").style.display = 'grid';
    document.getElementById("item-A").style.display = 'none';
}

const mainContent = ["A1", "A2", "A3", "B1", "B2", "B3"];
const displayMain = (q) => {
    document.getElementById(q).style.display = "grid";
    const toNone = mainContent.filter(e => e !== q);
    for (let i = 0; i < toNone.length; i++) {
        document.getElementById(toNone[i]).style.display = "none";
    }
}

const displayA1 = () => displayMain("A1");
const displayA2 = () => displayMain("A2");
const displayA3 = () => displayMain("A3");
const displayB1 = () => displayMain("B1");
const displayB2 = () => displayMain("B2");
const displayB3 = () => displayMain("B3");
:root {
--main-color:red;
--dark-color:#444;
}
* {
margin:0;
padding:0;
box-sizing:border-box;
}
body {
margin: 0px;
display: grid;
place-items: center;
font-size: 20px;
}

/* repeated element */
.button-nav {
    text-decoration: none;
    color: var(--main-color);
    background: none;
    border: none;
    font-size: 20px;
    text-align: start;
}

.header {
    height: 100px;
    width: 100%;
    display: grid;
    place-items: center;
    border-bottom: 2px solid var(--dark-color);
}

.nav {
    position: relative;
    height: 75px;
    width: 100%;
    border-bottom: 2px solid var(--dark-color);
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 1em;
}
.nav h2 {
    position: absolute;
    left: 30px;
}

.section {
    position: absolute;
    left: 0px;
    min-height: calc(100vh - 175px);
    width: 30%;
    border-right: 2px solid var(--dark-color);
    padding: 30px;
    gap: 1em;
}
.sub-nav {
    display: grid;
    gap: 1em;
}
#item-A, #item-B{ display:none }

.main {
    position: absolute;
    left: 30%;
    min-height: calc(100vh - 175px);
    width: 70%;
    display: grid;
    padding: 30px;
    gap: 1em;
    text-align: center;
}
#A1 { display: grid; }
#A2, #A3, #B1, #B2, #B3 { display: none; }
<header class="header">
        <h1>Header</h1>
    </header>
    <nav class="nav">
        <h2>Nav</h2>
        <button class="button-nav" onclick="displayItemA()">item-A</button>
        <button class="button-nav" onclick="displayItemB()">item-B</button>
    </nav>
    <div>
        <section class="section">
            <h3>Section</h3>
            <br />
            <nav class="sub-nav" id="item-A">
                <button class="button-nav" onclick="displayA1()">A1</button>
                <button class="button-nav" onclick="displayA2()">A2</button>
                <button class="button-nav" onclick="displayA3()">A3</button>
            </nav>
            <nav class="sub-nav" id="item-B">
                <button class="button-nav" onclick="displayB1()">B1</button>
                <button class="button-nav" onclick="displayB2()">B2</button>
                <button class="button-nav" onclick="displayB3()">B3</button>
            </nav>
        </section>
        <main class="main">
            <h3>Main</h3>
            <div id="A1">These are the contents of A1.</div>
            <div id="A2">These are the contents of A2.</div>
            <div id="A3">These are the contents of A3.</div>
            <div id="B1">These are the contents of B1.</div>
            <div id="B2">These are the contents of B2.</div>
            <div id="B3">These are the contents of B3.</div>
        </main>
    </div>

You can also test the code at enter link description here so you can see it on a larger viewport.

Update: I made the items in the "section" area blank by default as per the OP's request. This was done by changing the value of the display of "#item-A" to "none" in the CSS file.

4
Vektor On

const embed = document.getElementById("main-frame");
const navLinksContainer = document.getElementById("nav-links");
const subLinksContainer = document.getElementById("sub-links");

const pageLinks = {
  "item-A": {
    A1: "https://en.wikipedia.org/wiki/Australia",
    A2: "https://en.wikipedia.org/wiki/Austria",
    A3: "https://en.wikipedia.org/wiki/America",
  },
  "item-B": {
    B1: "https://en.wikipedia.org/wiki/Barbados",
    B2: "https://en.wikipedia.org/wiki/Bahamas",
    B3: "https://en.wikipedia.org/wiki/Brazil",
  },
  "item-C": {
    C1: "https://en.wikipedia.org/wiki/Canada",
    C2: "https://en.wikipedia.org/wiki/Cayman_Islands",
    C3: "https://en.wikipedia.org/wiki/Chile",
  },
};

// Creates the page link element
function createPageLink(text, href = "") {
  const listItem = document.createElement("LI");
  const anchor = document.createElement("A");
  anchor.innerHTML = text;
  anchor.href = href;
  listItem.appendChild(anchor);
  listItem.anchor = anchor;
  return listItem;
}

window.onload = function loadHandler() {
  // build all the sub links for each nav link.
  Object.keys(pageLinks).forEach((text) => {
    const subSectionLinks = Object.keys(pageLinks[text]).map((subText) => {
      const subLink = createPageLink(subText, pageLinks[text][subText]);
      subLink.anchor.addEventListener("click", function (event) {
        event.preventDefault();
        embed.src = event.target.href;
      });
      return subLink;
    });

    // replaces the sub links in the left section
    // for each corresponding nav link that's clicked.
    const navLink = createPageLink(text);
    navLink.anchor.addEventListener("click", function (event) {
      event.preventDefault();
      subLinksContainer.innerHTML = "";
      subSectionLinks.forEach((element) =>
        subLinksContainer.appendChild(element)
      );
      embed.src = "";
    });
    navLinksContainer.appendChild(navLink);
  });
};
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

ul {
  list-style-type: none;
}

a {
  text-decoration: none;
  color: red;
  font-size: 28px;
}

a:hover {
  color: #920000;
}

body {
  font-family: Arial, Helvetica, sans-serif;
  font-weight: bold;
  font-size: 32px;
  color: #222;
}

.page {
  width: 702px;
  height: 918px;
  margin: 50px auto;
  display: grid;
  gap: 0;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: repeat(10, 1fr);
  grid-template-areas:
    "h h h h"
    "h h h h"
    "n n n n"
    "s m m m"
    "s m m m"
    "s m m m"
    "s m m m"
    "s m m m"
    "s m m m"
    "s m m m";
}

.page > * {
  border: 1px solid #777;
}

.page > header {
  grid-area: h;
  display: flex;
  justify-content: center;
  align-items: center;
}

.page > nav {
  grid-area: n;
  display: flex;
  flex-direction: row;
  align-items: center;
}

.page > section {
  grid-area: s;
  text-align: center;
  padding-top: 15px;
}

.page > main {
  grid-area: m;
  text-align: center;
}

.page > nav div {
  width: 25%;
  text-align: center;
}

.page > nav ul {
  width: calc(100% - 25%);
  text-align: center;
}

.page > nav ul li {
  display: inline;
}

.page > nav ul li:nth-of-type(n + 2) {
  margin-left: 15px;
}

.page > section ul {
  margin-top: 50px;
  text-align: left;
  text-indent: 40px;
}

.page > section ul li {
  margin-bottom: 10px;
}

.page > main p {
  height: 8%;
  margin-top: 20px;
}

.page > main iframe {
  width: 100%;
  height: calc(92% - 20px);
  border: none;
  overflow-x: hidden;
}
<div class="page">
  <header>Header</header>

  <nav>
    <div>nav</div>
    <ul id="nav-links"></ul>
  </nav>

  <section>
    section
    <ul id="sub-links"></ul>
  </section>

  <main>
    <p>main</p>
    <iframe allowTransparency="true" id="main-frame"></iframe>
  </main>
</div>

Update:

I added a line of code to clear the iframe whenever the user selects a different link from the navigation bar as per the comments made by the OP.