Removing an element on resize doesn't work (but adding does)

If taking my original approach, I have found this code to work when testing in Google Chrome and in Microsoft Edge:

function addPhoneNumberBox() {
    document.querySelector(".header-module--logo--B7flj").insertAdjacentHTML('afterend', `
        <div class="phoneNumberBox" dir="ltr" style="text-align: center; background: red;">
            <h2>Call me:</h2>
            <a tel:X>+1 012-3456780</a>
        </div>
    `);
};

if (window.innerWidth >= 850) {
    addPhoneNumberBox();
}

window.addEventListener("resize", function() {
    if (window.innerWidth < 850) {
        document.querySelector(".phoneNumberBox").remove();
    }
});

window.addEventListener("resize", function() {
    if (window.innerWidth >= 850) {
        const [...PhoneNumberBox] = document.querySelectorAll(".phoneNumberBox");
        PhoneNumberBox.forEach( (element)=>{
            element.remove();
        });
        addPhoneNumberBox();
    };
});

Main differences from the original code:

  • I directly select and remove the phone number box after calling the function which creates it — by respective-smallscale-resizing handler
  • I have added a “cleaner” component which removes any phone number box (of that kind) which might have stayed existing — by respective-largescale-resizing handler

Looked at your codepen, that’s really good, and the event only fires on the breakpoint, so no debounce necessary.

One thing that did come up though is addListener, apparently it is now depreciated.

I believe you should use this instead

mqls.addEventListener('change', mediaqueryresponse);

Great stuff :+1:

1 Like

Bearing in my new my JS is very basic that looks about the worst way you could do this. I imagine that your page would be greatly impacted by the multiple resize calls.

MatchMedia is more efficient and only gets triggered once and not thousands of times.

@rpg_digital could confirm but I suspect that at the very least you would need to debounce the resize event to avoid any lag on the page

1 Like

Thanks. I copied the code from an old demo of mine so was unaware of the change :blush:

1 Like

I did make this codepen

@bendqh1 you will need to open the console at the bottom. Note how many times the resize event fires compared to matchmedia. matchmedia is more efficient and frees up the event loop to handle other things.

@PaulOB, @rpg_digital I try to follow the approach you share here but I come across a problem.

I tried the following code on sitepoint.com which fails, the contact box isn’t added:

const mqls = window.matchMedia("(max-width: 850px)");
const hostElement = document.querySelector(".header-module--logo--B7flj");
const parasiteElement = `
    <div class="phoneNumberBox" dir="ltr" style="text-align: center; background: red;">
        <h2>Call me:</h2>
        <a tel:X>+1 012-3456780</a>
    </div>
`

function mediaqueryresponse(mql) {
    if (mqls.matches) {
        hostElement.insertAdjacentHTML("afterend", parasiteElement);
    };
};

mediaqueryresponse(mqls);

You missed out the important bit which was the event listener that listens for the media query breakpoint and you seem to be trying to insert the element into an svg instead of the header.

const mqls = window.matchMedia("(max-width: 850px)");
const hostElement = document.querySelector(".header-module--nav--7IzCJ");
const parasiteElement = `
    <div class="phoneNumberBox" dir="ltr" style="text-align: center; background: red;">
        <h2>Call me:</h2>
        <a tel:X>+1 012-3456780</a>
    </div>
`;

function mediaqueryresponse(mql) {
  if (mqls.matches) {
    hostElement.insertAdjacentHTML("afterend", parasiteElement);
  }
}

mediaqueryresponse(mqls);

// attach listener function to listen in on state changes
mqls.addEventListener("change", mediaqueryresponse);

Thanks, PaulOB.

Something interesting happens, the code worked for me without problem when I started from mobile display,
But when I changed max-width to min-width (which is what I personally need), than the code worked only partially — the contact box appeared both in mobile and desktop displays.

(tested on sitepoint.com from Google Chrome on Windows 10 from my laptop).

Which code are you referring to?

The first code you added is just a once only code because you missed out the event listener. It would only add the new element if you were already at the smaller width and only on load.

The adjusted snippet I gave you above added the event listener so the element is added when the media query breakpoint is activated.

However you have not yet added the code to remove the element so all you get is an element added each time you return to the smaller screen

I gave you a working demo in the codepen showing the how to add and also remove the element. I assumed you had left it out on purpose just for testing :slight_smile:

If you want the new box only on the large screen then just reverse the if/else code. I’ve adjusted the codepen to show this:

1 Like

If you are adding to the Sitepoint page then I guess you need it like thi:

const mqls = window.matchMedia("(max-width: 850px)");
const hostElement = document.querySelector(".header-module--nav--7IzCJ");
const parasiteElement = `
    <div class="phoneNumberBox" dir="ltr" style="text-align: center; background: red;">
        <h2>Call me:</h2>
        <a tel:X>+1 012-3456780</a>
    </div>
`;

function mediaqueryresponse(mql) {
  if (mqls.matches) {
    // {max-width: 850px} query matched
        var contactInfo = document.querySelector('.phoneNumberBox');
     if (contactInfo !== null) contactInfo.remove()
  } else {
     hostElement.insertAdjacentHTML("beforeend", parasiteElement);
  }
}
mediaqueryresponse(mqls);
// attach listener function to listen in on state changes
mqls.addEventListener("change", mediaqueryresponse);

Small Screen:
Screen Shot 2022-02-07 at 20.41.49

Large Screen:

1 Like

@PaulOB

I meant to to the code in post #21 (with changing max-width to min-width).

There is one flaw here. You pass in mqls to mediaqueryresponse on the initial call which is good.

mediaqueryresponse(mqls);

However you then don’t use it (Note mql and mqls)

function mediaqueryresponse(mql) {
  if (mqls.matches) {

Instead referring to the mqls outside of the function. Changing your function parameter from mql to mqls should fix that. It then keeps matches nicely contained inside of the function,

You could (if you like) also make use of an early return to get rid of the need for that else statement. Note I have gone for an easier to read and remember ‘mediaQueryList’ parameter here

function mediaqueryresponse(mediaQueryList) {
    if (mediaQueryList.matches) {
        const contactInfo = document.querySelector('.phoneNumberBox')

        if (contactInfo !== null) contactInfo.remove()
        return // exit here
    }
    // we didn't exit? Not a match then!
    hostElement.insertAdjacentHTML("afterend", parasiteElement)
}

Note: I haven’t tested this. Just a look at your code.

1 Like

@bendqh1 you will need to open the console at the bottom. Note how many times the resize event fires compared to matchmedia. matchmedia is more efficient and frees up the event loop to handle other things.

I checked for such event notifications on both Google Chrome console and Microsoft Edge console (in the end) but didn’t find any; I only find warnings and/or errors there.

Anyway, I understand that idea about software performance.
But isn’t something like mqls.addEventListener("change", mediaqueryresponse); on each webpage in a large website also a problem?

It’s a good question, I don’t know is the answer.

I prefer the mediaQueryList, but you can alleviate the issue with the resize eventListener by using debounce.

You can see the same codepen I did, but this time with debounce. For convenience I have used lodash.

window.addEventListener('resize', _.debounce(resizeHandler, 300))

codepen here

1 Like

The problem I see (with my limited js knowledge) is that you don’t get the change at exactly the right point and it makes it feel laggy compared to the matchMedia version.

e.g.

You can see the red appears exactly when it should with the matchMedia routine but the debounced resize (blue background) you have to wait until the debounce has finished. It makes it look laggy just for a color change but imagine if this was a layout change and then the layout could possibly be broken until the debounce has finished because the screen may have been resized quite a bit smaller during that time.

I doubt there is any noticeable impact compared to using the resize event which is known resource hog.

@PaulOB

I would go with matchMedia, hands down. In fact I will be amending a responsive menu I wrote previously with matchMedia.

I was just giving an example. A better use for debounce would be say for instance a search box, where you don’t want the database being thrashed on every key press, but rather on the completion of typing a word.

I concurr :slight_smile:

1 Like

Yes, sorry I didn’t mean to infer that you meant it as a better alternative :slight_smile:

Yes that makes sense :slight_smile:

1 Like

For possible future readers, this thread somewhat continued here and here:

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.