简体   繁体   中英

How to execute the map() function within an event handler

I'm building a law firm website in vanilla JS, that involves a lot of pages with content. I'm trying to have a single page display the different pages of content as the user clicks on different links. I'm doing this by having the html already written with a default property of display: none, and as the user clicks on links, the target link can dynamically change that element's CSS to display: block, while making sure that all other elements are set to display: none, so that it can show one at a time. I have an array that contains all content elements and using splice to remove the target element from the map function which is supposed to set all elements to display: none, and them I'm setting the target element to display: block. The problem is map is not executing when I use it within the event handler, but it does work when I use it outside the event handler. It's not throwing any errors, it's just not setting the display to none.

I've tried different ways of getting the same results such as using the forEach() function, but this is also having a similar result to map. It's not throwing any errors but it's not working. I tried creating a universal class with display: none, and dynamically adding that class to all target elements using map or forEach but that's also not working.

Also, splice was not working because it kept telling me that splice is not a function. After a lot of trial and error, and tons of research the only way I was able to fix this was by manually targeting each element using document.getElementById() which is extremely inefficient. It never worked when I used document.getElementsByClassName(), or when I used document.querySelectorAll()

Problem One: splice is not a function

Grabbing all elements and destructuring them for more efficiency

let contentText = document.getElementsByClassName('content-text');

let [immigrationText, contractsText, divorceText, debtCollectionText, escrowText, expungementText, mediationText, personalInjuryText, willsAndTrustsText] = contentText;

Using splice within the event handler

let immigrationEvent = () => {  
      contentText.splice(0, 1);  
      contentText.map((link) => link.style.display = 'none');  
      immigrationText.style.display = 'block';  
    }; 

Error

Uncaught TypeError: contentText.splice is not a function
    at HTMLLIElement.immigrationEvent

Problem 2: Map feature doesn't execute

Grabbing all links and destructuring them. This is so the user can click on these links, and when they click on them, it should map through all the links that are not being called at the time, and should change the css display to none

let contentLinks = Array.from(document.getElementsByClassName('side- 
 nav-items'));

let [immigration, contracts, divorce, debtCollection, escrow, 
 expungement, mediation, personalInjury, willsAndTrusts] = 
 contentLinks;

Grabbing all elements that contain the content we wish to display, and destructuring them, and adding them to the array called contentText

let contentText = Array.from(document.getElementsByClassName('content- 
 text'));

let [immigrationText, contractsText, divorceText, debtCollectionText, 
 escrowText, expungementText, mediationText, personalInjuryText, 
 willsAndTrustsText] = contentText;

Splicing the array to exclude the page that's currently being called by the user, and then mapping the rest so that they switch the display property to none. This, of course, is the event handler function

let immigrationEvent = () => {
 contentText.splice(0, 1);
 contentText.map((link) => link.style.display = 'none');
 immigrationText.style.display = 'block';
};

let contractsEvent = () => {
 contentText.splice(1, 1);
 contentText.map((link) => link.classList.add('content-hide'));
 contractsText.style.display = 'block';
};

Calling the Event handler function. I'm including 2 examples

immigration.addEventListener('click', immigrationEvent, false);
contracts.addEventListener('click', contractsEvent, false);

Problem 1: Expected result, is I want splice to work when I use some type of select all feature, but it only works when I target them using

getElementById()

Problem 2: I want the map feature to set all target elements within the array to set to display none. Instead what happens is, as I click through the links, it adds the elements to the same page but doesn't hide the previous elements

This results in a "TypeError: contentText.splice is not a function":

let contentText = document.getElementsByClassName('content-text');
contentText.splice(0, 1);  

...because getElementsByClassName returns "an array-like object" (a "live" HTMLCollection , which changes to track with the DOM), not a static array.

To make a copy in a real Array object, use Array.from(document.getElementsByClassName(...)) .

For #2 the problem seems to be outside of the code you posted. Please post the code that reproduces the issue. Note that using .map , while valid, is not recommended if you just want to do something for each element of a collection .

 let immigrationEvent = () => { const elts = Array.from(document.getElementsByClassName("hideme")); const [visibleElt] = elts.splice(0, 1); elts.map((elt) => elt.style.display = 'none'); visibleElt.style.display = 'block'; } document.querySelector("button").addEventListener('click', immigrationEvent, false); 
 <div class="hideme">one</div> <div class="hideme">two</div> <div class="hideme">three</div> <button>Run</button> 

I finally figured it out

Problem one: Nickolay was spot on. I needed to create an instance of my original array in order for JS to be able to parse through it

let contentText = 
 Array.from(document.getElementsByClassName('content- 
 text'));

Array from allowed me to use map, and splice etc.

Problem Two: Thanks to Nickolay I was able to notice that my map feature was working, but every time the splice was running, it was removing elements, and the page was not able to read those changes. Instead I used slice, and targeted the sliced item to be the one that would display the data, and the original array would remain intact, and the map feature would remove the display from all elements in the array. See code below

Destructuring the links that are going to trigger the event

let contentLinks = 
 Array.from(document.getElementsByClassName('side-nav- 
 items'));

let [immigration, contracts, divorce, debtCollection, 
 escrow, expungement, mediation, personalInjury, 
 willsAndTrusts] = contentLinks;

Destructuring the elements that are going to be displayed on the page

let contentText = 
 Array.from(document.getElementsByClassName('content- 
 text'));

let [immigrationText, contractsText, divorceText, 
 debtCollectionText, escrowText, expungementText, 
 mediationText, personalInjuryText, willsAndTrustsText] = 
 contentText;

One of the events that are supposed to display only the target content. We slice the target code block and have it display block while having all elements display none

 let immigrationEvent = () => {
  let targetElement = contentText.slice(0, 1);
  contentText.map((text) => text.style.display = 'none');
  targetElement[0].style.display = 'block';
  console.log(targetElement)
 };

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM