I have a timer every 20 seconds using setInterval, it uses jQuery's ajax function load() to set the toparticles div with the information from another URL on site. Once that load is successful, it performs a jQuery highlight effect on the first article in the toparticles div. All articles on both places are held in their own seperate table, so I use #toparticles table:first.
I only want to perform the loading into the toparticles div, AND the animation if the first article is not the same.
So the concept is as follows:
Every 20 seconds:
Check this url, if the first table isn't equal to the first table of the page you're on, reload the entire div with that url's information, then perform highlight animation.
My current code:
setInterval(function() {
$("#toparticles").load("http://myarticles/feed/of/top/articles", function()
{
$("#toparticles table:first").effect("highlight", {color:"#f2f37f"}, 1000);});
}, 20000);
Thanks if you can provide any help.
A naive approach (best would be to have some sort of id) is
setInterval(function() {
var first_html = $("#toparticles table:first").text();
$("#toparticles").load("http://myarticles/feed/of/top/articles", function()
{
if ( first_html == $("#toparticles table:first").text() )
{
$("#toparticles table:first").effect("highlight", {color:"#f2f37f"}, 1000);
}
});
}, 20000);
It stores the text of the first table in a variable before the ajax call, and then compares it to the new first table. (i only check for text, you could change that to .html() to check for the whole html structure if you want that level of detail)
You could probably change your request to use jQuery.ajax(). It has an "ifModified" option. From the docs:
ifModifiedBoolean
Default: false
Allow the request to be successful only if the response has changed since the last request. This is done by checking the Last-Modified header. Default value is false, ignoring the header. In jQuery 1.4 this technique also checks the 'etag' specified by the server to catch unmodified data.
jQuery.ajax() documentation
Also, I haven't checked myself but it seems as though they have an example that uses the .load() function's call back:
$("#success").load("/not-here.php", function(response, status, xhr) {
if (status == "error") {
var msg = "Sorry but there was an error: ";
$("#error").html(msg + xhr.status + " " + xhr.statusText);
}
});
Related
I am implementing infinite-scrolling in AngularJs. The below function gets called on a successful AJAX call, that takes place when:
The user scrolls to the end of screen.
The selects some filters, and hits the "Search" button.
In the first case, the data fetched from the AJAX call is appended to the existing list. In the second case, I intend to completely empty any existing data in the list, and display the new data. Here is my code to do that:
$scope.successCallBack=function(data){
$('#spn-model-buffering-image').hide(); //hide the loading spinner icon
if($scope.providersList === null) {
$scope.providersList = []; /* init if null */
}
if($scope.scrolled === 'true'){
/*If it was an scroll-end event, then simply append the new data to the existing one*/
Array.prototype.push.apply($scope.providersList, JSON.parse(data.serviceproviderlist)); //push the new data to the existing list
}
else{
/*If the user clicks on "Search Providers" button, then new data are fetched, and occupy the entire list view*/
$scope.providersList=[];
$scope.providersList=JSON.parse(data.serviceproviderlist);
}
viewToBeDisplayed(LIST_VIEW);
$scope.scrolled='true';
}
So, after a successful AJAX call, the above method is called. It hides the buffering image, and checks if the variable named scrolled is set to true. If yes, then it means that the event is not button-click, but the user has reached the end of screen, and hence, data have to be appended. Else, the user has clicked on the button, and hence, data have to be displayed fresh.
This is the function that gets called on button-click event:
$scope.getFilteredData=function(){
$scope.scrolled='false';
$scope.getMoreData();
}
My problem: View does not get updated. The AJAX call returns data as JSON. In the scroll-event, data are fetched and appended to the existing list, as expected.
Can someone suggest me what I might be doing wrong? Thanks!
Here is the AJAX call code:
$scope.getMoreData=function(){
$('#spn-model-buffering-image1').show(); //while the data are being fetched, display the loading spinner
$scope.updateAjaxData(); //update AJAX data: pagekey, category, and reftag
var url=$scope.getURL();
A.ajax(url, {
method: 'post',
params: AJAX_DATA,
success: function(data, s, x) {
$scope.successCallBack(data);
},
error: function(xhr, statusText, errorThrown) {
$scope.errorCallback(xhr);
}
});
}
Try to use the http provided by AngularJS.
$http.get('/someUrl', config).then(successCallback, errorCallback);
This is good practice and it will probably solve your problem of not updating the view.
My website structure is as follows:
public_html/
- index.php
- students.php
The user loads the site (index.php) which contains a button. When this button is clicked AJAX is used to load "students.php" and it is displayed to the user (As if they just went to a different page seamlessly). When doing so the following JavaScript is run:
var state = {'Page' : 'Students'};
history.pushState(state, null, "students");
This adds a state to the browsers history and causes the browsers URL to display "example.com/students" instead of "example.com". However if a user was to refresh at this point, nothing would load (404 Not Found) due to the folder "students" not actually existing.
My question is, how can I get the users browser to actually display "index.php" and automatically take them to the students page. In other words, the user refreshes "example.com/students" and what actually happens is the user is taken to the index.php file and the AJAX automatically takes them to the students page (As though they actually refreshed the page)
Note: I am aware I can pass null to the url parameter in "pushState()" however this URL behaviour is desired as it would allow users to quickly jump to a page (If I can get it working)
The full code to show the students page via AJAX is as follows:
/**
* Display students screen.
*/
function displayStudents(createState) {
if(typeof(createState)==='undefined') {
createState = true;
}
$("#container").css("width", $( window ).width());
$("#container").css("position", "fixed");
$("#container").animate({marginLeft: "-100%"}, ANIMATION_SPEED);
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
$("#container").css("margin-left", "100%");
$("#container").html(xmlhttp.responseText);
$("#container").animate({marginLeft: "0"}, ANIMATION_SPEED, null, function reset() {
$("#container").css("width", "100%");
$("#container").css("position", "relative");
});
if(createState) {
var state = {'Page' : 'Students'};
history.pushState(state, null, "students");
}
}
};
xmlhttp.open("GET", "students.php", true);
setTimeout(function() { xmlhttp.send(); }, ANIMATION_SPEED);
}
Most of the code here is for animation.
In other words, the user refreshes "example.com/students" and what actually happens is the user is taken to the index.php file and the AJAX automatically takes them to the students page (As though they actually refreshed the page)
The point of pushState is that when you use JavaScript to transform the state of the page, you provide a URL which the server can use to deliver some HTML that will provide the page in that state.
If you are always going to serve up the homepage and then transform it with JavaScript, then just use hashbangs. pushState is entirely the wrong tool for the job.
If you were to use pushState, then a pseudocode implementation of a possible approach would be along the lines of:
GET data needed for the page
IF `Accept` header prefers `application/json`
Output `Content-Type: application/json` header
Output data in JSON format
ELSE
Output `Content-Type: text/html` header
Pass data through the template for the page
Output template as HTML
And you would use students.php in the URL instead of students (or you would make students resolve to the PHP code you wanted to run instead).
Since you are using raw XMLHttpRequest, you will need to use setRequestHeader to set the Accept header. You are using jQuery though, so you could just use $.ajax and pass it dataType: "json".
I have a simple social networking site with chat functionality. I have used $.post a lot in multiple pages.
The code works well on all pages except message.php where the user message is posted and fetched multiple times with
$.post
(used to work well on local server).
When the messaging between users occur simulateously, the website stops to respond. On reload, the server goes down and ERR_EMPTY_RESPONSE message is shown. The website again comes into operation after a couple of minutes. To what I learnt, this is happening on pages that use $.post frequently.
To summarize the situation, I have created a live test page. An ERR_EMPTY_RESPONSE occurs when input is given continuously for some seconds.
The page contents:
a.php
<script>
$(document).ready(function(e) {
$(".abc").keyup(function(){
var a = $(this).val();
$(".showoff").text("wait..");
$.post('bbs.php',{a:a},function(abc){
$(".showoff").html(abc);
});
});});
</script>
<input type="textbox" class="abc">
<div class="showoff">Type to Change Me!</div>
bbs.php
<?php
echo $_POST['a'];
?>
I am hitting my head hard on the wall for a week. So, Please help me with this problem.
Thanks in Advance.
Sorry for my lame English as well.
As you appear to want an autocomplete type setup, use a timer. Reset it on each keypress and after a delay send your post. In this example it will send 3 seconds after the last keypress.
$(document).ready(function(e) {
var timer;
$(".abc").keyup(function() {
var $input= $(this);
// Start timer
clearTimeout(timer);
// Start a new 3 second timer
timer = setTimeout(function() {
// Once the
var a = $input.val();
$(".showoff").text("wait..");
$.post('bbs.php', {
a: a
}, function(abc) {
$(".showoff").html(abc);
});
}, 3000);
});
});
JSFiddle: https://jsfiddle.net/TrueBlueAussie/Locpnk35/
This will avoid overloading your server as no more than 1 request every 3 seconds can come from the same user. If the response is slower than 3 seconds you may also need to disable the key handler while an Ajax request is in progress.
Simplest answer would be you allow your server to be spammed to the point that it stops responding (yet still recieving new connections). If the connections are not closed(resolved) in time you will also hit limitation of concurrent browser connections to domain (which I think is really happening - browser blocking you in making those request).
You either switch to sockets, or send text to server on set interval of time. Alternatively you dont allow next post, till previous is resolved.
Instead of allowing your server to be spammed, you can remove the handler before the first post and set it back again when the post returns.
$(document).ready(function(e) {
var $abc = $('.abc'); //good idea to cache those jQuery selectors!
function abcPost() {
$abc.off('keyup', abcPost)
var a = $(this).val();
$(".showoff").text("wait..");
$.post('bbs.php', {
a: a
},
function(abc) {
$(".showoff").html(abc);
$abc.on('keyup', abcPost)
});
}
$abc.on('keyup', abcPost);
});
Ajax syncronous: Make the ajax call syncronous. This will stop its thread untill the response is back, easy to implement but comes with the downside that the user cannot type anymore untill request is solved
$.ajax({
url: 'bbs.php',
data: {a:a},
success: function(abc){
$(".showoff").html(abc);
},
async: false
});
Global variable check: make a global variable that checks the state of previous request and doesn't allow future ones until it is resolved:
var waiting=false;
$(".abc").keyup(function(){
if(!waiting){
waiting = true;
// code
$.post('bbs.php',{a:a},function(abc){
$(".showoff").html(abc);
waiting=false;
});
}
});
This is good.
var waiting=false;
$(".abc").keyup(function(){
if(!waiting){
waiting = true;
// code
$.post('bbs.php',{a:a},function(abc){
$(".showoff").html(abc);
waiting=false;
});
}
});
I was wondering if there is any proper way to prevent ajax request from delivering random 404/500 Errors when calling many of them at the same time (synchronous or asynchronous)
e.g. a simple html table with some rows and columns to show a list of 500-800 people with some data
Way to go:
Getting ppl by selection (html form with organizational units) from the backend and write the resultlist in the first columns of the table
getting events of each person by his/her personId (result of the first request)
getting attributes of each person
getting roles for each person
getting calculated stuff from the backend for each person depending on their individual attributes,roles and events.
pseudocode:
function createTableData(){
var selected;
var personIds;
//get personIds by selection and write them into table
object.executeJSONRequest(...,
{ _ts: new Date().getTime(),
input: selected
},function(data) {
// write result into table
// fill resourceIds with result param
},..);
getEvents(personIds);
getAttribtues(personIds);
getRoles(personIds);
calculateStuff(personIds);
}
function getEvents(personIds){
object.executeGetRequest('...',
{ _ts: new Date().getTime(),
ppl: personIds
},function(data) {
//add result to table
}
}
function getAttributes(personIds){...} //and so on..
if i call all these methods in a row i sometimes get random errors sometimes while loading attributes, sometimes on loading roles, sometimes it all works fine.
if i call them nested in each ajax success block like
function createTableData(){
object.executeJSONRequest(...
{ _ts: new Date().getTime(),
input: selected
},function(data) {
getEvents(..);
});
}
function getEvents(..){
object.executeGETRequest(...
{ _ts: new Date().getTime(),
input: selected
},function(data) {
getAttributes(..);
});
}
function getAttributes(..){ ...,function(data){ getRole(..)}); and so on
it all works fine. If i try a solution with something like
document.ajaxStart/Stop(function(){ //if table columns i expected are filled do next}
i have to check all neccessary table colums if they are already filled with data or not.
Is there any really proper solution i just dind't think about?
(jQuery Version 1.2 /IE V7-8 ^^)
"If possible update jquery and ie versions"
First of all why are you calling multiple server calls in a single process.
It's better if you combine all the process into a single request and response cycle, do the required handling of data in java code.Don't go forth and back with request and response.
Any way you can use the jquery ajax which returns the status of the ajax call.
$.post("url",function(result,status){{
if(status == success){
//continue....
}else{
alert("Sorry something went wrong");
}
}});
Like this check all the request weather it successfully finished.
I strongly recommend you consider combining all the ajax calls into a single request.
How to implement a periodical save of a form in the background? Same kinda thing that gmail does.
setInterval(function(){
var form = $('#my-form-id');
var method = form.attr('method').toLowerCase(); // "get" or "post"
var action = form.attr('action'); // url to submit to
$[method](action, form.serialize(), function(data){
// Do something with the server response data
// Or at least let the user know it saved
});
},10000); // do it every 10 seconds
If you don't want to use the method of the form, but always want to use 'post', then use:
$.post(action, form.serialize(), ... );
And, if you want to supply your own action for the autosave that is different from the action for the actual save:
$.post("/autosave/comments", form.serialize(), ... );
You would need a timed loop on the client side that would save the form every x seconds/minutes. A crude way of doing this would be to have a setTimeout javascript function that collects the form's field values and updates the model via an update (PUT in Rails' case) AJAX request.
Example
Here's a crude way of doing it (i.e. there might be a better way):
// repeat every 10 seconds
var repeatTime = 10 * 1000;
function updateModel(){
// get field values (using jQuery, etc.)
// make ajax request using these field values
//(make sure put parameters match model attribute names)
console.log('updated');
setTimeout(updateModel, repeatTime); // start call over again
}
setTimeout(updateModel, repeatTime);
I included the console.log so that you can test this out in Firebug right now and see that the updateModel executes every 10 seconds. I would recommend using jQuery to generate the PUT AJAX requests.
Why not do this purely on the client, using a local database (or whatever)? That should reduce complexity, server load and bandwidth usage.
Permanent or per-session storage -- whatever's appropriate -- and you can save after every keystroke: no need for setTimeout().
Sisyphus.js: Gmail-like client-side drafts and bit more. Plugin developed to save html forms data to LocalStorage to restore them after browser crashes, tabs closings and other disasters.
http://sisyphus-js.herokuapp.com
Smashing Magazine article: http://coding.smashingmagazine.com/2011/12/05/sisyphus-js-client-side-drafts-and-more/
Version that works without jquery:
function urlencodeFormData(fd) {
var s = '';
function encode(s) { return encodeURIComponent(s).replace(/%20/g,'+'); }
for (var pair of fd.entries()) {
if(typeof pair[1]=='string') {
s += (s?'&':'') + encode(pair[0])+'='+encode(pair[1]);
}
}
return s;
}
setInterval(function() {
var form = document.getElementById('my-form-id');
var request = new XMLHttpRequest();
request.open(form.method, form.action);
request.setRequestHeader('Content-Type','application/x-www-form-urlencoded')
request.send(urlencodeFormData(new FormData(form)));
}, 10000);
If you need to do something with the server response see this post: https://blog.garstasio.com/you-dont-need-jquery/ajax/#posting