I am having an issue showing a hidden DIV after posting a form with Ajax. The setup is like so;
index.html - My content and form is loaded into a div from a resource page
<div id="inst_stud_resource_change_success" style="display: none;">
<div class="greenbox">
Deleted!
</div>
</div>
<div id="inst_stud_resources_getpackages">
<script type="text/javascript">
$("#inst_stud_resources_getpackages").fadeOut("slow").load('/inst/stud/resources/getpackages?inst_id={{ inst.id }}&stud_id={{ stud.id }}').fadeIn('slow');
</script>
</div>
/inst/stud/resources/getpackages.html - this page has the form, and the content needed for the DIV on index.html
The Jquery is used like so on getpackages.html;
<script type="text/javascript">
$(document).ready(function() {
$('#delete_package').on('submit', function(event) {
$.ajax({
data : {
stud_id : $('#stud_id').val(),
pck_id : $('#pck_id').val()
},
type : 'POST',
url : '{{ url_for('mod_inst_stud.delete_package2') }}'
})
.done(function(data) {
if (data.error) {
$('#errorAlert').text(data.error).show(); // IGNORE haven't gotten this far
$('#successAlert').hide(); // IGNORE haven't gotten this far
}
else {
$("#inst_stud_resources_getpackages").hide(); // doesn't seem to do anything
$('#inst_stud_resource_change_success').show(); // never shows the div on Index.html
$('#inst_stud_resource_change_success').delay(3200).hide(); // never hides, since it is never shown..
$("#inst_stud_resources_getpackages").load('/inst/stud/resources/getpackages?inst_id={{ inst.id }}&stud_id={{ stud.id }}').show(); // this seems to work since the div from index.html is updated with the new content from getpackages.html
}
});
event.preventDefault();
});
});
Any ideas what is going on? I'm not really that verse in web development, my background is more in python/flask, not Jquery/Ajax/CSS.
I found the solution..
else {
$("#inst_stud_resources_getpackages").hide();
$('#inst_stud_resource_change_success').fadeIn(1000);
$('#inst_stud_resource_change_success').delay(2600).fadeOut(3500);
$("#inst_stud_resources_getpackages").delay(7200).fadeIn().load('/inst/stud/resources/getpackages?inst_id={{ inst.id }}&stud_id={{ stud.id }}');
}
Apparently there is a queue in Jquery, however .load() will always go to the front. So It was negating the order of my calls. I had to move some lines around, and add an animation to .load() in order to delay it from loading right way. Seems to be working well now.
I want to make my post url to update the total click by registering it one unique click per browser everytime it is(the url) clicked, in simpler words, i want my total clicks to be unique.
I have found the method for url clicking here
http://jsfiddle.net/donejs/qYdwR/
//html
<!-- YOUR CODE HERE -->
<div id="content"></div>
<!-- PUT ANY TEMPLATES YOU NEED HERE -->
<script id="main-template" type="text/mustache">
<h2>CanJS component example</h2>
<click-counter></click-counter>
</script>
//javascript
var Component = can.Component.extend({
tag: 'click-counter',
template: '<a href="javascript://" can-click="updateCount">' +
'Click Me</a>' +
'<p id="msg">Clicked {{count}} times</p>',
scope: {
count: 0,
updateCount: function() {
this.attr('count', this.attr('count') + 1);
}
}
});
$('#content').html(can.view('main-template', {}));
The example of what i wish to do can be seen here pingje.org (article post).
Help me gurus, point me where to start, ive been trying to achieve this for days now, any time you took to answer my question is highly appreciated.
I am currently working on a website in which the home page displays the most recent 10 blog entries. When I scroll down, and when I reach almost the end of the last item on screen, another 10 blog entries are automatically loaded, and so on (this is the infinite scrolling feature).
If a user clicks on any blog entry, then he/she is taken to another page to display the details about that blog entry. When the user clicks the back button, he/she is taken to the home page that has the entries displayed.
Please note, the home page loads the data using Ajax.
Assume the following scenario:
A user goes to the site, and entries 1 to 10 are loaded (via Ajax).
The user scrolls down, and the next 10 entires, specifically entries 11 to 20 are loaded (via Ajax as well). Note that the page now has entires 1 to 20 displayed.
The user scrolls further down, and now entries 21 through 30 are loaded, for a total of 1 through 30 blog entries being displayed on the page.
The user clicks on entry 25, and the page for entry 25 is displayed.
The user clicks the back button, and all items, 1 through 30 are displayed.
Now, if the users uses FireFox, Opera, or Safari, and when that user performs step 5 (i.e, clicks the back button to go back to the home page) then the blog entries are just displayed on screen, and without being re-loaded. However using IE and on Chrome, when the user clicks on the back button, the page is reloaded, and only items 1 through 10 are displayed.
I do not like the IE and Chrome behaviour. The user should see items 1 though 30. How can I ensure all browsers behave like FireFox?
Thanks.
Update
Here is the code I am using
First, hers is my html
<html>
<body>
<section id="content">
<section id="articles">
<!-- This section is filled by jQuery/Ajax -->
</section>
<section id="loading-spinner">
<img src="ajax-loader.gif" />
</section>
</section>
</body>
</html>
And here is my jQuery
/**
*
* This file uses a bunch of programming concepts, but the most important one is ensuring ajax calls run as a critical section
* ... (this means if ajax is already called, then another instance of JavaScript cannot get into the critical section)
*
* .. For more details, please read: http://stackoverflow.com/questions/22150960/critical-section-in-javascript-or-jquery
*
*/
load_more_posts = function () {
// If we almost reach the bottom of the document, then load more posts
if ( jQuery(window).scrollTop() >= jQuery(document).height() - jQuery(window).height() - 300) {
// If the value of the promise is not pending, then we can call the load_posts function (the load_posts function will change the status to pending when it is executing the ajax request)
if (ajax_status.state() !== "pending") {
load_posts();
}
}
};
function load_posts() {
ajax_status = jQuery.ajax({
type: 'post',
dataType: 'json',
beforeSend: function(xhr) {
if(jQuery.data(document.body, 'load_page') == false) {
xhr.abort();
}
else {
// Show the spinner
jQuery('#loading-spinner').visible();
}
},
url: '../link/to/get_poasts.php',
data: {
action: 'load_posts',
js_query_data: query_data,
js_page: jQuery.data(document.body, 'page_to_load')
},
success: function (response) {
if (response.isSuccessful) {
var number_of_post_items = response.posts_array.length;
for (var i = 0; i < number_of_post_items; i++) {
// If the item is already returned from the database and posted. then we skip it, otherwise, keep insert a new record
if (jQuery('#articles').find('#article-' + response.posts_array[i].post_id).length == 0) {
// Add 'article'
jQuery('#articles').append('<article id="article-' + response.posts_array[i].post_id + '"></article>');
// More code here to add details about each article, such as title, excerpt...etc.
}
}
// Increase the value of the page to load by 1, and save it.
page = jQuery.data(document.body, "page_to_load");
page = page + 1;
jQuery.data(document.body, "page_to_load", page);
jQuery(window).on('scroll', load_more_posts);
}
else {
// Display error message
jQuery('#articles').append('<div>' + response.message + '</div>');
// Make sure no further AJAX requests are made
jQuery.data(document.body, 'load_page', false);
}
}
}).always(function() {
// Hide the spinner
jQuery('#loading-spinner').invisible();
});
return ajax_status;
}
// Create a new promise. This will be used to ensure that no two calls hit the critical section at the same time
// ... (the critical section in this case is the time when we retrieve data from the database. We only want one call at a time)
var ajax_status = new jQuery.Deferred();
jQuery(document).ready(function() {
// Hide the loading spinner first
jQuery('#loading-spinner').invisible();
// We resolve the promise, making sure it is ready (this is an intial state)
ajax_status.resolve();
// Initial values that are used
jQuery.data(document.body, 'page_to_load', 1);
// This parameter is used to stop loading pages when no more items are available to be displayed
jQuery.data(document.body, 'load_page', true);
// Initial loading of poasts
load_posts();
// Enable on scrolling to load more pasts (to allow infinite scrolling)
jQuery(window).on('scroll', load_more_posts);
});
You'll find some information about how it works in the "good" browsers in this answer:
Is there a cross-browser onload event when clicking the back button?
Here you'll find a way to emulate it in IE:
Differences in Internet Explorer and Firefox when dynamically loading content then going forward and back
Not quite sure why it doesn't work in Chrome though.
Just so everyone knows, here is the solution I came up with that is consistent in all browsers. Unfortunately this solution requires a reloead/refresh button to reload the data. I tried to avoid that but could not. Until both IE and Chrome tackle the bfcache issue, I will stick to this solution.
First, here is the new html
<html>
<body>
<section id="content">
<a id="refresh">
<img src="link/to/refresh.png" title="Refresh" alt="refresh" />
</a>
<section id="articles">
<!-- This section is filled by jQuery/Ajax -->
</section>
<section id="loading-spinner">
<img src="ajax-loader.gif" />
</section>
</section>
</body>
</html>
And this is the javascript
/**
*
* This file uses a bunch of programming concepts, but the most important one is ensuring ajax calls run as a critical section
* ... (this means if ajax is already called, then another instance of JavaScript cannot get into the critical section)
*
* .. For more details, please read: http://stackoverflow.com/questions/22150960/critical-section-in-javascript-or-jquery
*
*/
load_more_posts = function () {
// If we almost reach the bottom of the document, then load more posts
if ( jQuery(window).scrollTop() >= jQuery(document).height() - jQuery(window).height() - 300) {
// If the value of the promise is not pending, then we can call the load_posts function (the load_posts function will change the status to pending when it is executing the ajax request)
if (ajax_status.state() !== "pending") {
load_posts();
}
}
};
function load_posts() {
ajax_status = jQuery.ajax({
type: 'post',
dataType: 'json',
beforeSend: function(xhr) {
if(jQuery.data(document.body, 'load_page') == false) {
xhr.abort();
}
else {
// Show the spinner
jQuery('#loading-spinner').visible();
}
},
url: '../link/to/get_poasts.php',
data: {
action: 'load_posts',
js_query_data: query_data,
js_page: sessionStorage.getItem("page_to_load")
},
success: function (response) {
if (response.isSuccessful) {
var number_of_post_items = response.posts_array.length;
for (var i = 0; i < number_of_post_items; i++) {
// If the item is already returned from the database and posted. then we skip it, otherwise, keep insert a new record
if (jQuery('#articles').find('#article-' + response.posts_array[i].post_id).length == 0) {
// Add 'article'
jQuery('#articles').append('<article id="article-' + response.posts_array[i].post_id + '"></article>');
// More code here to add details about each article, such as title, excerpt...etc.
var history_session = get_history_session_name();
var history = sessionStorage.getItem(history_session);
var article_content = jQuery('#articles').find('#aarticle-' + response.posts_array[i].post_id)[0].outerHTML;
sessionStorage.setItem(history_session, history + article_content);
}
}
// Increase the value of the page to load by 1, and save it.
page = parseInt(sessionStorage.getItem("page_to_load"));
page = page + 1;
sessionStorage.setItem("page_to_load", page);
jQuery(window).on('scroll', load_more_posts);
}
else {
// Display error message
jQuery('#articles').append('<div>' + response.message + '</div>');
// Make sure no further AJAX requests are made
jQuery.data(document.body, 'load_page', false);
}
}
}).always(function() {
// Hide the spinner
jQuery('#loading-spinner').invisible();
});
return ajax_status;
}
function get_history_session_name () {
session_name = 'history___' + escape(location.href);
return session_name;
}
// Create a new promise. This will be used to ensure that no two calls hit the critical section at the same time
// ... (the critical section in this case is the time when we retrieve data from the database. We only want one call at a time)
var ajax_status = new jQuery.Deferred();
jQuery(document).ready(function() {
// Hide the loading spinner first
jQuery('#loading-spinner').invisible();
// We resolve the promise, making sure it is ready (this is an intial state)
ajax_status.resolve();
// This parameter is used to stop loading pages when no more items are available to be displayed
jQuery.data(document.body, 'load_page', true);
// Get the name of the history session
var history_session = get_history_session_name();
if (sessionStorage.getItem(history_session) === null) {
// Set the history session storage
sessionStorage.setItem(history_session, "");
// Initial values that are used
sessionStorage.setItem("page_to_load", 1);
// Load the posts
load_posts();
}
// Load from history when the back button is clicked
else {
jQuery('#articles').append(sessionStorage.getItem(history_session));
}
// Enable on scrolling to load more pasts (to allow infinite scrolling)
jQuery(window).on('scroll', load_more_posts);
// Reload data when the refresh button is clicked
// ... We are using a refresh button because if we go to a page that already had history, ...
// ... and even though we went to that page without using the back button (i.e, via links or directly via the url), ...
// ... then the history session will be displayed. ...
// ... Therefore a reload button is needed to overcome this problem if you like to reload data
jQuery("#refresh").click(function () {
// Reset/clear the articles section first
jQuery('#articles').html("");
// reset the 'load_page' variable
jQuery.data(document.body, 'load_page', true);
// Reset/clear the history session storage
sessionStorage.setItem(history_session, "");
// Start with loading page 1
sessionStorage.setItem("page_to_load", 1);
// Load the posts
load_posts();
});
});
Hope this helps.
I have this code, it basically changes the word 'article' to 'articles' if the value is '0' or more than '1'. But the word only changes when the page is refreshed. Is it possible to automaticaly re-run the code at the same moment the value (quantity) changes?
<span id="quantity" class="simpleCart_quantity"></span> gets it's value from an external file, it is always a number (like 0, 1, 2, 3, etc.)
<span id="quantity" class="simpleCart_quantity"></span>
<span id="quantityText"></span>
<script type="text/javascript">
$(window).load(function()
{
var quantity = document.getElementById("quantity"),
quantityText = document.getElementById("quantityText");
if (parseInt(quantity.innerHTML, 10) === 1) {
quantityText.innerHTML = "article";
} else {
quantityText.innerHTML = "articles";
}
});
</script>
Thanks in advance!
Yes it's possible.
The direct and dirty way is to poll the server for changes at an interval. make a timer function that calls an ajax function that checks to see if the article count has changed.
something like:
setInterval(function(){
$.ajax({
url:"checkchanges.php",
dataType:"json",
type:'GET',
.success(function(data){
if (data.articlecount>1){ //pseudocode, it depends on how you get your data
$("#quantity").innerHTML="articles";
}
})
});
},3000);
Another method is to use a framework like meteor that wires the checking up for you.
I've developed a webpage showing some statistics.
These statistics are refreshed periodically by AJAX requests using mootools 1.4.5.
Here ist the basic code:
<script type="text/javascript">
var statisticRequest = new Request.HTML({
url: theURL,
noCache: true,
onSuccess: function(responseTree, responseElements, responseHTML, responseJavaScript) {
$(responseTree[0]).replaces($('statisticContainer'))
}
})
function getCurrentStatistics() {
statisticRequest.get()
}
window.addEvent('domready', function(){
getCurrentStatistics.periodical(2000)
});
</script>
On FF all works fine but the IE9 continuously allocates memory until the machine is nearly freezed.
It looks like the garbage collector didn't remove the old DOM elements.
Using sIEve, I can see the increasing number of DOM elememts and the resulting memory usage.
What can I do to force the IE to remove the unused elements?
Edit:
Using destroy() as shown below will slow down the memory consumption but will not stop it completely. Removing Request.HTML had no further effect.
<script type="text/javascript">
var statisticRequest = new Request({
url: theURL,
noCache: true,
onSuccess: function(responseText, responseXML) {
var newStatistic = Elements.from(responseText)
var oldStatistic = $('statisticContainer')
newStatistic.replaces(oldStatistic)
oldStatistic.destroy()
}
})
function getCurrentStatistics() {
statisticRequest.get()
}
window.addEvent('domready', function(){
getCurrentStatistics.periodical(2000)
});
</script>
yes you can. look at the code for this:
https://github.com/mootools/mootools-core/blob/master/Source/Element/Element.js#L743-747
it will just replace it in the dom. it won't really do much in terms of GC - the old element still 'exists' - in case you want to re-attach it.
http://jsfiddle.net/rE3JH/
var foo = document.id('foo');
new Element('div').replaces(foo);
console.log(foo); // still an element, though not in the dom
call foo.destroy(); to properly GC - see https://github.com/mootools/mootools-core/blob/master/Source/Element/Element.js#L802-807
alternatively, update the parent of staticContainer - applying a change to innerHTML direct. also, keep in mind .empty() will dispose child nodes and not destroy them - for periodical stuff like yours, you need to be thorough as it can avalanche over time.
I've been playing about with this for a while. I think you're better to use something like mootools. It's well tested and is pretty small. It also gives you lots of extra features that are all cross browser compatible and don't need extensve testing.
I've run the following code for over two hours with no memory leaks. Hope it helps either the questioner or someone else searching stack overflow: First the index.html file:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>Untitled Document</title>
<style>
img.slide{
border:1px solid black;
}
</style>
<script type="text/javascript" src="mootools/mootoolsCore.js">
</script>
<script type="text/javascript" src="mootools/mootoolsMore.js">
</script>
<script type="text/javascript">
function data(){
this.who="alan";
this.pageHolder=1;
this.lastPage = 4;
this.count = 0;
}
var newData = new data();
function changePage(newData,dirn){
newData.dirn = dirn;
saveData(newData);
}
function saveData(newData) {
//alert("reached save data");
var dataJSON = JSON.encode (newData);
var request = new Request.JSON({
method: 'post',
url: 'forwardDataJson.php',
data: {
json: dataJSON
},
onComplete: function(jsonObj) {
newData.pageHolder = jsonObj.pageHolder;
newData.count = jsonObj.count;
$("picHolder").set('html','<img class="slide" src ="OpeningSlide/Slide'+jsonObj.pageHolder+'.jpg"/>');
$("alertBox").set('html',jsonObj.alertGiven);
$("countme").set('html',jsonObj.count);
}
}).send();
};
function getCurrentStatistics() {
saveData(newData);
}
window.addEvent('domready', function(){
getCurrentStatistics.periodical(2000)
});
</script>
</head>
<body>
<div id="alertBox"></div>
<button type="button" onmousedown="changePage(newData,'backward')"/>backward</button>
<button type="button" onmousedown="changePage(newData,'forward')">forward</button>
<div id="picHolder"><img class="slide" src ="OpeningSlide/Slide1.jpg"/></div>
<div id="countme">0</div>
</body>
</html>
This looks for a series of images (Slide1.jpg, Slid2.jpg etc) and then displays them on the page. It checks every two seconds for a new bit of info and gets a counter number. Clicking forward or back makes the slides run through every 2 seconds. Not very exciting but it demonstrates the princilple of using AJAX and a server poll with Mootools.
You also need a server side script. Which in this case is:
<?php
if(get_magic_quotes_gpc()){
$test = stripslashes($_POST['json']);
}else{
$test = $_POST['json'];
}
$obj = json_decode($test);
$direction = $obj->{'dirn'};
$counter = $obj->{'count'};
++$counter;
$obj->{'count'} = $counter;
switch ($direction) {
case "forward":
if($obj->{'pageHolder'} < $obj->{'lastPage'}){
++$obj->{'pageHolder'} ;
}
break;
case "backward":
if($obj->{'pageHolder'} >1){
--$obj->{'pageHolder'} ;
}
break;
}
$reply = json_encode($obj);
echo $reply;
?>
You'll notice that I've used JSON for passing an object to and from the server. This is just for ease of coding. If you've never used it before it's the way to go (in my opinion at least) since it's straightforward to use once you get your head around it.
This example should work as is. You simply need a directory called OpeningSlide which should contain your jpg slides/images and of course the mootools libs.
Hope this helps
Incidently if you're wondering about the first few lines of the php code it's there to sort out issues with JSON and magic quotes. It adjusts for magic quotes being on or off at the server. You can remove it if you know your server setting.