0

I am trying to populate a dropdown with JSON. It works in every other browser except IE. If I add

alert(response.html);

after the success response, it shows the data correctly. But IE won't populate the dropdown with that data. Any help will REALLY be appreciated!!!

<script type="text/javascript">
jQuery(document).ready(function() {
(function($) {
    $('select[name="post_type"]').change(function(event) {
        $.post( <? php echo json_encode(admin_url('admin-ajax.php')); ?> , {
            action: 'wpse158929_get_terms_for_cpt',
            post_type: $(this).val(),
            taxonomy: <? php echo json_encode($taxonomy); ?> ,
            current_selected: $('select[name="location"]').val(),
                nonce: <? php echo json_encode(wp_create_nonce('wpse158929_get_terms_for_cpt_submit_')); ?>
        }, function(response) {
            if (response && !response.error) {
                $('select[name="location"]').html(response.html);
            }
        }, 'json');
    });
    // Remove if you don't want to call change immediately.
    $('select[name="post_type"]').change();
})(jQuery);
});
</script>

This is the function for the 2 dropdowns:

function my_dropdown_categories( $taxonomy, $current_selected = '', $include = null ) {
// Get all terms of the chosen taxonomy
$terms = get_terms($taxonomy, array('orderby' => 'name'));

// our content variable
$list_of_terms = '<select  id="location-dropdown" class="fade-in five selectboxSingle" name="location">';

            // the current selected taxonomy slug ( would come from a QUERY VAR)
            //$current_selected = "asfasdf";

if ( ! is_wp_error( $terms ) ) foreach($terms as $term){

    // If include array set, exclude unless in array.
    if ( is_array( $include ) && ! in_array( $term->slug, $include ) ) continue;

    $select = ($current_selected == $term->slug) ? "selected" : ""; // Note: ==

    if ($term->parent == 0 ) {

        // get children of current parent.
        $tchildren = get_term_children($term->term_id, $taxonomy);

        $children = array();
        foreach ($tchildren as $child) {
            $cterm = get_term_by( 'id', $child, $taxonomy );
            // If include array set, exclude unless in array.
            if ( is_array( $include ) && ! in_array( $cterm->slug, $include ) ) continue;
            $children[$cterm->name] = $cterm;
        }
        ksort($children);

        // OPTGROUP FOR PARENTS
        if (count($children) > 0 ) {
           //  $list_of_terms .= '<optgroup label="'. $term->name .'">';
             if ($term->count > 0)
                 $list_of_terms .= '<option class="option-parent" value="'.$term->slug.'" '.$select.'>'. $term->name .'</option>';
        } else
            $list_of_terms .= '<option value="'.$term->slug.'" '.$select.'>'. $term->name .' </option>';
        //$i++;

        // now the CHILDREN.
        foreach($children as $child) {

             //$select = ($current_selected) ? "selected" : ""; // Note: child, not cterm
             $list_of_terms .= '<option class="option-child" value="'.$child->slug.'" '.$select.'>'. "&nbsp;&nbsp;" . $child->name.' </option>';

        } //end foreach

        if (count($children) > 0 ) {
            $list_of_terms .= "</optgroup>";
        }
    }
}

$list_of_terms .= '</select>';

return $list_of_terms;
}

add_action( 'wp_ajax_wpse158929_get_terms_for_cpt', 'wpse158929_get_terms_for_cpt' );
add_action( 'wp_ajax_nopriv_wpse158929_get_terms_for_cpt',     'wpse158929_get_terms_for_cpt' );

function wpse158929_get_terms_for_cpt() {
$ret = array( 'html' => '', 'error' => false );

if ( ! check_ajax_referer( 'wpse158929_get_terms_for_cpt_submit_', 'nonce', false /*die*/ ) ) {
    $ret['error'] = __( 'Permission error', 'wpfm' );
} else {
    $post_type = isset( $_REQUEST['post_type'] ) ? $_REQUEST['post_type'] : '';
    $taxonomy = isset( $_REQUEST['taxonomy'] ) ? $_REQUEST['taxonomy'] : '';
    $current_selected = isset( $_REQUEST['current_selected'] ) ? $_REQUEST['current_selected'] : '';

    if ( ! $post_type || ! $taxonomy ) {
        $ret['error'] = __( 'Params error', 'wpfm' );
    } else {
        global $wpdb;
        $sql = $wpdb->prepare( 'SELECT t.slug FROM ' . $wpdb->terms . ' t'
            . ' JOIN ' . $wpdb->term_taxonomy . ' AS tt ON tt.term_id = t.term_id'
            . ' JOIN ' . $wpdb->term_relationships . ' AS tr ON tr.term_taxonomy_id = tt.term_taxonomy_id'
            . ' JOIN ' . $wpdb->posts . ' AS p ON p.ID = tr.object_id'
            . ' WHERE tt.taxonomy = %s AND p.post_type = %s AND p.post_status = %s'
            . ' GROUP BY t.slug'
            , $taxonomy, $post_type, 'publish' );
        $include = $wpdb->get_col($sql);
        $ret['html'] = my_dropdown_categories( $taxonomy, $current_selected, $include );
    }
}

wp_send_json( $ret );
}
Guit4eva
  • 151
  • 1
  • 9
  • have you seen http://stackoverflow.com/questions/412734/jquery-html-attribute-not-working-in-ie? It has quite some possible solutions... – Reinder Wit Aug 28 '14 at 11:39
  • Which version of jQuery are you using? 1.x versions will support IE8, but 2.x versions only support IE9 and higher. See here for details: http://jquery.com/browser-support/ – jme11 Aug 28 '14 at 11:45
  • I'm using version 1.7.1 – Guit4eva Aug 28 '14 at 12:40

1 Answers1

0

Internet Explorer had always problems with dynamic HTML and dropdowns, mostly with .html() . You should create the dropdown with a more compatible way:

var json = [{value:"foo",text:"text 1"},{value:"bar",text:"text 2"}];
$("#myid option").remove();
$.each(json,function(k,v) {
   $("#myid").append($("<option></option>",{value:v["value"],text:v["text"]}));
});

The above works for IE11. You can also try this vanilla way for even more compatibility:

var json = [{value:"foo",text:"text 1"},{value:"bar",text:"text 2"}];
var d = document.getElementById("myid");
for(var x in json) {
   d.options[x] = new Option(json[x]["text"],json[x]["value"]);
}

UPDATE 2

Something like this:

PHP

echo json_encode("html_options"=>array(
   array("text"=>"text 1","value"=>"foo"),
   array("text"=>"text 2","value"=>"bar"),
));

JS

$("select[name="location"] option").remove();
$.each(response.html_options,function(k,v) {
   $("select[name="location"]").append($("<option></option>",{value:v["value"],text:v["text"],selected:v["selected"],class:v["class"]}));
});

or

var d = document.getElementById("myid");     <--- you need a select id here
for(var x in response.html_options) {
   d.options[x] = new Option(response.html_options[x]["text"],response.html_options[x]["value"]);
   d.options[x].className = response.html_options[x]["class"];
   if (response.html_options[x]["selected"]) {
      d.selectedIndex = x;
   }
}

this is the modified my_dropdown_categories that returns the options in array (not the HTML).

function my_dropdown_categories( $taxonomy, $current_selected = '', $include = null ) {
   $options = array();
   // Get all terms of the chosen taxonomy
   $terms = get_terms($taxonomy, array('orderby' => 'name'));
   if ( ! is_wp_error( $terms ) ) foreach($terms as $term) {
      // If include array set, exclude unless in array.
      if ( is_array( $include ) && ! in_array( $term->slug, $include ) ) continue;
      $select = ($current_selected == $term->slug); // Note: ==
      if ($term->parent == 0 ) {
         // get children of current parent.
         $tchildren = get_term_children($term->term_id, $taxonomy);
         $children = array();
         foreach ($tchildren as $child) {
            $cterm = get_term_by( 'id', $child, $taxonomy );
            // If include array set, exclude unless in array.
            if ( is_array( $include ) && ! in_array( $cterm->slug, $include ) )     
               continue;
            $children[$cterm->name] = $cterm;
         }
         ksort($children);

         // OPTGROUP FOR PARENTS
         if (count($children) > 0 ) {
            if ($term->count > 0) {
               $options[] = array("value"=>$term->slug,"text"=>$term->name,"class"=>"option-parent","selected"=>FALSE);
            }
         } else {
            $options[] = array("value"=>$term->slug,"text"=>$term->name,"class"=>"option-parent","selected"=>$select);
         }
         // now the CHILDREN.
         foreach($children as $child) {
            $options[] = array("value"=>$child->slug,"text"=>$child->name,"class"=>"option-child","selected"=>$select);
         } // end foreach
      }
   }
   return $options;
}

Then you call your func to populate the 'html_options' (instead the 'html') and return the $ret.

$ret['html_options'] = my_dropdown_categories( $taxonomy, $current_selected, $include);
  • Would this work in IE8 and below? How would I implement that? – Guit4eva Aug 28 '14 at 12:41
  • You need to return _values and text_ for the options rather than complete html etc. `` from the AJAX for full compatibility with IE. The vanilla way will surely work since it does not use jquery, though you have to test the first method but both ways are more compatible than a `.html` call. –  Aug 28 '14 at 12:55
  • I'm really battling to implement that. I've posted my function for the two dropdowns in my original post, will your answer still be suited for that? – Guit4eva Aug 28 '14 at 13:26
  • Yes, my **UPDATE** code is suited for your dropdown with _name = location_ (since this is the one you're changing) but you need to also modify your own code so you dont have to return just the html from your `my_dropdown_categories`. You _have_ to extract the **value** and **text** for your options from your PHP somehow and pass them to `wp_send_json` as my example in PHP. As a side note i just tested my 2 approaches (jquery and vanilla), they both worked down to **IE6**. –  Aug 28 '14 at 13:35
  • Just took a peek into your function `my_dropdown_categories`. What you need to extract really are the `$term->slug` (the value) and `$term->name` (the text). AH i see you're adding some $childs also... makes that more complex... Allow me to modify your function somehow –  Aug 28 '14 at 13:38
  • Something weird. In javascript you try to replace `$('select[name="location"]')` with the `html` that is coming from server. But i just saw that this html already holds another ` –  Aug 28 '14 at 13:46
  • Oh drats...so what does that ultimately mean? (awesome news though that it can potentially work in IE6!!!) – Guit4eva Aug 28 '14 at 13:59
  • I just **UPDATE** d my answer with more code (JS and PHP) with some big changes. I hope u understand there's really no other workaround than returning the options in array rather HTML for full compatibility.. –  Aug 28 '14 at 14:04
  • I'm getting `Notice: Array to string conversion` in this line: `echo my_dropdown_categories( $taxonomy );` which calls the second drop down in my front page – Guit4eva Aug 28 '14 at 14:49
  • The function doesn't return HTML anymore, it returns array of options. You cant echo it anymore because you'll be getting compatibility errors in IE8. –  Aug 28 '14 at 15:00
  • Oh:) SO how would I then display the dropdown? – Guit4eva Aug 28 '14 at 15:03
  • I know, but please remember that it probably looks easy to you since you're so familiar with it, whereas I'm still new to this stuff, so it's very difficult to understand and implement. Would I make a normal empty – Guit4eva Aug 28 '14 at 15:11
  • That's the idea, yes. Making empty containers in HTML, populating with JS. (for dropdowns at least) –  Aug 28 '14 at 15:13
  • I've added this to my frontpage: `` and getting an undefined variable on this line: `taxonomy: ` – Guit4eva Aug 28 '14 at 15:31
  • Well, thats weird since $taxonomy has nothing to do completely with what i've changed. As i saw $taxonomy is being initialized by some $_REQUEST. –  Aug 28 '14 at 15:38
  • I went back to the start and carefully replaced my code with yours, still brings up the undefined variable error. Drats...seemed like it was so close to working :/ – Guit4eva Aug 28 '14 at 15:52
  • :) don't panic, your code is just a bit complex. Replace the code back to working state, keeping mine commented for later use, then try to fix the error by using your previous approach. –  Aug 28 '14 at 16:03
  • I can't believe something so simple in theory can be so hard in practice ha ha:) Sigh..... Is there not maybe another, better way to do it? Or is JSON the only way? Thanks for all your help though, I really do appreciate it! – Guit4eva Aug 28 '14 at 17:14
  • No problem :) i doubt there's other way for that, you just have to break it down and JSON is really an awesome way to do that. You just have to forget about returning full HTML when you have to do with damn IE :) Its simple both in theory and practice. When you return something from server, make it a habit to be a JSON, not HTML. This way you can always return an hypothetical HTML along with other information as well, the reverse cant happen. –  Aug 28 '14 at 17:18