Changing direction of arrow upon dropdown menu opening with JavaScript

I have developed a piece of code that enables users to click on a div in order to reveal a dropdown menu containing radio buttons. My goal is to make the arrows rotate 180 degrees when the dropdown menus are opened, and then return to their original position when the dropdown menus are closed. I have inserted a few lines of code within the existing code block, and I believe I am close to solving this issue. Any advice or suggestions would be greatly appreciated. Thank you! I will provide the HTML, CSS, and JS files for review.

<main class="subscription__container">
        <section
          id="preferences"
          class="subscription__container--preferences box"
        >
          <div class="question__container">
            <h3 class="question__container--title">
              How do you drink your coffee?
            </h3>
            <img
              class="question__container--img"
              src="../assets/plan/desktop/icon-arrow.svg"
              alt="arrow"
            />
          </div>
          <div class="options__container">
            <div class="options__container--option">
              <input
                id="capsule"
                type="radio"
                data-preference="Capsule"
                value="Capsule"
                name="preferences"
              />
              <label class="test__trail" for="capsule">
                <h4 class="options__container--title">Capsule</h4>
                <p class="options__container--description">
                  Compatible with Nespresso systems and similar brewers.
                </p>
              </label>
            </div>
            <div class="options__container--option">
              <input
                id="filter"
                type="radio"
                data-preference="Filter"
                value="Filter"
                name="preferences"
              />
              <label class="test__trail" for="filter">
                <h4 class="options__container--title">Filter</h4>
                <p class="options__container--description">
                  For pour over or drip methods like Aeropress, Chemex, and V60.
                </p>
              </label>
            </div>
            <div class="options__container--option">
              <input
                id="espresso"
                type="radio"
                data-preference="Espresso"
                value="Espresso"
                name="preferences"
              />
              <label class="test__trail" for="espresso">
                <h4 class="options__container--title">Espresso</h4>
                <p class="options__container--description">
                  Dense and finely ground beans for an intense, flavorful
                  experience.
                </p>
              </label>
            </div>
          </div>
        </section>
        <section id="bean" class="subscription__container--beans box">
          <div class="question__container">
            <h3 class="question__container--title">What type of coffee?</h3>
            <img
              class="question__container--img"
              src="../assets/plan/desktop/icon-arrow.svg"
              alt="arrow"
            />
          </div>
          <div class="options__container">
            <div class="options__container--option">
              <input
                id="single"
                type="radio"
                data-bean="Single"
                value="Single"
                name="beanType"
              />
              <label class="test__trail" for="single">
                <h4 class="options__container--title">Single Origin</h4>
                <p class="options__container--description">
                  Distinct, high quality coffee from a specific family-owned
                  farm.
                </p>
              </label>
            </div>
            <div class="options__container--option">
              <input
                id="decaf"
                type="radio"
                data-bean="Decaf"
                value="Decaf"
                name="beanType"
              />
              <label class="test__trail" for="decaf">
                <h4 class="options__container--title">Decaf</h4>
                <p class="options__container--description">
                  Just like regular coffee, except the caffeine has been
                  removed.
                </p>
              </label>
            </div>
            <div class="options__container--option">
              <input
                id="blended"
                type="radio"
                data-preference="Blended"
                value="Blended"
                name="beanType"
              />
              <label class="test__trail" for="blended">
                <h4 class="options__container--title">Blended</h4>
                <p class="options__container--description">
                  Combination of two or three dark roasted beans of organic
                  coffees.
                </p>
              </label>
            </div>
          </div>
        </section>
.question__container--img.rotate {
  transform: rotate(180deg);
}

//
const questionBox = document.getElementsByClassName("question__container");
const arrows = document.querySelectorAll(".question__container--img");
[...questionBox].forEach((el) =>
  el.addEventListener("click", (event) => {
    const subMenu = event.target.parentElement.parentElement.querySelector(
      ".options__container"
    );
    subMenu.classList.toggle("open");
    arrows.forEach((arrow) => arrow.classList.toggle("rotate"));
  })
);
//

The current error message in the console states.. Uncaught TypeError: Cannot read property 'toggle' of undefined at HTMLDivElement. ?

Answer №1

It happens because the variable arrows holds a collection of all elements with the class .question__container--img, not just one specific element. To access the correct arrow, you should retrieve it from the el parameter within the event listener function and not from the entire document:

//
const questionBox = document.getElementsByClassName("question__container");
[...questionBox].forEach((el) =>
{
  const arrow = el.querySelector(".question__container--img");
  el.addEventListener("click", (event) => {
    const subMenu = event.target.parentElement.parentElement.querySelector(
      ".options__container"
    );
    subMenu.classList.toggle("open");
    arrow.classList.toggle("rotate");
  })
});
//
.question__container--img.rotate {
  transform: rotate(180deg);
}
<main class="subscription__container">
        <section
          id="preferences"
          class="subscription__container--preferences box"
        >
          <div class="question__container">
            <h3 class="question__container--title">
              How do you drink your coffee?
            </h3>
            <img
              class="question__container--img"
              src="../assets/plan/desktop/icon-arrow.svg"
              alt="arrow"
            />
          </div>
          <div class="options__container">
            <div class="options__container--option">
              <input
                id="capsule"
                type="radio"
                data-preference="Capsule"
                value="Capsule"
                name="preferences"
              />
              <label class="test__trail" for="capsule">
                <h4 class="options__container--title">Capsule</h4>
                <p class="options__container--description">
                  Compatible with Nespresso systems and similar brewers.
                </p>
              </label>
            </div>
            <div class="options__container--option">
              <input
                id="filter"
                type="radio"
                data-preference="Filter"
                value="Filter"
                name="preferences"
              />
              <label class="test__trail" for="filter">
                <h4 class="options__container--title">Filter</h4>
                <p class="options__container--description">
                  For pour over or drip methods like Aeropress, Chemex, and V60.
                </p>
              </label>
            </div>
            <div class="options__container--option">
              <input
                id="espresso"
                type="radio"
                data-preference="Espresso"
                value="Espresso"
                name="preferences"
              />
              <label class="test__trail" for="espresso">
                <h4 class="options__container--title">Espresso</h4>
                <p class="options__container--description">
                  Dense and finely ground beans for an intense, flavorful
                  experience.
                </p>
              </label>
            </div>
          </div>
        </section>
        <section id="bean" class="subscription__container--beans box">
          <div class="question__container">
            <h3 class="question__container--title">What type of coffee?</h3>
            <img
              class="question__container--img"
              src="../assets/plan/desktop/icon-arrow.svg"
              alt="arrow"
            />
          </div>
          <div class="options__container">
            <div class="options__container--option">
              <input
                id="single"
                type="radio"
                data-bean="Single"
                value="Single"
                name="beanType"
              />
              <label class="test__trail" for="single">
                <h4 class="options__container--title">Single Origin</h4>
                <p class="options__container--description">
                  Distinct, high quality coffee from a specific family-owned
                  farm.
                </p>
              </label>
            </div>
            <div class="options__container--option">
              <input
                id="decaf"
                type="radio"
                data-bean="Decaf"
                value="Decaf"
                name="beanType"
              />
              <label class="test__trail" for="decaf">
                <h4 class="options__container--title">Decaf</h4>
                <p class="options__container--description">
                  Just like regular coffee, except the caffeine has been
                  removed.
                </p>
              </label>
            </div>
            <div class="options__container--option">
              <input
                id="blended"
                type="radio"
                data-preference="Blended"
                value="Blended"
                name="beanType"
              />
              <label class="test__trail" for="blended">
                <h4 class="options__container--title">Blended</h4>
                <p class="options__container--description">
                  Combination of two or three dark roasted beans of organic
                  coffees.
                </p>
              </label>
            </div>
          </div>
        </section>

Answer №2

One way to avoid toggling rotate is to directly modify its transform using jQuery:

$("item").css("transform", "rotate(0deg)")

You can also achieve this with vanilla JavaScript:

item.style.transform = "rotate(0deg)"

Remember to revert the changes when necessary. I hope this solution works for you!

Answer №3

To modify the rotation of arrows, instead of using

arrows.classList.toggle("rotate");
, you can use
arrows.style.transform = "rotate(180/0)"; 
with an if/else statement.

Additionally, for your subMenu CSS, consider adding display: and then adjust the display property using

subMenu.style.display = "none/block";
once more with if/else logic.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What steps are involved in implementing Local fonts in theme UI for Next JS?

I am currently developing an application using next JS with [theme-UI][1]. However, I need to implement local or custom fonts in my project and I'm unsure of how to do this. Below is the current theming setup: const theme = { fonts: { ...

bridging information from tables with text fields in forms

I am working on an HTML/CSS page that utilizes a table layout filled with buttons to mimic a T9 keypad design. Within the page, I have a form containing two text fields. My aim is to populate these text fields with numbers based on the values from the tab ...

Firefox does not allow contenteditable elements to be edited if they are nested inside a parent element that is draggable

Here is a basic HTML example: <div draggable=true> <div contenteditable=true>can't edit me</div> </div> When testing in Chrome, I noticed that I was able to edit the contents of the contenteditable div, however, this functi ...

"Enhance user experience with autofocusing on form fields within an overlay

Despite spending hours searching, I can't seem to figure out a seemingly simple task. I am trying to set autofocus on a form field within an overlay that opens when a button is clicked. The overlay is implemented using basic jQuery overlay code. $(f ...

Ways to refresh the main frame

Here is an example of parent code: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Parent</title> </head> <body> <iframe src="https://dl.dropboxusercontent.com/u/4017788/Labs/child.html" width ...

Problem with Azure Table JavaScript Solution

When attempting to utilize JavaScript to access Azure Storage Tables, I encountered an error that reads: "Error getting status from the table: TypeError: tableServiceClient.getTableClient is not a function." Despite finding multiple successful examples onl ...

What is the best way to center align tabs in a Bootstrap 4 list?

I am working with tabs structured like this: <link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet"/> <ul class="nav nav-pills mb-3" id="pills-tab" role="tablist"> <li class="nav-item"> ...

Developing a music playlist using javascript/angular (replicating array elements while linking nested objects)

I am currently working on creating a playlist for a music player within an Angular app that includes a shuffle feature. The actual shuffle function is not the issue, as I am utilizing the Fisher Yates Shuffle method and it is functioning correctly. When th ...

The video.play() function encountered an unhandled rejection with a (notallowederror) on IOS

Using peer.js to stream video on a React app addVideoStream(videoElement: HTMLVideoElement, stream: MediaStream) { videoElement.srcObject = stream videoElement?.addEventListener('loadedmetadata', () => { videoElement.play() ...

I'm trying to determine which jQuery event would be more beneficial for my needs - should I go with

I'm facing a dilemma On my website, I need to capture the value of a span within a modal. The value changes when the modal is opened and reverts to the old value when closed. This particular value represents the cart total in my online store. Wheneve ...

Looking for assistance with a JavaScript code snippet

I have encountered an issue while iterating through receipts in the given code snippet. The objective is to fetch the receipt number for each receipt and add it to a JSON object. However, I am facing a problem where the same receipt is appearing in two sep ...

Basic image slider featuring adjustable heights

I'm currently working on a basic content slider, but I've encountered an issue where the container doesn't expand as new content slides in. It seems to be related to the absolute positioning of the content items. If I don't use absolute ...

Develop content specific to different geographic locations for a web application using PHP

I have been working on a PHP-based online shopping website but have not had much success with it. example.com After trying multiple approaches without success, I have decided to implement an admin feature for adding locations. For instance, if I add "Mad ...

I would like to mention a website without inserting a direct hyperlink, for example, in the Safari browser

Is there a way to prevent a website name from becoming a clickable link in Safari? In my marketing email, I am highlighting the websites of both my client and their competitor. When mentioning the competitor's site "sitename.com," I want to avoid cre ...

Ensuring the positioning of input fields and buttons are in perfect alignment

I've been struggling to align two buttons next to an input field, but every time I try, I end up messing everything up. I managed to align an input field with a single button, but adding a second button is proving to be quite difficult. Here is ...

Gulp-sourcemaps now exclusively provides the source JavaScript file

Whenever I try to use sourcemaps, I only get the source value returned no matter what. Broswerify.js // if custom browserify options are needed var customOptions = { entries: ['./frontend/js/app.js'], debug: true }; var finalOpts = assi ...

Place a fresh banner on top of the Ionicon icon

I recently started using Ionicons from and I am not too familiar with css. My question is, can a banner that says 'new' be overlaid on the top right corner of the Icon? Is there a simple or standard method to achieve this? (whether it's an ...

Divide a string into an array starting from the end

I have a unique phrase. var phrase = "LoremipsumdolorsitametconsectetuadipiscingelitSeddoeiusmodtemporincididuntutlaboreetaliqua"; I am interested in dividing it into chunks of 11 characters starting from the end. Currently, I use: function splitPhrase ...

Changing the Color Scheme of Twitter BootstrapRevamping the Color Palette

I am interested in updating the color scheme of a website that I modeled after this example: http://getbootstrap.com/examples/navbar/ So far, I have successfully changed the background color of the entire page using: body{background-color:#XXXXXX} Howev ...

When attempting to use the jsonify method on a variable within an html file, the output is not displayed

Is it possible to store "jsonify" in a variable? I find the pure json format of "return jsonify(data)" unappealing, so I am looking for a way to enhance it using an HTML template with proper indentation. Here's the python code I have: from flask impo ...