I am using jQuery to show/hide a div container (#pluginOptionsContainer), and load a page (./plugin_options.php) inside it with the required POST vars sent.
What POST data is sent is based on the value of a select list (#pluginDD) and the click of a button (#pluginOptionsBtn)...
It works fine in Firefox, but doesn't work in IE.. The '$("#pluginOptionsContainer").load()' request never seems to finish in IE - I only see the loading message forever...
bind(), empty() and append() all seem to work fine in IE.. But not load()..
Here is my code:
// wait for the DOM to be loaded
$(document).ready(function() {
// hide the plugin options
$('#pluginOptionsContainer').hide();
// This is the hack for IE
if ($.browser.msie) {
$("#pluginDD").click(function() {
this.blur();
this.focus();
});
}
// set the main function
$(function() {
// the button shows hides the plugin options page (and its container)
$("#pluginOptionsBtn") .click(function() {
// show the container of the plugin options page
$('#pluginOptionsContainer').empty().append('<div style="text-align:center;width:99%;">Loading...</div>');
$('#pluginOptionsContainer').toggle();
});
// set the loading message if user changes selection with either the dropdown or button
$("#pluginDD,#pluginOptionsBtn").bind('change', function() {
$('#pluginOptionsContainer').empty().append('<div style="text-align:center;width:99%;">Loading...</div>');
});
// then update the page when the plugin is changed when EITHER the plugin button or dropdown or clicked or changed
$("#pluginDD,#pluginOptionsBtn").bind('change click', function() {
// set form fields as vars in js
var pid = <?=$pid;?>;
var cid = <?=$contentid;?>;
var pDD = $("#pluginDD").val();
// add post vars (must use JSON) to be sent into the js var 'dataString'
var dataString = {plugin_options: true, pageid: pid, contentid: cid, pluginDD: pDD };
// include the plugin option page inside the container, with the required values already added into the query string
$("#pluginOptionsContainer").load("/admin/inc/edit/content/plugin_options.php#pluginTop", dataString);
// add this to stop page refresh
return false;
}); // end submit function
}); // end main function
}); // on DOM load
Any help would be GREATLY appreciated! I hate IE!
IE sometimes caches responses. You can check by watching the requests IE makes to the server. Fiddler2 is a tool that's good for watching http requests.
If you notice that you hit submit and don't see any http requests being made, IE is caching the result.
If that's the case, you can add a random number to the url to cache bust it:
$("#pluginOptionsContainer").load("url.php?random=" + Math.random()*99999, dataString);
IE is sometimes pickier then FF when it comes to duplicate element ids.
Check if every ID you use is used only once and is not created anew during the ajax call.
If caching is the issue, then try setting cache = false in jquery's ajax setup...
$.ajaxSetup ({
cache: false,
});
Related
I am working on a browser extension.
It has two parts:
popup - which contains checkboxes
content script - which contains the code to alter the CSS property
I am saving the states of checkboxes so that the next time I open the popup again the same checkboxes are marked as checked.
When I use the checkboxes they change the DOM as intended, however when I try to alter the DOM after the page is loaded, changes are not reflected. This is probably because the element on which I want to perform the operation is loaded slow and thus required operations fail.
I tried to use onload and ready but nothing worked
$('.question-list-table').on('load', function() {
browser.storage.local.get(["options"], modifyThenApplyChanges)
});
I also tried, but nothing changed.
$('body').on('load','.question-list-table', function() {
browser.storage.local.get(["options"], modifyThenApplyChanges)
});
Also, there is no visible error with the popup or content script as I test in both Google Chrome and Mozilla Firefox.
Update:
As suspected earlier, the target element is loaded slowly so I used setTimeout for 5 seconds and the script is working as intended.
Loading time is variable and I want to show my changes as early as possible everything in a consistent manner.
After going through MutationObserver as suggested by #charlietfl in the comment section, this is what I coded and works for me
// Mutation Observer
const observer = new MutationObserver(function (mutations) {
mutations.forEach(function(mutation) {
if(mutation.addedNodes.length) {
//do stuff
}
});
});
el = document.getElementsById('elementId');
if(el) {
observer.observe(el, {
childList: true // specify the kind of change you are looking for
});
}
I have some custom JavaScript on my SquareSpace site that manipulates Product titles beyond what you can do with SquareSpace's default style editor. It works when initially loading the page (https://www.manilva.co/catalogue-accessories/) but if you click on any of the categories on the left, the styling resets to the default.
I'm assuming the JavaScript is being overwritten by the SquareSpace style, but I can't figure out why. Perhaps I'm calling the function in the wrong place?
Any suggestions would be helpful.
Thanks!
Current code:
document.querySelectorAll(".ProductList-filter-list-item-link".forEach(i=>i.addEventListener("click", function()
{
var prodList = document.querySelectorAll("h1.ProductList-title");
for (i = 0, len = prodList.length; i < len; i++)
{
var text = prodList[i].innerText;
var index = text.indexOf('-');
var lower = text.substring(0, index);
var higher = text.substring(index + 2);
prodList[i].innerHTML = lower.bold() + "<br>" + higher;
});
The source of your problem is that your template has AJAX loading enabled. There are currently a couple generally-accepted ways to deal with this as a Squarespace developer:
Disable AJAX loading
Write your javascript functions in a
manner that will run on initial site load and whenever an "AJAX load" takes place.
Option 1 - Disable AJAX:
In the Home Menu, click Design, and then click Site Styles.
Scroll down to Site: Loading.
Uncheck Enable Ajax Loading.
Option 2 - Account for AJAX in Your JS
There are a number of ways that developers approach this, including the following, added via sitewide code injection:
<script>
window.Squarespace.onInitialize(Y, function() {
// do stuff
});
</script>
or
<script>
(function() {
// Establish a function that does stuff.
var myFunction = function() {
// Do stuff here.
};
// Initialize the fn on site load.
myFunction();
// myFunction2(); , etc...
// Reinit. the fn on each new AJAX-loaded page.
window.addEventListener("mercury:load", myFunction);
})();
</script>
or
<script>
(function() {
// Establish a function that does stuff.
var myFunction = function() {
// Do stuff here.
};
// Initialize the fn on site load.
myFunction();
// Reinit. the fn on each new AJAX-loaded page.
new MutationObserver(function() {
myFunction();
// myFunction2(); , etc...
}).observe(document.body, {attributes:true, attributeFilter:["id"]});
})();
</script>
Each of those works for most of the latest (at time of writing) templates most of the time. Each of those have their advantages and disadvantages, and contexts where they do not work as one might expect (for example, on the /cart/ page or other "system" pages). By adding your code within the context of one of the methods above, and ensuring that the code is of course working in the desired contexts and without its own bugs/issues, you will have your code run on initial site load and on each AJAX page load (with some exceptions, depending on the method you use).
Your problem is the page does not reload when clicking a button on the left, just some elements are removed, added and replaced. The changed elements will not be restyled. You will need to re-run your JavaScript after one of those buttons is clicked. Perhaps something like this:
document.querySelectorAll(
".ProductList-filter-list-item"
).forEach(
i=>i.addEventListener(
"click", ()=>console.log("hello")
)
)
where you replace console.log("hello") with whatever resets your formatting.
I have added a Select all / deselect all wrapper round a Select2 multi select control.
It works by looping through the options, pushing the values into an array then passing the array to the selct2 val as follows:
mySelect2.select2("val", mySelectedValuesArray);
This works fine in Chrome and in cases where there are not so many options to be selected. But in IE8 where they might be 100+ options the browser freezes as it attempts to render the selected values and I get multiple Stop Running this Script? alerts. I have had similar problems with IE8 when using expandable text boxes where the browser freezes whenever it has to increase the height of the textbox and assume its a quirk of the IE rendering engine. Anyway, in this case it renders the page unusable whenever you select all with anything more than 30 or 40 options.
I have tried creating the markup for the selected options container manually so as to just add it in one go, but, aside form then having to manually wire up the click events on each one to be able top remove them, Im finding when the selects change event fires it, select2 ends up removing the options anyway and i cant find a way round this.
Any ideas?
As an update here is my code
$(".filterIconContainer .filtericon").on("click",function () {
var $this = $(this);
var $associatedSelect = $("#" + $this.attr("data-associated-select"));
if ($associatedSelect.length == 0) {
$associatedSelect = $("#filterContainer div[data-tabid='" + $("#filterTabs li.active").attr("id") + "'] select");
}
if ($this.attr("data-action") == "select") {
var selected = [];
$associatedSelect.find("option").each(function (i, e) {
selected.push($(e).attr("value"));
});
setTimeout(function() {
$associatedSelect.select2("val", selected); // Browser throws stop running this script alert during select2 processing this line
$associatedSelect.change(); // call the change event to force any post change action
},5);
}
else {
$associatedSelect.select2('val', '');
$associatedSelect.change(); // call the change event to force any post change action
}
});
In the end I fixed this by making a change to the select2.js file
$(data).each(function () {
var i = this;
setTimeout(function () {
self.addSelectedChoice(i);
}, 0);
});
Wrapping the call to addSelectedChoice in a setTimeout allows IE to render the change without throwing a slow running script error.
I'm using Ajax to load the contents of a select:
<select id = "idResultEntryMeet" class="form-control input-md" size = 1>
</select>
...
$('#idResultEntryMeet').mousedown(function() {
$.post("/cgi-bin/listOptions", function(data) {
$('#idResultEntryMeet').html(data);
});
});
This isn't consistent across browsers, which makes me think that there's a problem with the code:
IE9 never shows anything in the select
FF 27 works as expected
Chrome and IE11 don't show anything in the pull-down on the first
mouse click, but will show the expected contents on the second mouse
click. I can fix this on both browsers by pre-loading the select
during the initial page load
Opera and Safari require a second mouse click, even with an initial preload
Any suggestions on what's wrong with this?
EDIT
Sorry, guess this wasn't obvious: the select must be dynamic. The options are constantly changing, depending on the contents of a database. The idea is that the user sees the current options when they click the pull-down on the select. Using a click (instead of mousedown) handler doesn't work, since the user can't then actually select anything they see in the pull-down.
And the CGI code returns an HTML snippet, containing the options. Firebug shows a correctly-formed select containing options on completion of the POST.
EDIT
The problem is that the Ajax request has to be synchronous (Sjax?) (as more-or-less suggested in the comments), to prevent interfering with whatever happens when the select pull-down is activated. This code works with proper browsers (and almost works in IE9), but changing async to true causes consistent problems with various browsers:
$('#idResultEntryMeet').mousedown(function() {
$.ajax({
type : "POST",
url : "/cgi-bin/listOptions",
async : false
}).done(function(data, textStatus, jqXHR) {
$('#idResultEntryMeet').html(data);
});
});
Try that (just tested on chrome):
$('#idResultEntryMeet').on('mousedown', function(e){
if(!e.view) return;
e.preventDefault();
var _self = this;
$.post("/cgi-bin/listOptions", function (data) {
$(_self).html(data);
var mdwn = document.createEvent("MouseEvents");
mdwn.initMouseEvent("mousedown", false, false, null, 0, 0, 0, 0, 0, true, false, false, true, 0, null);
_self.dispatchEvent(mdwn);
});
});
Simplified DEMO
EDIT: doesn't work on FF nor IE...
Try change your code for:
html
<select id="idResultEntryMeet" class="form-control input-md" size="1">
</select>
js
$(document).ready(function() {
$.post("/cgi-bin/listOptions", function(data) {
$('#idResultEntryMeet').html(data);
});
});
$('#idResultEntryMeet').change(function() {
var valueSelected = $(this).val();
alert(valueSelected);
//Do something
});
Edit:
you need include the delegate bind with jquery for do this dinamic.
$('#idResultEntryMeet').bind("click", function() {
var data = '<option value="volvo">Volvo</option><option value="saab">Saab</option>';
$('#idResultEntryMeet').html(data);
});
And need format the return of the method some like this
Im building a small application and I have some click events binded to some span tags that trigger AJAX requests to a PHP file which queries a MySQL database and spits out the results to populate the targeted area.
However, sometimes i will be clicking the buttons and I have conditionals in place to stop multiple clicking to prevent duplicate content being added numerous times.
I click on a button and firebug tells me that the ajax request had actioned more than once, sometimes it will multiply - so it will start by doing it 2 times or another time it will carry our the request 8 times on one click and obviously flood my content area with duplicate data.
Any ideas?
EDIT
Code for a button is as follows:
<span class="btn"><b>Material</b></span>
This would be enabled by
$('.btn').bind('click', matOption);
and this would be controlled by something like this
var matOption = function() {
$(this).addClass('active');
// remove colours if change of mind on materials
if($('#selectedColour').val() >= 1) {
$('.colour').slideUp(500).children().remove();
$('#selectedColour').val('');
$('.matColOpt .btn').html('<b>Material Colour</b>').removeClass('active').css('opacity', 0.55);
$('.btn').eq(2).unbind('click', colOption); // add click to colour
$('#stage h1 span').eq(2).fadeOut(500);
$('.paperOpt .btn').css('opacity', 0.55).unbind('click', selectPaper);
}
// ajax req for available materials
var cid = $('#selectedColour').val();
var target = $('#notebookOpts .matOpt ul');
$.ajax({
type: "GET",
url: ajaxFile+"?method=getMaterials",
beforeSend: function() {if($('.mats').children('li').size() >= 1) { return false; }},
success: function(data) {
target.append(data).slideDown(500);
$('.mats li').bind('click', matSelect);
},
error: function() {alert('An unexpected error has occurred! Please try again.');}
});
};
You're probably binding your matOption function more than once.
if(!window.matOptionBound){
$('.btn').bind('click', matOption);
window.matOptionBound = true;
}
If you have a code that binds an event handler to a DOM element repeatedly then that event handler does gets executed repeatedly on the event. so if your code such
$("span").click(myHandlerFunction)
gets executed thrice, then you have just told jQuery to fire myHandlerFunction thrice on every click of span. It would be good to make sure there is no such condition goign on in your code. If that is not true then please post your code so that I can help further.
PS: The safest way to do this will be as
$("span").unbind("click",myHandlerFunction).bind("click",myHandlerFunction)