I've been frustated trying to find the best way to load and unload some JS file via jQuery, this was last what I can do:
$("#button").live("click", function(){
var pl = $(this).attr('rel');
$.getScript('' + siteAddress + 'min/?js=fjs'+ pl +'', function() {
$('#container').load(""+ siteAddress +"load/"+ pl +"/");
});
});
What I want to do is to load some page via jQuery, and at same time it will include appropriate external JS file for current page that been loaded, it work fine for the first time, but when I click the button again, the last JS still loaded, so it will trigger the function inside JS file twice time for same page.
I've been try use .append, also by change <script> attribute and create dynamicaly <script> element but still, all i got is same result.
You can't "unload" JavaScript. Once it's loaded, it's loaded. There's no undo.
However, you can detach event handlers. See: http://api.jquery.com/unbind/
live() is a special case for unbind(), though. Live event handlers are attached to document rather than the element, so you have to remove the handler like so:
$(document).unbind('click');
However, that would probably remove more handlers than just the one in question, so you can do one of two things: 1) name your handler function or 2) create a namespace.
Naming handler function
function myClickHandler(){
var pl = $(this).attr('rel');
$.getScript('' + siteAddress + 'min/?js=fjs'+ pl +'', function() {
$('#container').load(""+ siteAddress +"load/"+ pl +"/");
});
}
$("#button").live("click", myClickHandler);
// And later ...
$(document).unbind('click', myClickHandler);
Namespacing
$("#button").live("click.myNamespace", function(){
var pl = $(this).attr('rel');
$.getScript('' + siteAddress + 'min/?js=fjs'+ pl +'', function() {
$('#container').load(""+ siteAddress +"load/"+ pl +"/");
});
});
// And later...
$(document).unbind('click.myNamespace');
UPDATE:
As #RTPMatt mentions below, die() is actually more appropriate. The method described above will work, but die() is easier to use. However, with die() you must match the selector exactly to the one used when you called live() or the results may be unpredictable:
$("#button").live("click", function(){
var pl = $(this).attr('rel');
$.getScript('' + siteAddress + 'min/?js=fjs'+ pl +'', function() {
$('#container').load(""+ siteAddress +"load/"+ pl +"/");
});
});
// And later ...
$('#button').die('click');
You could even have a "placeholder function" and check for its existence before loading the script again. But, first, i think it would be better to load the page and only after load the external script (and only if it's needed)
$("#button").live("click", function()
{
var pl = $(this).attr('rel');
//now we load the page, and then the "complete" callback function runs
$('#container').load(""+ siteAddress +"load/"+ pl +"/", function()
{
we check if the function is present into memory
if (typeof window["page_" + pl + "_init"] == 'undefined')
{
//function not found, we have to load the script
$.getScript('' + siteAddress + 'min/?js=fjs'+ pl +'');
}
});
});
Into the external script you will need to have the function
function page_abcde_init()
{
//this is just a place holder, or could be the function used
//to initialize the loaded script (sort of a document.ready)
}
Where "abcde" of "page_abcde_init()" is the value of the clicked element var pl = $(this).attr('rel');
Related
I would like to execute a function after a redirection on my site. Here is my code:
$('a.filter-redirect').on('click', function(){
window.location.replace('/technos/');
filter();
});
And here is my function "filter":
$('a.filter-tech').on('click', function filter(){
var tag = $(this).attr('rel');
var val_input = $('#tag').val();
if(tag === val_input){
$('#tag').val('');
$('#form').submit();
}
if(val_input){
$('#tag').val(val_input + ',' + tag)
}
$('#tag').val(tag);
$('#form').submit();
return false;
});
I am not an expert in JS and jQuery and the code may be wrong. My function works, but not after the redirection.
when you redirect to a new page the scripts on the previous page are no more executed. So you have to call this function as soon as the new page is loaded e.g. on $(window).load() or $(document).ready() not on an click in previous page.
$(document).ready(function(){
var tag = $(this).attr('rel');
var val_input = $('#tag').val();
if(tag === val_input){
$('#tag').val('');
$('#form').submit();
}
if(val_input){
$('#tag').val(val_input + ',' + tag)
}
$('#tag').val(tag);
$('#form').submit();
return false;
})
When you redirect your page location changes, which means that a new page is loaded and the old is gone.
To do some action in the new page you have to add it in that page (for example in the body on load or in a script tag)
When you go to the new page, keep all your required code inside $(document).ready() or window.load()
Somthing like this
function runOnPageLoad() {
alert('Hey There');
}
window.onload = runOnPageLoad;
Or in jquery as
$(document).ready ( function(){
alert('Hey There');
});
Hope it helps
I am getting an id that is not addressable by jquery ("#"+id).something .
At document start I have a :
var g_justClicked = '';
$.ajaxSetup({
beforeSend:function(event){
if(g_justClicked) {
console.log('g_justClicked='+g_justClicked+' tagName='+$('#'+g_justClicked).tagName);
};
var wOffset = $('#'+g_justClicked).offset();
$('#loading').show();
},
complete:function(){
$('#loading').hide();
}
});
At document end I have another script (all elements with class spinner should set the global variable 'g_justClicked'):
$(document).ready(function () {
$('.spinner').click(function() {
g_justClicked = $(this).attr('id');
console.log('.spinner.click: g_justClicked='+g_justClicked);
});
This works fine, the variable is set and displayed correctly in ajaxSetup.
BUT: referencing it in tagName= or in wOffset = with
$('#'+g_justClicked).
results in
"TypeError: wOffset/tagName is undefined"
Note: all ids start with several characters, t.e. "boxshow12345" is a typical id.
What am I doing wrong?
I think was able to reproduce your scenario here: https://jsfiddle.net/mrlew/qvvnjjxn/3/
The undefined in your console.log is because you're accessing an inexistent jQuery property: .tagName. This property is only available to native HTML Element.
To retrieve the tag name from a jQuery Object, you should use: .prop("tagName"), or access the property accessing the native element with $('#'+g_justClicked)[0].tagName
So, if you change
console.log('g_justClicked='+g_justClicked+' tagName='+$('#'+g_justClicked).tagName);
to:
console.log('g_justClicked='+g_justClicked+' tagName='+$('#'+g_justClicked).prop("tagName"));
Will successfully log: g_justClicked=boxshow12345 tagName=BUTTON, as expected.
Note: In order to your logic work, you have to click .spinner first.
Your problem is that your ajax setup runs regardless of whatever you do in the click handler, and it runs before you even setup that handler. The initial value for g_justClicked is empty string, and this is what it tries to access in $('#'+g_justClicked), hence the error.
If you want to click the spinner and then pass the id to the beforeSend, do it like this:
$(document).ready(function() {
$('.spinner').click(function() {
var g_justClicked = this.id; //simplify this a bit
console.log('.spinner.click: g_justClicked=' + g_justClicked);
// call ajax
_setupAjax( g_justClicked );
});
});
function _setupAjax(g_justClicked) {
$.ajaxSetup({
beforeSend: function(event) {
if (g_justClicked) {
console.log('g_justClicked=' + g_justClicked + ' tagName=' + $('#' + g_justClicked).tagName);
};
var wOffset = $('#' + g_justClicked).offset();
$('#loading').show();
},
complete: function() {
$('#loading').hide();
}
});
}
UPDATE
If you don't want a separate function, just move your ajax setup into the click handler:
$(document).ready(function() {
$('.spinner').click(function() {
var g_justClicked = this.id; //simplify this a bit
console.log('.spinner.click: g_justClicked=' + g_justClicked);
// call ajax setup
$.ajaxSetup({
beforeSend: function(event) {
if (g_justClicked) {
console.log('g_justClicked=' + g_justClicked + ' tagName=' + $('#' + g_justClicked).tagName);
};
var wOffset = $('#' + g_justClicked).offset();
$('#loading').show();
},
complete: function() {
$('#loading').hide();
}
});
});
});
OK #mrlew.
Answer: I tried your .prop appoach, but still got "undefined". Now back to the roots:
The goal is to get the id of any element that was clicked to modify the busy indicators position, while ajax is running. Newly I am back to my original approach, without global variable and parameter passing:
$(document).ready(function () {
$('.spinner').click(function() {
_setupAjax();
});
});
which works, and:
function _setupAjax() {
$.ajaxSetup({
beforeSend: function() {
$('#loading').show();
wJustClicked = $(this).attr('id'); /// <- that doesnt work!
console.log("_setupAjax wJustClicked="+wJustClicked);
console.log('_setupAjax tagName=' + $('#' + wJustClicked).prop("tagName"));
....defining css based on id (no problem)..
which yields "undefined" twice. I tried so many ways to get that f.... id.
#mrlew
thanks a lot for your help. Meanwhile I found the solution. All trouble came from a timing problem. Here is what works (for all DIV, SPAN and IMG of class=spinner and having an id:
$(document).ready(function () {
_setupAjax();
$('.spinner').click(function() {
wJustClicked = $(this).attr('id');
if(wJustClicked == null) alert('Id missing on item clicked');
console.log('.spinner.click! id='+wJustClicked);
var wOffset = $('#' + wJustClicked).offset();
var xPos = Math.round(wOffset.left) + 8;
var yPos = Math.round(wOffset.top) + 4;
console.log(wJustClicked+' offset left='+wOffset.left+' top='+wOffset.top+' xPos='+xPos+' yPos='+yPos);
wDiv = 'loading';
$('#'+wDiv).css('left',xPos);
$('#'+wDiv).css('top',yPos);
});
and the js function:
function _setupAjax() {
$.ajaxSetup({
beforeSend: function() {
$('#loading').show();
},
complete: function() {
$('#loading').hide();
}
});
}
A strange thing remained (I have firebug installed), which I have solved with Math.round: the x and y position come overdetailed like 170.5134577 and 434.8768664 ?!?
I can live with that. But where does this pseudo precision come from?
Again thanks a lot to keep my hope upright.
I'm attempting to dynamically create an iFrame and add HTML into it from the current document. The iFrame gets created successfully, but when the function gets to the point where it needs to add the HTML in, it doesn't do it.
Here's my code:
function createiFrame(min, max, key) {
console.log("Max-Width", max);
//CREATING A CLASS FOR THE IFRAME
var iframeClass = key + "-" + max;
//var path = window.location.pathname;
//var page = path.split("/").pop();
//ADDING AN IFRAME INTO THE DOCUMENT AND ADDING ON THE CLASS
$(document).ready(function() {
$('<iframe>', {
width: max
}).addClass(iframeClass).prependTo('body');
});
var requiredHTML = document.getElementById('container').innerHTML;
console.log("RequiredHTML", requiredHTML);
//ADDING THE COLLECTED HTML INTO THE IFRAME -- THIS IS WHERE
//IT STOPS WORKING
$('.' + iframeClass).ready(function() {
console.log("iFrame ready");
$('.' + iframeClass).contents().find('body').html("<p>Testing it out</p>");
});
var $head = document.getElementsByTagName('head')[0].innerHTML;
$(document).ready(function() {
$('.' + iframeClass).contents().find('head').append($head);
});
}
EDIT
I've realised this problem is occurring because when I try to run that code, the DOM isn't ready yet.
So new question;
How do I get the DOM ready?
check out this post:
addEventListener to iFrame
you need to use
$('#myIFrame').load(function(){
....
$('.' + iframeClass).ready(function() {
...
}
Doesn't work because an iframe being ready doesn't trigger the Event 'DOMContentLoaded' which .ready() is waiting for. You'll need to refer directly to a document, which will then trigger the DOMContentLoaded event. This should work based on that.
$(iframeClass document).ready(function() {
...
}
I will stress though that this isn't something that I've tried before, but it seems like it's just a matter of which document you're referring to.
So this little script was working exactly how i wanted it to but i did something to mess it up, basically i have one jQuery function
function loadDiv(id, page) {
$(function () {
$("#" + id).load(page);
});
}
and then this HTML (obviously through a for loop)
Edit this Post -->
I have tried removing "javascript:" I actually tried that because I could think of nothing else wrong.
I'm not sure but I don't think you need the extra jQuery wrapper.
function loadDiv(id, page) {
$(function () { // what is this line for?
$("#" + id).load(page);
});
}
I would just keep:
function loadDiv(id, page) {
$("#" + id).load(page);
});
I would write your links like so
Edit this Post
Then write your function like so
$('body').on('click', '.loadTrigger', function(){
var id = $(this).attr('data-id');
var page = $(this).attr('data-page');
$("#" + id).load(page);
});
I'm currently writing an object oriented module which assigns callback to dynamically generated elements.
function Instant(containerID) {
this.var1 = 0;
this.var2 = 0;
this.containerID = containerID;
// and more variables...
};
And here containerID is the id of a DIV which is dynamically generated. I populate this DIV via Ajax Request which reads a file like the following:
<!-- content.html -->
<div class="general_container">
<div class="top_container">
<!-- plenty of divs, spans etc -->
</div>
<div class="tweet_section">
<!-- plenty of divs, spans etc -->
</div>
</div>
Now the important part is, I assign all callbacks like the following:
Instant.prototype.addCallbacks = function() {
$(this.containerID + " bar").click(function() {
$(this.containerID + " bar").foo();
});
$(this.containerID + " bar").click(function() {
$(this.containerID + " bar").foo();
});
$(this.containerID+ " bar").click(function(e) {
$(this.containerID + "bar, " + this.containerID+ " bar").foo();
});
});
As you see, I always have to put this.containerID before each selector to assign events. (Therefore, I make sure I'm selecting only one element) Now, my code is full of clutter as I have plenty of this.containerIDs. I don't know if there is a smarter method to make my code easy. Any help will be appreciated.
Here is a sample JSFiddle.
Note that this is not my real module, I just made it up to make it clear!
Then you shouldn't be using IDs. You should be using classes instead.
It would take long to edit your code, but here's a hint: Add a handler to the parent. Use event delegation, like .on(). Then have it listen for all children, now or future.
Create a separate java script file and put your add callbacks function in there and just pass the containerID. That way, you can re-use it later. However, looks like you cannot get rid of containterID since you will be needing that to do your add, subtract, save etc..
in your current file shown as above,
Instant.prototype.addCallbacks = createAddCallbacks(this.ContainerID);
create addCallbacks.js
function createAddCallbacks(containerId)
{
Instant.prototype.addCallbacks = function() {
$(containerId + " bar").click(function() {
$(containerId + " bar").foo();
});
$(containerId + " bar").click(function() {
$(containerId + " bar").foo();
});
$(containerId+ " bar").click(function(e) {
$(containerId + "bar, " + containerIdD+ " bar").foo();
});
});
}
Like #JosephTheDreamer said, use Event Delegation. (Jquery.fn.on)
Using event delegation you set one handler to multiple targets. It means just one handler in memory and dynamic event handlers set.
I made a demonstration modifying your code, take a look...
Instant.prototype.addCallbacks = function () {
var selfContainer = null, // DOMElement container
me = this; // Object reference
$('body').on("click", ".selection_container .btn-add", function () { //Using event delegation
selfContainer = $(this).parents(".general_container"); //set DOMElement
selfContainer.find("input[name=currentValue]").val(++me.instantValue);
});
$('body').on("click", ".selection_container .btn-subtract", function () {
selfContainer.find("input[name=currentValue]").val(--me.instantValue);
});
$('body').on("click", ".selection_container .btn-reset", function () {
me.instantValue = 0;
selfContainer.find('input[name=currentValue]').val(0);
});
$('body').on("click", ".selection_container .btn-save", function () {
me.savedValue = me.instantValue;
});
$('body').on("click", ".selection_container .btn-load", function () {
me.instantValue = me.savedValue;
selfContainer.find('input[name=currentValue]').val(me.savedValue);
});
};
Hope it helps...
So, I think I find a better method according to this post
I wanted to limit the scope of my selector.
Firstly, I'll create a jQuery instance variable
function Instant(containerID) {
this.var1 = 0;
this.var2 = 0;
this.container= $('#'+containerID);
// and more variables...
};
and adding a new prototype like this
Instant.prototype.$ = function(selector){
return this.container.find(selector);
};
I'll only use this.$(selector) function which is better.