Changing value inside text field based on body class>?

Hi there,

I have some pages that have body classes such as:

  • term-art-craft-competitions
  • term-music-competitions
    and
  • term-art-craft-freebies
  • term-music-freebies

I have a search field (just a text input) with some default placeholder text “Search Job, keywords…”

What I would like to do is replace this text and have this text field display something like “Search competitions” or “Search freebies” based on the body class. So I’m thinking of trying something like checking if the body has a class with the word “competitions” or “freebies”.

This is the code I have, but it’s not doing what I’d like.

Can anyone see what I have wrong?

document.addEventListener('DOMContentLoaded', function() {
    const bodyClass = document.body.className;
    const searchInput = document.getElementById('PqmIc_title');

    if (bodyClass.includes('competitions')) {
      searchInput.placeholder = 'Search competitions by title, keywords...';
    } else if (bodyClass.includes('freebies')) {
      searchInput.placeholder = 'Search freebies by title, keywords...';
    }
  });

Thanks!

As long as you’re not going to ever have the same word be used twice - like “competitions-free” and “competitions-paid” (which would both match the includes("competitions") statement), the code looks correct…

When in doubt, throw console.log("Debug: Step X") in all over the place and see what, if anything, it’s doing? (At the very least, it’ll give us more information - where the script stopped, if its running at all, etc.)

2 Likes

FWIW, this looks suspiciously like a generated ID that might change with each build…

2 Likes

Hi for this problem the most modern solution is using declarative programming and I always use juris.js. for this. For your case, you can just create an instance of Juris and use the enhance() API.

you can read more about the enhance() API in here

const juris = new Juris();

juris.enhance('#PqmIc_title', {
    placeholder: () => {
        const bodyClasses = document.body.classList;
        
        // More precise detection using classList
        const hasCompetitions = Array.from(bodyClasses).some(cls => 
            cls.includes('competitions')
        );
        
        const hasFreebies = Array.from(bodyClasses).some(cls => 
            cls.includes('freebies')
        );
        
        if (hasCompetitions) {
            return 'Search competitions by title, keywords...';
        } else if (hasFreebies) {
            return 'Search freebies by title, keywords...';
        }
        
        return 'Search Job, keywords…';
    }
}, {
    // Retry if element doesn't exist yet
    debounceMs: 100,
    observeNewElements: true
});
</script>

@restiguay Awesome, many thanks, that worked! Never heard of Juris, so thanks :slight_smile:

Seems you have found one to go with, but here is my attempt

const searchTerms = ['competitions', 'freebies']

function getPlaceHolder(className, terms = searchTerms) {
    // In this example will create the regex /competitions|freebies/
    const terms_Rx = new RegExp(terms.join('|'));
    const match = className.match(terms_Rx);

    if (match !== null)
        // A successfull match returns an array e.g.
        // ['competitions', index: 15, input: 'term-art-craft-competitions']
        return `Search ${match[0]} by title, keywords...`

    // or return some default placeholder
    return `Search by title, keywords...`
}

Tests

console.log(getPlaceHolder('term-art-craft-competitions'))
// Search competitions by title, keywords...

console.log(getPlaceHolder('term-art-craft-freebies'))
// Search freebies by title, keywords...

console.log(getPlaceHolder('term-art-craft-fair'))
// Search by title, keywords...
1 Like

Your approach looks mostly fine, but sometimes document.body.className returns a string with all classes separated by spaces, so using includes() should work.

Can you elaborate on that?

using className in the context of a multijoined pattern RegEx works. I dont see a weakness in your approach, you solve the problem without needing to bloat your code with an unneeded library.

2 Likes

The constructor for searchTerms should take care of that (or for that matter, the binder)

Something else that the constructor would have to account for is sloppy entries (double spaces, trimming the string, etc.)