jQuery.trigger() not firing on refresh - javascript

I have an html page, Home.htm, that contains an iframe which holds another page Child.htm, i.e.
<body>
<div>
<iframe id="child-iframe" src="Child.htm"></iframe>
</div>
</body>
Home.htm also contains some javascript/jQuery that retrieves data and depending on this data retrieves more information and then triggers an event set up in the Child.htm file to display this information within Child.htm, i.e.
<script>
$(document).ready(function () {
$.getJSON("http://getsummarydata/001")
.done(function (data) {
if (data meets some condition) {
$.getJSON("http://getspecificdata/001")
.done(function (data) {
// Trigger the event
var target = $("#child-iframe");
if (target[0] !== undefined) {
target[0].contentWindow.$(target[0].contentWindow.document).trigger("data-available", [data]);
}
});
}
}
});
</script>
Within Child.htm I have set up the custom event, data-available, and its handler using jQuery as follows;
<script>
// Event handler
function myFunc(data) {
// Display the data
}
// Event
$(document).on('data-available', function (__e, __data) {
myFunc(__data);
});
</script>
When the Home.htm page is first loaded the data is retrieved succesfully, the event is triggered and the data is displayed as expected within the iframe. However, when I refresh the Home.htm (F5), the data is still retreived but the trigger is no longer fired - infact I get the following error.
Uncaught TypeError: target[0].contentWindow.$ is not a function
Even though target[0].contentWindow seems ok.
I don't know why this happening on a refresh and any help with resolving this would be much appreciated.
Paul

It sounds like your events are firing before the iframe has completely loaded. That would explain why it can't find $ when it needs it, but it is there when you inspect it. One potential reason might be that your data requests are cached and so return almost immediately.

Related

Catching an element "load" event for append()-ed elements using jQuery?

So, I have a div (id="content") where I'm loading various other HTML I get from AJAX requests. I want to be able to tell when they have loaded successfully, but the load event does not seem to work with append().
I have this simplified example to illustrate the situation (in the real case, the listeners for the 'load' event are registered in different files which get loaded in the section of the script)
<html>
<head>
<script
type="text/javascript"
src="http://code.jquery.com/jquery-latest.min.js">
</script>
</head>
<body>
<div id="content"><div>
<script type="text/javascript">
$(document).ready( function () {
// this does not seem to work
$("#myDiv").on('load', function () {
console.log("myDiv loaded");
});
// neither does this
$("#content").on('load', "#myDiv", function () {
console.log("myDiv loaded by delegation");
});
// the content to append will come from the network
$("#content").append($("<div id='myDiv'>myDiv</div>"));
});
</script>
</body>
</html>
Of course, in the real case things are more complex (the loaded data can be anything) so these are not valid options:
having a function called after the div has loaded
having a function embedded in the loaded code (the code is generated from template files)
If you get the data from Ajax requests you should actually use the Ajax done() function. Since the call is async, you wont be able to listen to the changes in the div. Another solution would be to add a body delegate on the div and make it listen to the change event.
$("body").delegate("mydividentifier", "change", function(f){});
$.ajax().done(function(f){});

jQuery stops working after ajax loading

some info
I'm working on a webpage that can load data on multiple layouts, so user can choose which one is best. It can be loaded in a list or a cards like interface, and the data is loaded using ajax.
In this page I also have a notifier for new messages that the user received. The ajax function is new, and when page was loaded by the php scripts, the js script (that add a badge with the number of unread messages to a link on a menu item) was working ok.
I'm using HTML5, PHP, jQuery and a mySQL DB.
jQuery is imported onto the HTML using
<script src="https://code.jquery.com/jquery.js"> </script>
So it's a recent version.
the problem
Now, when I load the data onto the page using ajax, the js script won't work anymore. I had the same issue with another js script and I managed to solve it by using the delegate event binder.
But my unread messages updater runs on a time interval, using
<body onload="setInterval('unread()', 1000)">
the unread() js is quite simple:
function unread() {
$(document).ready(function(){
$('#menu_item').load('ajax_countNewMsgs.php');
});
}
it calls a php script which grabs the unread msgs count from the DB and echo into a element that jQuery will point. Hope I'm being clear.
The problem is that I cannot figure out how I would call a timed event using delegate. Without much hope I've tried
$(document).on('ready()','#menu_item', function () {
$(this).load('ajax_countNewMsgs.php');
});
That didn't work.
I read many posts about js stop working after changes in the DOM, but, again, I couldn't figure out a way to solve that, nor found a similar question.
Any help or tips would be highly appreciated.
EDITED to change second php script's name
2nd EDIT - trying to make things clearer
I tried the way #carter suggested
$(document).ready(function(){
function unread(){
$.ajax({
url: 'ajax_countNewMsgs.php',
type: 'GET',
dataType: 'html',
success: function(response){
$('#menu_item').html(response);
},
error: function(response){
//no error handling at this time
}
});
}
setInterval(unread(), 1000);
});
the ajax_countNewMsgs.php script connects to the DB, fetch the unread messages, and echoes the number of unread messages.
If I try to apply the ajax reponse to another element, say, the <body> the results are as expected: at each 1 sec , the body html is changed. So the function is working.
As I said, none of my JS changes the #menu_item. Actuallly this element is part of another php scritp (menu.php) which is imported to the top of the page.
the page structure is this way:
<html>
<head>
some tags here
</head>
<body>
<?php include (php/menu.html); ?>this will include menu with the #menu_item element here
<div id='wrapper'>
<div id='data'>
here goes the data displayed in two ways (card and list like). Itens outside div wrapper are not being changed.
</div>
</div>
</body>
</html>
Even though the elemente is not being rewritten js cannot find it to update it's value.
It's not the full code, but I think you can see what is being done.
$(document).on('ready()','#menu_item', function () {
is an invalid event listener. If you wanted to be made aware of when the DOM is ready you should do this:
$(document).ready(function () {
However I don't think that is actually what you want. Your function unread will fire repeatedly but it attaches an event listener everytime. Instead if you want to make an ajax call every so many seconds after initial page load, you should do something like this (dataType property could be html, json, etc. pick your poison):
$(document).ready(function(){
function makeCall(){
$.ajax({
url: 'ajax_countNewMsgs.php',
type: 'GET',
dataType: 'html',
success: function(response){
//handle your response
},
error: function(response){
//handle your error
}
});
}
setInterval(makeCall, 1000);
});
remove that on your unread function:
$(document).ready(function(){
WHY?
The Document is already "ready" and this document state will only fired 1x - After that the "ready state" will never ever called. Use follwing syntax:
jQuery(function($){

have function work after div content is updated

I have a div with content in it. When the page loads, this function works fine. But when I update the div with content using javascript, this function fails to work.
Can anyone help me figure out what I should do to make this work?
$("textarea.indent").each(function(){
var indentWidth = $(this).siblings('[class=indent]').width();
if(indentWidth != null)
$(this).css('text-indent', (indentWidth+5)+'px');
});
Are you loading $("textarea.indent") dynamicly?
Jquery binds all events on document ready ie. when the page loads. That means that elements added after the page is done loading won't get bound to that event. To fix this you need to dynamicly bind your events as well. Like this..
$.ajax{
...
//Some ajax call
success: function(){
//Bind event
$("textarea.indent").each(function(){
var indentWidth = $(this).siblings('[class=indent]').width();
if(indentWidth != null)
$(this).css('text-indent', (indentWidth+5)+'px');
});
}
}
It doesn't have to be a ajax request thats add the elements, but my point still stands.

Is JavaScript (jQuery) and a handler run from memory or read every time?

My question is in two parts. One overall question and one relating to it with explicit code.
The general question:
Is Javascript read into the memory on load, and by this "installed", or is it read each time I do something? How are handlers installed? Once I .click() on an element, is then the handler in memory, including the function inside it? I once had trouble with a .mouseleave(), every time I left the element, the function was installed again and it was absolute chaos...how does this work with .click() then? Is the function then every time read again or does it stay in memory? The solution to the .mouseleave() was: here.
The specific question:
I just found out, that a .click() function I use here runs on first click once, on the second click twice, etc. ? You can see it, when you open the link, open the console and click on an image. Click on it to close it again, then click on ANY(!!) image and it loads as described. Weird, huh? Also it logs in the console the boolean for .data("installed") as true, although the switch to true comes only later in code?
Hope you can help me.
jQuery code:
$('.pfiles').data("installed", false);
if (!$('.pfiles').data("installed")) {
$('.pfiles img').click(function() {
var scroll = $('body').scrollTop(),
imgThis = $(this).attr('src'),
txtThis = $(this).attr('src').split('/')[2].split('.')[0] + ".txt",
$this = $(this),
bigImgH = $(this).height(),
bigImgW = $(this).width();
$('.progress').show();
console.log($('.pfiles').data("installed"));
$('.pfiles').fadeOut(200, function() {
$('.big').fadeIn(400);
$('.frame').height($('.big').height());
});
$.ajax({
type: 'GET',
url: imgThis,
dataType: 'HTML',
success: function(data) {
$('.big').empty().append("<img src='" + imgThis + "'/>");
if (bigImgW / bigImgH <= 1.3529411176) {
$('.big img').css({'height': '100%'});
} else {
$('.big img').css('width', '100%');
}
$('body').scrollTop(0);
$('.big img').click(function(){
$('.big').fadeOut(400, function() {
$('.pfiles').fadeIn(400);
$('body').scrollTop(scroll);
$('.big').empty();
$('.frame').height($('.incontent').height());
});
});
// progress();
}
});
});
$('.pfiles').data("installed", true);
}
"HTML" code
<?php
//Profile catch
$path = 'img/profile';
$profiles = scandir($path);
natsort($profiles);
$profiles = array_reverse($profiles);
$profiles = array_diff($profiles, array('.', '..', '.DS_Store', 'txt'));
?>
<div class="incontent" style="background:white">
<div class="progress">
<div class="bardiv">
<div class="bar"></div>
<p class="bartext text"></p>
</div>
</div>
<div class="big"></div>
<div class="pfiles">
<?php
foreach ($profiles as $pfiles) {
echo '<img onclick="" src="img/profile/'.$pfiles.'">';
}
?>
</div>
I already tried the same trick with the .data(), but it keeps console.logging on every click (even true!) and it is to no avail to the multiple XHR load... (On the server it is without the .data() switch!)
Javascript code in your page is parsed and run at the time the page loads and remains in memory in the browser while the page is active. As the user interacts with the page, any event handlers that your code might have installed are then called upon demand as those events happen.
Once you install a .click() handler, it remains in place for the lifetime of that DOM element or until you remove the click handler. Until you remove it, the click handler will get called every time the item is clicked on.
You should ONLY install a .click() handler for a given function one time. If you install it multiple times, it will be called multiple times when the item is clicked. If your click handler is being called more and more times each time you click it, then your code is apparently installing another click handler each time you click on it and you would need to modify your code not to do that.
To help more specifically, we'd need to know which click handler you're having an issue with and probably need to see some of the relevant HTML.
You can simplify your event handling code by having only one constant event handler for the .big img rather than constantly creating a new one. You can do that with delegated event handling like this:
$(".big").on("click", "img", function() {
$(".big").fadeOut(400, function() {
$('.pfiles').fadeIn(400);
$('body').scrollTop(scroll);
$('.big').empty();
$('.frame').height($('.incontent').height());
});
});
Put this code before any of the code you have in your question so it is initialized once and only once.
Here's a potential problem. At the very beginning of your block of code, you have this:
$('.pfiles').data("installed", false);
if (!$('.pfiles').data("installed")) {
That means that you will ALWAYS execute the if block, even if you previously set the data to true. You can just remove the first line because the default value for $('.pfiles').data("installed") will be falsey. You don't need to initialize it. Then, when this is called subsequent times, it will respect the fact that you've set it to true later in your code.

Call function inside iframe

im trying to do something here. I have a document which I set an array. Then, jquery takes this array and appends an iframe for each value:
<script>
var containers = new Array("test1", "test2");
</script>
This results is 2 iframes, identified by id with his name. Ok. perfect, working. Then, inside of each iframe, it calls a document. Inside this document, I have a function called play().
I am testing play() by returning an alert. Whenever I click on a button, it works:
$("#viewport .next").click(function(){
document.getElementById(containers[current]).contentWindow.play();
});
This works. Perfectly. But I it put this function to trigger on document ready, it doesnt works.
$(function() {
document.getElementById(containers[current]).contentWindow.play();
});
It returns to me:
Uncaught TypeError: Object [object Window] has no method 'play'
Whats am I doing wrong guys?
Thanks!
EDIT
Tried to apply onload on iframe. Didnt work.
var initialFrame = containers[qual];
initialFrame.onload = function() {
document.getElementById(initialFrame).contentWindow.play();
};
EDIT2
For some reason, it started working. Thanks!
Wait for the load event of the iframe first.
initialFrame.addEventListener("load", function() {
initialFrame.contentWindow.play();
});
You would generally listen for the iframe's load event like this:
$("#iframe").load(function(){
// iframe is loaded
});
... but I had trouble with this recently so I instead checked for the contents of the iframe over and over until it had loaded, like this:
function loadFrame() {
if($('body', $('#iframe').contents()).length != 1) {
setTimeout(loadFrame,500);
}
else {
// iframe is loaded
}
};
loadFrame();
Not sure if this is the best solution, but it works.

Categories

Resources