3

I'm trying to change the Text inside a table based on the widthof the screen.

This works fine, when i reach the breakpoint. The Problem is, that the text does not change back to the original when i resize to the bigger width.

Here is the code:

function updateText() {
  const elements = document.querySelectorAll('.responsive-text');
  const originaltext = document.querySelectorAll('.responsive-text').innerText;
  elements.forEach(element => {
    if (window.matchMedia('(min-width: 400px) and (max-width: 600px)').matches) {
      element.textContent = element.getAttribute('data-alt-text');
    } else {
      element.textContent = originaltext;
    }

  });
}

window.addEventListener('resize', updateText);
window.addEventListener('load', updateText);
<div class="schedule-container">
  <div class="header responsive-text" data-alt-text="1. HJ">1. Halbjahr</div>
  <div class="header responsive-text" data-alt-text="MO">Montag</div>
  <div class="header responsive-text" data-alt-text="DI">Dienstag</div>
  <div class="header responsive-text" data-alt-text="MI">Mittwoch</div>
  <div class="header responsive-text" data-alt-text="DO">Donnerstag</div>
  <div class="header responsive-text" data-alt-text="FR">Freitag</div>
</div>

Thanks for your help!

1
  • I think the solution you are looking for is in CSS. Two spans and then add the responsive classes there. If you use tailwind or any framework, you should have utility classes for it already, but if not, it's a few lines. It's gonna be considerably more efficient than JS code, especially since your one is not debounced. I keep as a rule of thumb if it includes matchMedia in js, i am doing something wrong, although there are exceptions to it. Commented Feb 28 at 12:21

3 Answers 3

3

You are replacing the original text with the alternate, and when you go back, the original text doesn't exist anymore.

You can use CSS to hide the original text by setting it's font-size to 0, and showing a pseudo-element (::after) with the alternate text:

@media (min-width: 400px) and (max-width: 600px) {
  .responsive-text {
    font-size: 0;
    
    &::after {
      font-size: 1rem;
      content: attr(data-alt-text);
    }
  }
}
<div class="schedule-container">
  <div class="header responsive-text" data-alt-text="1. HJ">1. Halbjahr</div>
  <div class="header responsive-text" data-alt-text="MO">Montag</div>
  <div class="header responsive-text" data-alt-text="DI">Dienstag</div>
  <div class="header responsive-text" data-alt-text="MI">Mittwoch</div>
  <div class="header responsive-text" data-alt-text="DO">Donnerstag</div>
  <div class="header responsive-text" data-alt-text="FR">Freitag</div>
</div>

Another option is to use 2 data attributes, and replace the pseudo-elements content:

.responsive-text::after {
  content: attr(data-text);
}

@media (min-width: 400px) and (max-width: 600px) {
  .responsive-text::after {
    content: attr(data-alt-text);
  }
}
<div class="schedule-container">
  <div class="header responsive-text" data-alt-text="1. HJ" data-text="1. Halbjahr"></div>
  <div class="header responsive-text" data-alt-text="MO" data-text="Montag"></div>
  <div class="header responsive-text" data-alt-text="DI" data-text="Dienstag"></div>
  <div class="header responsive-text" data-alt-text="MI" data-text="Mittwoch"></div>
  <div class="header responsive-text" data-alt-text="DO" data-text="Donnerstag"></div>
  <div class="header responsive-text" data-alt-text="FR" data-text="Freitag"></div>
</div>

Using JS, you can create a MediaQueryList using window.matchMedia(), and switch the textContent and the data attribute values whenever it changes:

const mql = window.matchMedia('(width >= 400px) and (width <= 600px)');

function updateText() {  
  const elements = document.querySelectorAll('.responsive-text');

  elements.forEach(element => {
    const textContent = element.textContent;
    const altText = element.getAttribute('data-alt-text');
    
    element.textContent = altText;
    element.setAttribute('data-alt-text', textContent);
  });
}

if(mql.matches) updateText();

mql.addEventListener('change', updateText);
<div class="schedule-container">
  <div class="header responsive-text" data-alt-text="1. HJ">1. Halbjahr</div>
  <div class="header responsive-text" data-alt-text="MO">Montag</div>
  <div class="header responsive-text" data-alt-text="DI">Dienstag</div>
  <div class="header responsive-text" data-alt-text="MI">Mittwoch</div>
  <div class="header responsive-text" data-alt-text="DO">Donnerstag</div>
  <div class="header responsive-text" data-alt-text="FR">Freitag</div>
</div>

1
  • 2
    Nice answer. PS: I would use the more human reasonable const mql = window.matchMedia("(width >= 400px) and (width <= 600px)"); Commented Feb 28 at 15:18
2

Every time you run updateText you overwrite the originalText variable. So it doesn't stay as the original text - next the function triggers, it becomes whatever is the text in that element at the time. So if you have replaced the original text with the alt text, next time you try to reset it, originalText will be populated with the alt text, because that's what in the innerText of the elements at that time.

One solution is to keep all the sets of text as data attributes, so you can recall them as needed.

function updateText() 
{
  const elements = document.querySelectorAll('.responsive-text');

  elements.forEach(element => 
  {
    if (window.matchMedia('(min-width: 400px) and (max-width: 600px)').matches) 
    {
      element.textContent = element.dataset.alttext;
    }
    else 
    {
      element.textContent = element.dataset.defaulttext;
    }
  });
}

window.addEventListener('resize', updateText);
window.addEventListener('load', updateText);
<div class="schedule-container">
  <div
    class="header responsive-text"
    data-defaulttext="Halbjahr"
    data-alttext="1. HJ"
  >
    1. Halbjahr
  </div>
  <div
    class="header responsive-text"
    data-defaulttext="Montag"
    data-alttext="MO"
  >
    Montag
  </div>
  <div
    class="header responsive-text"
    data-defaulttext="Dienstag"
    data-alttext="DI"
  >
    Dienstag
  </div>
  <div
    class="header responsive-text"
    data-defaulttext="Mittwoch"
    data-alttext="MI"
  >
    Mittwoch
  </div>
  <div
    class="header responsive-text"
    data-defaulttext="Donnerstag"
    data-alttext="DO"
  >
    Donnerstag
  </div>
  <div
    class="header responsive-text"
    data-defaulttext="Freitag"
    data-alttext="FR"
  >
    Freitag
  </div>
</div>

0
2

First of all, originaltext in your code will be undefined, because querySelectorAll returns a list of elements, not a single element [MDN].

The main problem is that you would like to restore textContent to the original text, but you have lost it, having overwritten it with abbreviations. You could then save both variants in data attributes, and set the correct one based on your condition.

function updateText() {
  const elements = document.querySelectorAll('.responsive-text');
  elements.forEach(element => {
    if (window.matchMedia('(min-width: 400px) and (max-width: 600px)').matches) {
      element.textContent = element.getAttribute('data-alt-text');
    } else {
      element.textContent = element.getAttribute('data-text');
    }
  });
}

window.addEventListener('resize', updateText);
window.addEventListener('load', updateText);
<div class="schedule-container">
  <div class="header responsive-text" data-alt-text="1. HJ" data-text="1. Halbjahr"></div>
  <div class="header responsive-text" data-alt-text="MO" data-text="Montag"></div>
  <div class="header responsive-text" data-alt-text="DI" data-text="Dienstag"></div>
  <div class="header responsive-text" data-alt-text="MI" data-text="Mittwoch"></div>
  <div class="header responsive-text" data-alt-text="DO" data-text="Donnerstag"></div>
  <div class="header responsive-text" data-alt-text="FR" data-text="Freitag"></div>
</div>

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.