I have a HTML5 application which is using jquery 3.2.1.
In part of the application - a search feature - I make an ajax request. The response from the ajax request is HTML, and this includes a tag which links to a js file which is hosted on the same server as the application.
So the ajax code looks like this - for making the ajax request and writing the response to a div with the ID #ajaxContent
:
$.ajax({
url: $('#searchRegulations').attr('action'),
type: 'post',
cache: false,
data: $('#searchRegulations').serialize()
}).done(function (response, status, xhr) {
if (response) {
$('main .content').hide();
$('#ajaxContent').html(response).show();
return false;
}
}
});
If I inspect #ajaxContent
I can see that the tag is included in the ajax response:
I have also checked my Network tab to make sure /js/search_regulations.js
is being loaded correctly, and it's giving a 200 response:
Inside search_regulations.js
there is some jquery which toggles some filters that are present in #ajaxContent
.
The problem is that this code only seems to be working about 50% of
the time. When it works it will toggle the state of some filter
buttons by adding/removing a class.active
to elements inside
.browse-ctp__filters-data
and then writing them to a hidden form
with the ID#tmpFilters
.
To ensure the script was "firing" I put in the line console.log('search_regulations.js firing');
and sure enough this is shown in the Console every time irrespective of whether the script functions or not.
What's stranger is that if I cut/paste the code into my Console after the ajax response has been written to the page, it always works as expected.
Is this some issue with the way the script is being brought into the page?
I've pasted the script below, but I don't think it's an issue with the code in it, rather the way the browser/ajax response is being handled:
$(function() {
console.log('search_regulations.js firing');
/* toggle the active (applied) state on browse by filters */
/* @link https://stackoverflow.com/questions/48662677/switch-active-class-between-groups-of-include-exclude-buttons */
$(document).on('click', '.browse-ctp__filters-data .include, .exclude', function(){
var $this = $(this);
// Split name into array (e.g. "find_355" == ["find", "355"])
var arr = $this.attr('name').split('_');
// Toggle active class
$this.toggleClass("active");
if ($this.siblings().hasClass("active")) {
$this.siblings().removeClass("active")
}
// Remove any existing instances of the filter from hidden form
$('#tmpFilters input[value="exclude_'+arr[1]+'"]').remove();
$('#tmpFilters input[value="find_'+arr[1]+'"]').remove();
// If a filter has been applied then add it to hidden form
if ($this.hasClass('active')) {
$('#tmpFilters').append('');
}
});
});
I've offered a bounty because it's not a trivial problem to solve - demonstrated by the fact nobody has given a workable answer. I expect the correct answer to:
- Be demonstrable with jsfiddle or equivalent.
- Explain how/why it works.
- Understand that the ajax response is HTML and js. The js acts on HTML elements in the response. Therefore both the HTML and js need to be included in the response - as opposed to saying "just add the js to a global file" (I don't want the js to be global, because it's specific to the HTML response given, and can vary in different parts of the application).
- Should not use a timeout (
setTimeout
or whatever). If the user interacts with the UI elements - such as buttons - returned in the HTML response before the timeout and therefore js is fired... that just leads to the same problem we have now. So that isn't a valid solution as far as I'm concerned. - If this problem is impossible to solve in HTML5/jquery explain why and suggest any alternative ways to handle it.
jsfiddle showing the HTML and script tag returned via ajax:
Several people have asked for a fiddle or demo. No 2 people would get the same outcome - which is very much the point of the question - so I didn't make one originally. The HTML returned that gets written to #ajaxContent
is shown here: http://jsfiddle.net/v4t9j32g/1/ - this is what dev tools in the browser shows following the ajax response. Please note that the length of the content returned can vary, since it's the response to a keyword search facility that brings back a load of filter buttons. Also note that this HTML response contains the line . That is where the problematic js is located and the full contents of that are shown above in this question - the bit that includes
console.log('search_regulations.js firing')
Answer
One of the problems that I see is that you're binding the onclick
to the same elements multiple times...
Since the js can be loaded multiply times via ajax requests, it is important to first detach, before attaching again events.
The other problem, is that you're running the code in $(document).ready
event (that is when HTML-Document is loaded and DOM is ready), however you'd probably be better off to run the code in the $(window).load
event (which executes a bit latter, when complete page is fully loaded, including all frames, objects and images)
Example:
$(window).load(function() {
console.log('search_regulations.js firing');
//off: detach the events
//on: attach the events
$('.browse-ctp__filters-data .include, .exclude').off('click').on('click', function(){
...
}
});
No comments:
Post a Comment