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

Is there a way to retrieve all "a" tags with an "href" attribute that contains the term "youtube"?

My goal is to capture all a tags that have the href attribute containing the word youtube. This task requires the use of jquery. ...

Verify all inputs are complete in the FullScreenForm

I have been working on implementing a form from this website: http://tympanus.net/Development/FullscreenForm/ My main objective is to validate each input when the form is submitted and display any errors that may arise. To achieve this, I have already se ...

Validation method in jQuery for a set of checkboxes with distinct identifiers

I am faced with a situation where I have a set of checkboxes that, due to the integration with another platform, must have individual names even though they are all interconnected. <div class="form-group col-xs-6 checkbox-group"> <label cla ...

Show two <p>'s next to each other

I am trying to arrange 2 paragraphs side by side. <p class = "firstClass">This is the first paragraph.</p> <p class = "secondClass">This is the second paragraph.</p> Result: This is the first paragraph. This is the second paragra ...

Trigger the reactive helper again when there is a change in the $scope

I am working with a reactive data source in Angular-Meteor and I want to find a method to trigger the reactive function to run again after modifying another $scope value. Specifically, I aim to change the sorting order based on $scope.model.sort: angular. ...

What is the most effective way to share data among components in React?

I recently delved into learning about react and find myself puzzled on how to pass data between two components. Presently, I have set up 2 functions in the following manner: First, there's topbar.tsx which displays information for the top bar, inclu ...

Top method for extracting mesh vertices in three.js

Being new to Three.js, I may not be approaching this in the most optimal way, I start by creating geometry like this: const geometry = new THREE.PlaneBufferGeometry(10,0); Next, I apply a rotation: geometry.applyMatrix( new THREE.Matrix4().makeRotation ...

What is the process for developing an Alphabetizer Program?

I have been working on this and I am having trouble getting the "alphabetized" version to display. I've tried a few things already, but I'm not sure what is missing or needs to be changed. Any advice on how to fix this would be greatly appreciate ...

Downloading and uploading images using AngularJS: A complete guide

I have developed an Angularjs 1.5.0 web application that needs to interact with a REST-based web service I created using dropwizard and jersey. The web service has been tested and is working perfectly. The method in the REST web service looks like this: ...

Error: The React Material-UI modal is encountering a type error where it cannot access the property 'hasOwnProperty' of an undefined value

Whenever I include a modal in one of my classes, I encounter this error. Error: Unable to access property 'hasOwnProperty' of undefined Here is a simple example where I am attempting to display a basic modal at all times. Any suggestions? I h ...

What is the method to retrieve results using 'return' from NeDB in vue.js?

Seeking assistance on retrieving data from NeDB within a method in a .vue file using electron-vue. Currently, I am aware that the data can be stored in a variable, but my preference is to fetch it using 'return' as I intend to utilize the result ...

Enhancing user experience with Ajax login forms that seamlessly integrate with browser password remember functionality

I recently implemented an ajax-based login form on my website, but it seems that browsers are not recognizing it as a login form and therefore not offering to remember passwords for easier login access. Once the submit button is clicked, the entered value ...

Increase the Speed of setInterval in JavaScript

I'm currently experimenting with gradually decreasing the interval at which a function is executed within a setInterval method. Below is a simplified example code snippet: var speed = 100; window.setInterval( speed -= 0.01 , speed); I suspect that ...

Tips for configuring page-specific variables in Adobe DTM

Although I have integrated Adobe Analytics for tracking on my website, I am facing difficulty in properly defining the variables. This is how I attempted to define the variable: var z = new Object(); z.abc = true; z.def.ghi = true Despite following the ...

Strategies for delaying the loading of CSS when importing

import 'react-dates/lib/css/_datepicker.css' The CSS mentioned can be deferred since it is not critical. Is it possible to defer the loading of CSS when utilizing import? I found information on deferring CSS loading using <link> from Goo ...

Employing CSS animations to elevate div elements

Currently, I am working on animating a table of divs and trying to achieve an effect where a new div enters and "bumps up" the existing ones. In my current setup, Message i3 is overlapping Message 2 instead of bumping it up. How can I make Messages 1 and 2 ...

How do I convert the object value/data to lowercase in JavaScript using underscore for an HTML5 document?

I am working with an array of objects (arr) where each object consists of 3 properties (Department, Categories, ProductTypes). The values for these properties are a mix of upper and lower case. To perform a comparison between arr and a search filter (alrea ...

Iterate through each key in the response JSON object using a variable named "a

Here is a snippet of my code: var roomid= roomIds[i] const Availabilitydata = await AvailResponse.json(); availableroomsArray.push(Availabilitydata); app.get("/api/availability", (req, res) => { res.json({ indicateur: availableroomsA ...

Align text to the center within the dropdown menu for all web browsers

Is it possible to center align text in a select drop down for all browsers? It appears centered in Firefox, but shifts to the left in Chrome and Safari. CSS: .challenge{ max-width: 850px; width: 98%; height: 50px; background: #ffffff; margin: 3 ...

Typing the url in the address bar when using Angular's ui-router

Two distinct states are present: .state('test', { url: '/test', templateUrl: 'js/angular/views/test.html', controller: 'UserController', }) .state('test.list', { url: ' ...