.forEach validates each element but not the whole input? JS

I’m trying to validate a form input with multiple hashtags. I absolutely have to split the input and convert it to lowerCase. ex) #sun #sea #summer #salt #sand

When I’m typing a hashtag that fails the validation, bubble message pops up and tells me it’s wrong. But if I type the next hashtag correctly, previous bubble message clears and the whole validation fails (form can be sent).

I’m assuming it has something to do with .forEach – possibly there are better solutions I’m not yet aware of. I’m new to JS and would appreciate your answers very much.

// conditions for validation

const hashtagInput = document.querySelector('.text__hashtags');
const commentInput = document.querySelector('.text__description');

const testStartWith = (hashtag) => {
  if (!hashtag.startsWith('#')) {
    return 'hashtag should start with #';
  }
  return undefined;
};

const testShortValueLength = (hashtag) => {
  if (hashtag.length === 1) {
    return 'hashtag should have something after #';
  }
  return undefined;
};

const testValidity = (hashtag) => {
  const regex = /^[A-Za-z0-9]+$/;
  const isValid = regex.test(hashtag.split('#')[1]);
  if (!isValid) {
    return 'hashtag can't have spaces, symbols like #, @, $, etc, or punctuation marks';
  }
  return undefined;
};

const testLongValueLength = (hashtag) => {
  if (hashtag.length > 20) {
    return 'maximum hashtag length is 20 symbols';
  }
  return undefined;
};

const testUniqueName = (hashtagArray, index) => {
  if (hashtagArray[index - 1] === hashtagArray[index]) {
    return 'the same hashtag can't be used twice';
  }
  return undefined;
};

const testHashtagQuantity = (hashtagArray) => {
  if (hashtagArray.length > 5) {
    return 'only 5 hashtags for each photo';
  }
  return undefined;
};

const testCommentLength = (commentInput) => {
  if (commentInput.value.length >= 140) {
    return 'maximum comment length is 140 symbols';
  }
  return undefined;
};

const highlightErrorBackground = (element) => {
  element.style.backgroundColor = '#FFDBDB';
};

const whitenBackground = (element) => {
  element.style.backgroundColor = 'white';
};

Here is the validation at work

const testHashtagInput = () => {
  const hashtagArray = hashtagInput.value.toLowerCase().split(' ');

  hashtagArray.forEach((hashtag, index) => {
    let error = testStartWith(hashtag)
    || testShortValueLength(hashtag)
    || testValidity(hashtag)
    || testLongValueLength(hashtag)
    || testUniqueName(hashtagArray, index)
    || testHashtagQuantity(hashtagArray);

    if (error) {
      highlightErrorBackground(hashtagInput);
      hashtagInput.setCustomValidity(error);
    } else {
      whitenBackground(hashtagInput);
      hashtagInput.setCustomValidity('');
    }
    hashtagInput.reportValidity();
  });

  if (hashtagInput.value === '') {
    whitenBackground(hashtagInput);
    hashtagInput.setCustomValidity('');
  }
  hashtagInput.reportValidity();
};

const testCommentInput = () => {
  let error = testCommentLength(commentInput);
  if (error) {
    highlightErrorBackground(commentInput);
    commentInput.setCustomValidity(error);
  } else {
    whitenBackground(commentInput);
    commentInput.setCustomValidity('');
  }
  commentInput.reportValidity();
};

hashtagInput.addEventListener('input', testHashtagInput);

Answer

Yes your forEach reevaluates the entire validity of the input based on the individual items but only the last one actually remains in the end because it’s the last one being evaluated. You could change your evaluation to an array-reducer function; best fit for your intention is the reducer “some” (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some).

It iterates over the list of items and returns whether any one (or more) of the items fullfills the criterion formulated in your callback function.

I didn’t get to test it now, but I guess this should do it:

let error = hashtagArray.some((hashtag, index) => {
    return (testStartWith(hashtag)
            || testShortValueLength(hashtag)
            || testValidity(hashtag)
            || testLongValueLength(hashtag)
            || testUniqueName(hashtagArray, index)
            || testHashtagQuantity(hashtagArray));
});
if (error) {
  highlightErrorBackground(hashtagInput);
  hashtagInput.setCustomValidity(error);
} else {
  whitenBackground(hashtagInput);
  hashtagInput.setCustomValidity('');
}
hashtagInput.reportValidity();

HTH, cheers

Leave a Reply

Your email address will not be published. Required fields are marked *