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: GET
s 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 :-(
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.
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.
AjaxDropDownList is a dropdownlist control that has the following features: Fetch data asynchronously in the background from a server source, with no postback.
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.
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 }); });
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With