Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

PHP Build a Basic PHP Website (2018) Enhancing a Form Grouping Options for More Detail

Tyler Taylor
Tyler Taylor
17,939 Points

Using jquery to hide/show select values

I'm following the "Build a Basic PHP Website" course, this video specifically https://teamtreehouse.com/library/build-a-basic-php-website/enhancing-a-form/grouping-options-for-more-detail

She recommends using javascript to show/hide the drop down menu options as necessary. For example, if the category is "books" then the format drop down shouldn't show movie formats.

What I've done is create a conditional statement to check what the value of the category selector is.

I can get the formats to HIDE this way, but how do I make them show up when needed?

If category == books, I'd like the element with the id of "books" to be added to the element with the id of "format" so that it shows up.

I tried append and appendChild but I don't think I set it up right. Obviously very new to javascript/jquery.

$('#format').append('#books'); is what the line in question is currently set to, not working.

Any suggestions?

Tyler Taylor
Tyler Taylor
17,939 Points

Okay, I am able to hide the whole format drop down menu, but I only want to hide the child elements ("books", "movies", "music")

Modifying the js that was linked to in the first lesson of this section, the first section of my code looks like this ---

$(document).ready(function () {
  toggleFields(); // Call this first so we start out with the correct visibility depending on the selected form value

  $('#format').hide();
  // this will call our toggleFields function every time the selection value of our  field changes
  $("#category").change(function () {
    toggleFields();
  });
});

This successfully hides the entire format drop down, which isn't exactly what I want. I just want to hide the values in the menu until their category is selected.

With the code below I can remove the movies format options, but I can't figure out how to easily add them back, without creating the whole section in javascript, which I'd like to avoid.

function toggleFields() {
  if ($("#category").val() == "Books") {
    $('#format #movies').remove();
  }
}

Hi Tyler,

I didn't try to implement this myself when I did the course but I can try to help you get your solution working.

Have you kept the html the same as in the videos?

In other words, are you essentially trying to remove 2 of the optgroup's and show the correct one based on the category selected?

Is #movies an id that you assigned to the movies optgroup element?

Tyler Taylor
Tyler Taylor
17,939 Points

Oops, I guess I should have added my other comment as a comment instead of an answer.

5 Answers

What you're trying to do with removing the optgroups and saving them to a variable to append later should work out.

I created a codepen demo to illustrate the basic concept. I only did the format dropdown. https://codepen.io/anon/pen/XdmoRq?editors=1010

I think this is fairly close to how you're trying to do it. You'll have to add in a few more lines to take care of the genre dropdown as well.

The basic idea is to remove each of the optgroups when the page loads and save them in variables. Then when the category changes you remove whatever optgroup is currently there (if any) and you append the correct optgroup that matches the category selected.

You could probably store the optgroups in a javascript object and then be able to use loops to get rid of the repetition.

Let me know if you have any questions about it.

Tyler Taylor
Tyler Taylor
17,939 Points

Ahhhhh, it works great on codepen but not in my project :( My code matches yours exactly. Now I'm really confused! I was so close to figuring it out haha, I was setting my variables incorrectly before. But the fact that it's not working now is even more confusing.

Tyler Taylor
Tyler Taylor
17,939 Points

Ahhh, I had to put it inside the document ready function. Derp! Thanks a bunch Jason, now I can get back to the php course.

David Bath
David Bath
25,940 Points

Thanks for the ideas, Tyler and Devin! I didn't realize opt groups could be individually hidden, but it works well. First I gave all optgroups an attribute of "data-category" that matches the categories in the category dropdown.

<optgroup label="Books" data-category="Books">

Then the change event in the category dropdown fires this function:

function selectCategory(el) {
    // get the category
    var c = $(el).val();
    $('[data-category]').each(function() {
        var $this = $(this);
        // 'show' only optgroup categories that match
        $this[($this.attr('data-category') === c ? 'show' : 'hide')]();
    });
    // reset any previously-selected dropdowns
    $('#genre, #format').val('');
}

Kind of cryptic syntax for calling show/hide methods if you're not used to it, but I like the compressed format.

Tyler Taylor
Tyler Taylor
17,939 Points

Hey Jason,

Yes the html is the same, other than I have added id's to the optgroups.

And yes that's exactly what I'm trying to do.

I've learned that hide/show isn't the best option, but removing it is giving me headaches as well. I'd try setting up a variable, and assigning it the value of removing the ID. So, this works in removing it, but I can't seem to get it to append when I select the category. Same with detach() which is supposed to preserve the data.

Going a little crazy over this, because I know it's righttt at my fingertips haha

Devin Gray
Devin Gray
39,261 Points

Thank you for this post. It helped me find my own answer to this question, since the codepen posted here didn't work for my site. The main difference is I used show() and hide() instead of remove() and append(), and I used a switch statement instead of multiple if statements. Now it works for both the format and genre dropdowns. My results will probably be on my github soon.

Ilia Loginov
Ilia Loginov
13,015 Points

I've created a simple "ready to use" solution for "PHP people" who don't want to mess with JavaScript courses just yet but do want to change this form based on a selection.

Just follow the instructions:

  1. Create a folder named "js" in your project directory;
  2. Download jQuery https://code.jquery.com/jquery-3.2.1.min.js and put it in the "js" folder;
  3. In "js" folder create a new JavaScript file named "form.js";
  4. Remove all the options you created in this lesson from "format" and "genre" selectors in your "suggest.php" file;
  5. Add "disabled" property to "format" and "genre" selectors, they should look like this: <select id="format" name="format" disabled> <option value="">Select One</option> </select> <select name="genre" id="genre" disabled> <option value="">Select One</option> </select>
  6. Connect your js files to the "suggest.php" file: Just add these lines at the bottom of the page before the footer: <script src="js/jquery-3.2.1.min.js"></script> <script src="js/form.js"></script>
  7. Paste this code in your "form.js" file and don't forget to save it:

const format = { Books: [ 'Audio', 'Ebook', 'Hardback', 'Paperback', ], Movies: [ 'Blu-ray', 'DVD', 'Streaming', 'VHS', ], Music: [ 'Cassette', 'CD', 'MP3', 'Vinyl', ], };

const genre = { Books: [ 'Action', 'Adventure', 'Comedy', 'Fantasy', 'Historical', 'Historical Fiction', 'Horror', 'Magical Realism', 'Mystery', 'Paranoid', 'Philosophical', 'Political', 'Romance', 'Saga', 'Satire', 'Sci-Fi', 'Tech', 'Thriller', 'Urban', ], Movies: [ 'Action', 'Adventure', 'Animation', 'Biography', 'Comedy', 'Crime', 'Documentary', 'Drama', 'Family', 'Fantasy', 'Film-Noir', 'History', 'Horror', 'Musical', 'Mystery', 'Romance', 'Sci-Fi', 'Sport', 'Thriller', 'War', 'Western', ], Music: [ 'Alternative', 'Blues', 'Classical', 'Country', 'Dance', 'Easy Listening', 'Electronic', 'Folk', 'Hip Hop/Rap', 'Inspirational/Gospel', 'Jazz', 'Latin', 'New Age', 'Opera', 'Pop', 'R&B/Soul', 'Reggae', 'Rock', ], };

const categorySelector = $('#category');

function changeOptions(selector, category) { if (category) { if (selector.attr('disabled')) selector.removeAttr('disabled'); selector.html('<option value="">Select One</option>'); eval(selector.attr('name'))[category].forEach( value => selector.append(<option value="${value}">${value}</option>) ); } else { selector.html('<option value="">Select One</option>'); selector.attr('disabled', true); } }

categorySelector.change( (event) => { const category = $(event.target).val(); changeOptions($('#format'), category); changeOptions($('#genre'), category); });

That's it. ...should work!