/    Sign up×
Community /Pin to ProfileBookmark

classList.remove not working and other stuff

I have some problems.

  • 1. First one witch is the simplest one. I have some buttons and I want to add a class when they are active and remove it from the others but for some reason is not working.
    Code:
    [code]const portfolioButtons = document.querySelectorAll(‘[data-content-target]’);

    portfolioButtons.forEach(button => {
    button.addEventListener(‘click’, ()=> {
    const targetContent = document.querySelector(button.dataset.contentTarget);
    const portfolioContent = document.querySelectorAll(‘[data-portfolio-content]’);

    if(portfolioContent.classList === ‘containers-active’) {return};

    portfolioContent.forEach(container => container.classList.remove(‘containers-active’))
    targetContent.classList.add(‘containers-active’);

    button.forEach(li => li.classList.remove(‘portfolio__button-active’));
    button.classList.add(‘portfolio__button-active’);
    });
    });[/code]

  • 2. This one is a bit tricky and I hope that I can explain it in such a way that you can understand.
    I have a section of the site that has a different style for mobile and desktop. The thing is that I also want different functionalities because on mobile there are some weird interactions if I add the desktop functionality.
    The desktop code is the first code you see in this post and THIS is the mobile code.
    [code]
    const portfolioButtons = document.querySelectorAll(‘[data-content-target]’);

    portfolioButtons.forEach(button => {
    button.addEventListener(‘click’, ()=> {
    const targetContent = document.querySelector(button.dataset.contentTarget);
    targetContent.classList.toggle(‘containers-active’);
    button.classList.toggle(‘portfolio__button-active’);
    });
    });
    [/code]

  • 3. And the last one. I want the active class to be on the first element by default on the desktop version. The thing is that if I add it in HTML as I would normally do it will be active on the mobile too. If I will make different classes and use media queries then the javaScript won’t work.
  • Here is:
    Website – https://wonderful-jones-0b8d39.netlify.com/
    Code Files – https://github.com/CodyHiII/3rd-Portfolio

    1 way I could fix all of this is by using different data sets and different classes for both mobile and desktop and keep both codes in JS but I don’t know if it’s worth it.

    to post a comment
    JavaScript

    32 Comments(s)

    Copy linkTweet thisAlerts:
    @SempervivumAug 04.2019 — In this line:

    `if(portfolioContent.classList === 'containers-active') {return};</C><br/>
    I spot two errors:
    <LIST type="decimal"><LI>1. portfolioContent is a node <B>[b]list[/b]</B>, you can access the class list of a single element only.</LI>
    <LI>2. classList is not a string, you need to use <C>
    contains</C>: <C>if(element.classList.contains( 'containers-active')) {return};`
    Copy linkTweet thisAlerts:
    @SempervivumAug 04.2019 — PS: The console shows up one more error:
    button.forEach is not a function[/quote]
    `button` is a single element, not an array or nodelist, thus forEach is not available.
    Copy linkTweet thisAlerts:
    @codyhillauthorAug 04.2019 — @Sempervivum#1607146 Awesome! Fixed point 1. Any suggestions for 2 and 3 :D ?
    Copy linkTweet thisAlerts:
    @SempervivumAug 04.2019 — Regarding 2) You can use matchMedia in order to check the width of the window and then switch the javacript based on the result:

    https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia
    Copy linkTweet thisAlerts:
    @codyhillauthorAug 04.2019 — @Sempervivum#1607149 Oh, Did know this exists. Thanks!
    Copy linkTweet thisAlerts:
    @codyhillauthorAug 04.2019 — @Sempervivum#1607149 I added matchMedia on document eventListener on DOMContentLoaded.

    Oviestlly that work only on load. But is there a way to make it work even if you don't reload the page? I tried eventListener on window resize but that doesn't work
    Copy linkTweet thisAlerts:
    @SempervivumAug 04.2019 — You can add an eventlistener to the media query list, so that you are informed about changes:

    https://developer.mozilla.org/en-US/docs/Web/API/MediaQueryList
    Copy linkTweet thisAlerts:
    @SempervivumAug 04.2019 — As I found this interesting I created a fiddle and it's working fine:

    https://jsfiddle.net/Sempervivum/sdfu0kw8/3/
    Copy linkTweet thisAlerts:
    @codyhillauthorAug 05.2019 — @Sempervivum#1607168 Ok, this is nice!

    What is mq1 those ?
    Copy linkTweet thisAlerts:
    @SempervivumAug 05.2019 — Don't understand your question. I followed the description on MDN. mql is a media query list object.
    Copy linkTweet thisAlerts:
    @codyhillauthorAug 05.2019 — @Sempervivum#1607178 I thought that L is a 1.
    Copy linkTweet thisAlerts:
    @SempervivumAug 05.2019 — Yes, the "l" is similar to a "1" in jsfiddle.
    Copy linkTweet thisAlerts:
    @codyhillauthorAug 05.2019 — @Sempervivum#1607181 Well this works only if you resize the page. And for this, I need it to work even if you don't resize the page

    You can see it here https://wonderful-jones-0b8d39.netlify.com/
    Copy linkTweet thisAlerts:
    @SempervivumAug 05.2019 — You can get the imformation `matches` from the object any time you need:

    https://jsfiddle.net/Sempervivum/sdfu0kw8/7/
    Copy linkTweet thisAlerts:
    @codyhillauthorAug 05.2019 — @Sempervivum#1607184 It doesn't work for me like that.

    this is the code
    const portfolioButtons = document.querySelectorAll('[data-content-target]');
    const query = window.matchMedia('(min-width: 800px)');

    query.addListener(event =&gt; {
    if(event.matches) {
    portfolioButtons.forEach(button =&gt; {
    button.addEventListener('click', ()=&gt; {
    const targetContent = document.querySelector(button.dataset.contentTarget);
    const portfolioContent = document.querySelectorAll('[data-portfolio-content]');
    <br/>
    <i> </i> portfolioContent.forEach(container =&gt; container.classList.remove('containers-active'))
    <i> </i> targetContent.classList.add('containers-active');
    <i> </i>
    <i> </i> portfolioButtons.forEach(li =&gt; li.classList.remove('portfolio__button-active'));
    <i> </i> button.classList.add('portfolio__button-active');
    <i> </i> });
    <i> </i> });
    <i> </i>} else {
    <i> </i> portfolioButtons.forEach(button =&gt; {
    <i> </i> button.addEventListener('click', ()=&gt; {
    <i> </i> const targetContent = document.querySelector(button.dataset.contentTarget);
    <i> </i> targetContent.classList.toggle('containers-active');
    <i> </i> button.classList.toggle('portfolio__button-active');
    <i> </i> });
    <i> </i> });
    <i> </i>}
    });
    Copy linkTweet thisAlerts:
    @SempervivumAug 05.2019 — You have to take [b]add[/b]EventListener literally: Each time you call it, a new listener is added and those having been added previously [b]remain[/b]. In your case you need to remove the previous listener before you add the new one.

    Note that removing is possible only if you added a named function.

    When writing this another option came across my mind: You might consider using the same listener function permanently and inside this function read `matches` and switch the further processing based on it. This seems to be more easy and clear than removing and adding event listeners.
    Copy linkTweet thisAlerts:
    @codyhillauthorAug 05.2019 — @Sempervivum#1607187 So I need to put all the code in a function and call it?
    Copy linkTweet thisAlerts:
    @SempervivumAug 05.2019 — Yes, IMO this would be the best option, clear and simple. Like this:

    https://jsfiddle.net/Sempervivum/sdfu0kw8/13/
    Copy linkTweet thisAlerts:
    @Steve_R_JonesmoderatorAug 05.2019 — ["classList.remove not wirking and other stuff","classList.remove not working and other stuff"]
    Copy linkTweet thisAlerts:
    @codyhillauthorAug 05.2019 — @Sempervivum#1607193 Same thing happens. Here is a code pen with the code.

    https://codepen.io/raul-rogojan/pen/PMOBGo?editors=1000
    Copy linkTweet thisAlerts:
    @SempervivumAug 05.2019 — My proposal looks like this:

    https://codepen.io/Sempervivum/pen/KOyBEZ

    (I changed the javascript only).

    There is one issue: In mobile view the header is not visible when the content is expanded. Shurely can be fixed easily by a media query.
    Copy linkTweet thisAlerts:
    @codyhillauthorAug 05.2019 — @Sempervivum#1607200 I don't see any changes, maybe you forgot to save it :D?
    Copy linkTweet thisAlerts:
    @codyhillauthorAug 05.2019 — @Sempervivum#1607200 If you mean that the buttons are not visible when the content is extended, that's because I have an active class with color: white background: var(clr); I just did not add the var in the code pen.
    Copy linkTweet thisAlerts:
    @SempervivumAug 05.2019 — I do see them. The javascript reads like this now, only one permanent listener and an if statement for the result of the media query:
    const portfolioButtons = document.querySelectorAll('[data-content-target]');
    const query = window.matchMedia('(min-width: 800px)');

    <i> </i> portfolioButtons.forEach(button =&gt; {
    <i> </i> button.addEventListener('click', () =&gt; {
    <i> </i> if (query.matches) {
    <i> </i> console.log('wide window');

    <i> </i> const targetContent = document.querySelector(button.dataset.contentTarget);
    <i> </i> const portfolioContent = document.querySelectorAll('[data-portfolio-content]');

    <i> </i> portfolioContent.forEach(container =&gt; container.classList.remove('containers-active'))
    <i> </i> targetContent.classList.add('containers-active');

    <i> </i> portfolioButtons.forEach(li =&gt; li.classList.remove('portfolio__button-active'));
    <i> </i> button.classList.add('portfolio__button-active');
    <i> </i> } else {
    <i> </i> console.log('narrow window');
    <i> </i> const targetContent = document.querySelector(button.dataset.contentTarget);
    <i> </i> targetContent.classList.toggle('containers-active');
    <i> </i> button.classList.toggle('portfolio__button-active');
    <i> </i> }
    <i> </i> });
    <i> </i> });
    Copy linkTweet thisAlerts:
    @SempervivumAug 05.2019 — PS: I posted the wrong code at first and then edited, please reload this page to view the final version.
    Copy linkTweet thisAlerts:
    @SempervivumAug 05.2019 — PPS: You are right, I didn't save the pen. I tried to verify by opening it from the link on my posting here but unfortunately this opened the same, unsaved version. Sorry for the confusion!
    Copy linkTweet thisAlerts:
    @codyhillauthorAug 05.2019 — @Sempervivum#1607207 The way you write it makes sense. I fix the issue nr 3 also. But I am not quite sure if what I did is actually good. I added 2 more classes to the first li, with one I only selected that li in JS and the other one is the save as the active class but with another name and I move it on click.

    But now I have another bug that I have no idea how to fix.

    If one of the tab is open when you go from mobile to desktop and desktop to mobile it remains active. Activate fre tab on mobile then go on desktop and see what happens. It's kinda funny :). I tried fixing it with window.addEventListener('resize' e =&gt; {<br/>
    portfolioContent.classList.remove('containers-active')<br/>
    )


    But doesn't work
    Copy linkTweet thisAlerts:
    @codyhillauthorAug 05.2019 — @Sempervivum#1607207 window.addEventListener('resize', e =&gt; {<br/>
    portfolioContent.forEach(container =&gt; container.classList.remove('containers-active'))<br/>
    });


    PS. This is the exact code I used
    Copy linkTweet thisAlerts:
    @codyhillauthorAug 05.2019 — @Sempervivum#1607207 I fixed it by making this constant global const portfolioContent = document.querySelectorAll('[data-portfolio-content]');.

    But now I have another issue when resizing the page. It happens only on the desktop version
    Copy linkTweet thisAlerts:
    @codyhillauthorAug 05.2019 — @RaulRogojan#1607225 I fixed it. This is how. Please tell me if it's ok or I just did it in a very poor and noobies way.

    HTML
    <i>
    </i>&lt;div class="portfolio-ul"&gt;
    &lt;ul&gt;
    &lt;li class="portfolio__button-active first-li first-button-active" data-content-target="#logosContainer"&gt;Logos&lt;/li&gt;
    &lt;li data-content-target="#business-cardsContainer"&gt;Business Cards&lt;/li&gt;
    &lt;li data-content-target="#illustrationContainer"&gt;Illustrations&lt;/li&gt;
    &lt;li data-content-target="#t-shirtsContainer"&gt;T-shirts&lt;/li&gt;
    &lt;li data-content-target="#web-sitesContainer"&gt;Web Sites&lt;/li&gt;
    &lt;li data-content-target="#studyCasesContainer"&gt;Study Cases&lt;/li&gt;
    &lt;/ul&gt;
    &lt;/div&gt;

    <i>
    </i>&lt;div class="elements__container display-first-container logos-container" id="logosContainer" data-portfolio-content&gt;
    ...
    &lt;/div&gt;


    <i>
    </i>const firstContainer = document.querySelector('.logos-container');
    const portfolioContent = document.querySelectorAll('[data-portfolio-content]');
    const firstListItem =document.querySelector('.first-li');

    window.addEventListener('resize', e =&gt; {
    portfolioContent.forEach(container =&gt; container.classList.remove('containers-active'))
    portfolioButtons.forEach(li =&gt; li.classList.remove('portfolio__button-active'));
    firstContainer.classList.add('display-first-container');
    firstListItem.classList.add('first-button-active');
    });

    <i>
    </i>if (query.matches) {
    const targetContent = document.querySelector(button.dataset.contentTarget);

    <i> </i> firstContainer.classList.remove('display-first-container');
    <i> </i> portfolioContent.forEach(container =&gt; container.classList.remove('containers-active'));
    <i> </i> targetContent.classList.add('containers-active');

    <i> </i> firstListItem.classList.remove('first-button-active');
    <i> </i> portfolioButtons.forEach(li =&gt; li.classList.remove('portfolio__button-active'));
    <i> </i> button.classList.add('portfolio__button-active');
    Copy linkTweet thisAlerts:
    @SempervivumAug 05.2019 — I didn't dive into the logic of your script. Only one remark: You are using the onresize event. I would prefer listening to the changes of of the media query list while these ones fire only when when the result, true or false, is changing while onresize fires very often.
    Copy linkTweet thisAlerts:
    @codyhillauthorAug 06.2019 — @Sempervivum#1607228 Much better, Thanks!

    The logic is: I added 2 more classes to the first li and container. One to select them in JS and one that is exactly the same as the other active classes. And on a click on any li, I remove both of them in the event listener for portfolioButtons. Those classes are added when you refresh and resize the page. The classes are on media query 800 and they are affecting only the desktop version.
    ×

    Success!

    Help @codyhill spread the word by sharing this article on Twitter...

    Tweet This
    Sign in
    Forgot password?
    Sign in with TwitchSign in with GithubCreate Account
    about: ({
    version: 0.1.9 BETA 5.13,
    whats_new: community page,
    up_next: more Davinci•003 tasks,
    coming_soon: events calendar,
    social: @webDeveloperHQ
    });

    legal: ({
    terms: of use,
    privacy: policy
    });
    changelog: (
    version: 0.1.9,
    notes: added community page

    version: 0.1.8,
    notes: added Davinci•003

    version: 0.1.7,
    notes: upvote answers to bounties

    version: 0.1.6,
    notes: article editor refresh
    )...
    recent_tips: (
    tipper: @AriseFacilitySolutions09,
    tipped: article
    amount: 1000 SATS,

    tipper: @Yussuf4331,
    tipped: article
    amount: 1000 SATS,

    tipper: @darkwebsites540,
    tipped: article
    amount: 10 SATS,
    )...