Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use Ajax and JSON for making dropdown menu?

Tags:

Here is the code I used to show a category menu in OpenCart with different levels. It works, but after each click it produces more and more XHR finished loading: POST and XHR finished loading: GETs which stops the page by clicking sometimes:

<script type="text/javascript">  _url = '';   $(document).ready(function(){                     $('#mnav a').on('click', function() {         var cat = $(this).attr('id');         _url = '&category_id=' + cat;          $.post('index.php?route=test/category/child' + _url,             function(data) {                if(data.length>10){                     $('#mnav #sub').remove();                     $(data).insertAfter($('#mnav #' + cat));                }             });     });  });  $.ajaxPrefilter(function( options, original_Options, jqXHR ) {     options.async = true; }); </script> 

HTML Codes:

<div id="mnav" class="list-group">   <?php foreach ($categories as $category) { ?>   <a id="<?php echo $category['category_id']; ?>" class="list-group-item active"><?php echo $category['name']; ?></a>   <?php } ?> </div> 

Controller codes:

<?php class ControllerTestCategory extends Controller {     public function index() {         if (isset($this->request->get['path'])) {             $parts = explode('_', (string)$this->request->get['path']);         } else {             $parts = array();         }          $data['category_id'] = 0;         if (isset($parts[0])) {             $data['category_id'] = $parts[0];         } else {             $data['category_id'] = 0;         }          if (isset($parts[1])) {             $data['child_id'] = $parts[1];         } else {             $data['child_id'] = 0;         }          $this->load->model('catalog/cat');          $data['categories'] = array();          $categories = $this->model_catalog_cat->getCategories(0);          foreach ($categories as $category) {             $children_data = array();              $filter_data = array(                 'filter_category_id'  => $category['category_id'],                 'filter_sub_category' => true             );              $data['categories'][] = array(                 'category_id' => $category['category_id'],                 'name'        => $category['name'],                 'children'    => $category['children'],                 'products'    => $category['products'],                 'href'        => $this->url->link('product/category', 'path=' . $category['category_id'])             );         }          $this->response->setOutput($this->load->view('test/category', $data));     }     public function child() {         if (isset($this->request->get['category_id'])) {             $this->load->model('catalog/cat');              $data['categories'] = array();              $categories = $this->model_catalog_cat->getCategories($this->request->get['category_id']);              $data['x'] = '<div id="sub">';              foreach ($categories as $category) {                 $data['x'] .= '<li>' . $category['name'] . '</li>';             }             $data['x'] .= '</div>';         } else {             $data['x'] = 'NA';         }         $this->response->setOutput($this->load->view('test/category', $data));     } } 

SQL codes:

public function getCategories($parent_id = 0) {     $sql = "SELECT c.category_id, c.parent_id, cd.name,         (SELECT COUNT(DISTINCT ch.category_id) from category ch where ch.parent_id = c.category_id and cd.language_id = '" . (int)$this->config->get('config_language_id') . "') as children";      $sql .= " , (SELECT COUNT(DISTINCT p.product_id)  FROM product p       LEFT JOIN product_description pd ON (p.product_id = pd.product_id)      LEFT JOIN product_to_category p2c ON (p2c.product_id = p.product_id)      LEFT JOIN category_path cp ON (cp.category_id = p2c.category_id)  WHERE      pd.language_id = '" . (int)$this->config->get('config_language_id') . "' AND      p.status = '1' AND      p.date_available <= NOW()) AS items";      $sql .= " FROM category c LEFT JOIN category_description cd ON (c.category_id = cd.category_id) WHERE c.parent_id = '" . (int)$parent_id . "' AND cd.language_id = '" . (int)$this->config->get('config_language_id') . "' AND c.status = '1' ORDER BY c.sort_order, LCASE(cd.name)";      $query = $this->db->query($sql);     return $query->rows; } 

I'd highly appreciate if you kindly help me by providing all necessary JavaScript, jQuery and JSON codes because I know these subjects with little :-(

like image 205
Kardo Avatar asked May 07 '17 03:05

Kardo


People also ask

Can we use AJAX with JSON?

According to the AJAX model, web applications can send and retrieve data from a server asynchronously without interfering with the display and the behavior of the existing page. Many developers use JSON to pass AJAX updates between the client and the server.

How do I populate a Dropdownlist with JSON data as AJAX response in jQuery?

First we start off by creating a HTML dropdown on the page with an ID attribute. Next we create an AJAX POST in jQuery to a urlPath that will return the data we need in a JSON object. On the return of this AJAX request we are going to parse the response and use this in the helpers.

What is AJAX dropdown?

AjaxDropDownList is a dropdownlist control that has the following features: Fetch data asynchronously in the background from a server source, with no postback.


2 Answers

You could store the result of the post request in a javascript array, so you could reuse it, see following please:

var cachedObj = [];    $(document).ready(function(){                    $('#mnav a').on('click', function() {      var cat = $(this).attr('id');      _url = '&category_id=' + cat;      getData(cat, _url); //<-- Get data from ajax or cache    });  });    //This function replaces the $.post call (just for example)   function dummyPost(id, url){    //url should be used to make the post call    var data = "<span class='sub'>Test " + id + "</span>";    return data;  }    function getData(id, url){    //Try to get data from cache    var data;    if(cachedObj[url]) {      data = cachedObj[url];      console.log("Data retrived from cache");    }    else {      data = dummyPost(id, url);      cachedObj[url] = data;      console.log("Data retrived from post");    }        $('#mnav .sub').remove();    //$(data).insertAfter($('#mnav #' + id));    $('#mnav #' + id).append($(data));  }
.sub{    color: red;    font-weight: bold;  }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>  <div id="mnav" class="list-group">    <a id="1" class="list-group-item active">One</a>    <a id="2" class="list-group-item active">Two</a>    <a id="3" class="list-group-item active">Three</a>  </div>

I've maked the dummyPost function that should be modified in order to do the post request.

You could see in my example's log, that the first time you click on a link it retrieves his submenu with a "post", the next times instead, it get data from the cached array cachedObj.

I hope it helps you. Bye.

Update: Applied to your code should be like:

<script type="text/javascript">    var cachedObj = []; //<-- Add an array to cache submenus    //Add a function to retrieves data from cache or REST   function getData(url){     //Try to get data from cache     if(cachedObj[url]) {       console.log("Data retrived from cache");     }     else {       $.ajax({          type: 'GET',          url: 'index.php?route=test%2Fcategory%2Fchild' + url,          success: function(data) {                cachedObj[url] = data;                console.log("Data retrived from post");             }),          async:false       });     }     return cachedObj[url];  }   $(document).ready(function(){                     $('#mnav a').on('click', function() {         var cat = $(this).attr('id');         var url = '&category_id=' + cat;          var data = getData(url); //<-- Call the new function to get data         if(data.length>10){            $('#mnav #sub').remove();            $(data).insertAfter($('#mnav #' + cat));         }     });  }); </script> 

I can't test it, so it could be contains some errors.

like image 70
Alessandro Avatar answered Sep 25 '22 00:09

Alessandro


The problem might be that you are not preventing the default action of the anchor tag. Try adding event.preventDefault. This way the browser will fire the POST request, not the GET one.

Besides it'd be best to bind the event to the document not to the elements if you are adding new #mnav a elements via ajax.

 $(document).ready( function() {                     $(document).on('click', '#mnav a', function( event ) {         event.preventDefault();         // some code     });  }); 
like image 39
a.barbieri Avatar answered Sep 27 '22 00:09

a.barbieri