0

I have problem with function called titleClickHandler which doesnt want to execute. This function should remove class "active" from all articles and links after clicking on each link and add class "active" to generated from js li a element which was clicked.

If you need some additional informations just ask.

This is the code:

"use strict";

const links = document.querySelectorAll(".titles a");
const optArticleSelector = ".art-post",
  optTitleSelector = ".post-title",
  optTitleListSelector = ".articles-list";

const titleClickHandler = function (event) {
  event.preventDefault();
  const articles = document.querySelectorAll(".posts .art-post");
  for (let article of articles) {
    article.classList.remove("active");
  }
  for (let link of links) {
    link.classList.remove("active");
  }
  console.log("ok");
  document
    .querySelector(`a[href="${event.target.hash}"]`)
    .classList.add("active");
  document.querySelector(`${event.target.hash}`).classList.add("active");
};

function generateTitleLinks() {
  const articles = document.querySelectorAll(".posts .art-post");
  function clearMessages() {
    document.querySelector(".articles-list").innerHTML = "";
  }
  clearMessages();
  for (let article of articles) {
    const articleId = article.getAttribute("id");
    const titleList = document.querySelector(optTitleListSelector);
    const articleTitle = article.querySelector(optTitleSelector).innerHTML;
    const linkHTML = `<li class="titles"><a href="#${articleId}">${articleTitle}</a></li>`;
    titleList.innerHTML = titleList.innerHTML + linkHTML;
  }
}
generateTitleLinks();
for (let link of links) {
  link.addEventListener("click", titleClickHandler);
}
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <link rel="stylesheet" href="css/style.css" />
  </head>
  <body>
    <div class="container">
      <h1>My blog</h1>
      <div class="inner-container">
        <div class="container-col">
          <h2>All Posts</h2>
          <ul class="articles-list"></ul>
        </div>
        <section class="container-col posts">
          <article class="art-post active" id="article-1">
            <h3 class="post-title">Article 1</h3>
            <p class="author">by Marek</p>
            <p class="post">
              Lorem ipsum
            </p>
          </article>
          <article class="art-post" id="article-2">
            <h3 class="post-title">Article 2</h3>
            <p class="author">by Darek</p>
            <p class="post">
              Lorem, ipsum
            </p>
          </article>
          <article class="art-post" id="article-3">
            <h3 class="post-title">Article 3</h3>
            <p class="author">by Anna</p>
            <p class="post">
              Lorem ipsum 
            </p>
          </article>
          <article class="art-post" id="article-4">
            <h3 class="post-title">Article 4</h3>
            <p class="author">by Mateusz</p>
            <p class="post">
              Lorem ipsum
            </p>
          </article>
          <article class="art-post" id="article-5">
            <h3 class="post-title">Article 5</h3>
            <p class="author">by Adrian</p>
            <p class="post">
              Lorem ipsum
            </p>
          </article>
          <article class="art-post" id="article-6">
            <h3 class="post-title">Article 6</h3>
            <p class="author">by Marek</p>
            <p class="post">
              Lorem ipsum
            </p>
          </article>
          <article class="art-post" id="article-7">
            <h3 class="post-title">Article 7</h3>
            <p class="author">by Stranger</p>
            <p class="post">
              Lorem, ipsum
            </p>
          </article>
          <article class="art-post" id="article-8">
            <h3 class="post-title">Article 8</h3>
            <p class="author">by Stranger</p>
            <p class="post">
              Lorem ipsum
            </p>
          </article>
          <article class="art-post" id="article-9">
            <h3 class="post-title">Article 9</h3>
            <p class="author">by Stranger</p>
            <p class="post">
              Lorem ipsum
            </p>
          </article>
          <article class="art-post" id="article-10">
            <h3 class="post-title">Article 10</h3>
            <p class="author">by Stranger</p>
            <p class="post">
              Lorem ipsum dolor sit amet consectetur adipisicing elit. Tempora
              placeat.
            </p>
          </article>
        </section>
        <div class="container-col">
          <h2 class="tags"></h2>
          <h2 class="authors"></h2>
        </div>
      </div>
    </div>
    <script src="js/script.js"></script>
  </body>
</html>

4
  • Does the function not run, or not do what is required? Commented Jan 3, 2023 at 10:29
  • where is the onclick ? Commented Jan 3, 2023 at 10:30
  • 2
    You are creating the titles elements dynamically, but the const links = document.querySelectorAll(".titles a"); is called on load. At the time you create that variable, no links exist so the variable will always be empty. Either update links at the end of generateTitleLinks, or call the querySelectorAll and assign to a variable right before the value will be used. Commented Jan 3, 2023 at 10:50
  • your a link is created in the function generateTitleLinks. Just after you put the addeventlistener, in fact thinking it's after but it's not! You should make a callback on generateTitleLinks and on callback fire the link addeventlistener Commented Jan 3, 2023 at 11:03

1 Answer 1

1

I added the constants that were specific to generateTitleLinks() inside the method.

I cleaned up the code a bit. Creating methods within methods always creates messy code. It's better to use variables to explain the code.

Always to try create variables outside loops, so you don't have to create new variables for each iteration.

Renamed .titles to .title.

I think it's easier (and less memory consuming) to only add a single click listener to the whole menu. By doing that, I can just select the target that triggers the listener, loop through all menu items to remove .active from all menu items.

const optTitleListSelector = ".articles-list";
const titleList = document.querySelector(optTitleListSelector);

function generateTitleLinks() {
  const articles = document.querySelectorAll(".posts .art-post");
  const optArticleSelector = ".art-post",
        optTitleSelector = ".post-title";
      
  let clearMessages = '';
  document.querySelector(".articles-list").innerHTML = clearMessages;
  
  let articleId, articleTitle, linkHTML;
  
  for (let article of articles) {
    articleId = article.getAttribute("id");
    articleTitle = article.querySelector(optTitleSelector).innerHTML;
    linkHTML = `<li class="title"><a href="#${articleId}">${articleTitle}</a></li>`;
    titleList.innerHTML += linkHTML;
  }
}

generateTitleLinks();

function addActiveClassToClickedMenuItem(event) {
  let clickedLiElement = event.target.parentElement;
  let menuElements = titleList.querySelectorAll('li');
  
  for (let liElement of menuElements) {
    liElement.classList.remove('active');    
  }

  clickedLiElement.classList.add('active');
}

titleList.addEventListener('click', addActiveClassToClickedMenuItem);
.title.active {
  background-color: yellow;
}
<h1>My blog</h1>
<div class="inner-container">
  <div class="container-col">
    <h2>All Posts</h2>
    <ul class="articles-list"></ul>
  </div>

  <section class="container-col posts">
    <article class="art-post active" id="article-1">
      <h3 class="post-title">Article 1</h3>
      <p class="author">by Marek</p>
      <p class="post">
        Lorem ipsum
      </p>
    </article>
    <article class="art-post" id="article-2">
      <h3 class="post-title">Article 2</h3>
      <p class="author">by Darek</p>
      <p class="post">
        Lorem, ipsum
      </p>
    </article>
    <article class="art-post" id="article-3">
      <h3 class="post-title">Article 3</h3>
      <p class="author">by Anna</p>
      <p class="post">
        Lorem ipsum
      </p>
    </article>
    <article class="art-post" id="article-4">
      <h3 class="post-title">Article 4</h3>
      <p class="author">by Mateusz</p>
      <p class="post">
        Lorem ipsum
      </p>
    </article>
    <article class="art-post" id="article-5">
      <h3 class="post-title">Article 5</h3>
      <p class="author">by Adrian</p>
      <p class="post">
        Lorem ipsum
      </p>
    </article>
    <article class="art-post" id="article-6">
      <h3 class="post-title">Article 6</h3>
      <p class="author">by Marek</p>
      <p class="post">
        Lorem ipsum
      </p>
    </article>
    <article class="art-post" id="article-7">
      <h3 class="post-title">Article 7</h3>
      <p class="author">by Stranger</p>
      <p class="post">
        Lorem, ipsum
      </p>
    </article>
    <article class="art-post" id="article-8">
      <h3 class="post-title">Article 8</h3>
      <p class="author">by Stranger</p>
      <p class="post">
        Lorem ipsum
      </p>
    </article>
    <article class="art-post" id="article-9">
      <h3 class="post-title">Article 9</h3>
      <p class="author">by Stranger</p>
      <p class="post">
        Lorem ipsum
      </p>
    </article>
    <article class="art-post" id="article-10">
      <h3 class="post-title">Article 10</h3>
      <p class="author">by Stranger</p>
      <p class="post">
        Lorem ipsum dolor sit amet consectetur adipisicing elit. Tempora placeat.
      </p>
    </article>
  </section>

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.