I'm trying to put together a script that will add to the concept of load, and extend it outward in a fashion that load can be called to multiple pages, in search of instances of a div.
For example, consider the code below:
<div class="loadStuffHere">
</div>
$('.loadStuffHere').load('/wiki.htm .posts');
So, the code above works just fine, but I'm not sure how to get it to search more than one page at a time.
The second page I would need to search in this case would be: /wiki.htm?b=1&pageindex=2. After the script searches the first page, then it would need to search the second. After the second page is searched, then the script would need to first auto increment the number 2, and change it to a three, and search that page, and then continue to do so, until it hits a page that doesn't exist, and then return false and end it's execution. So the search and load process would consist of this:
/wiki.htm
/wiki.htm?b=1&pageindex=2
/wiki.htm?b=1&pageindex=3
/wiki.htm?b=1&pageindex=4
/wiki.htm?b=1&pageindex=5
/wiki.htm?b=1&pageindex=6
And it would continue in that manor, until it hits a page that doesn't exist yet, as this is a pagination system.
Is this something that can be done, and if so, what would it look like?
Any help is very appreciated!
P.s. If you are thinking I'm likely attempting something that would be easier achieved with some server side coding, you are right. I don't have access to it however, regretfully.
You could do something like:
function loadWikiPosts(page_index) {
if (page_index != null) { url += '?b=1&pageIndex='+page_index; }
else { page_index = 1; /* for next time if this one fails */ }
url += ' .posts'; // to grab just the posts
// Send the AJAX request
$('.loadStuffHere').load(url, function(response, status, request) {
if (status == "error") { console.log(response); throw "Load returned an error"; }
if ($('.loadStuffHere').find('.posts').length == 0) {
page_index++;
loadWikiPosts(page_index);
}
});
}
try {
loadWikiPosts();
} catch (exception) {
// do something w/the exception message
}
Create an array with all your results, using the following code:
JavaScript/jQuery
var linkArray=["/wiki.htm",
"/wiki.htm?b=1&pageindex=2",
"/wiki.htm?b=1&pageindex=3",
"/wiki.htm?b=1&pageindex=4",
"/wiki.htm?b=1&pageindex=5",
"/wiki.htm?b=1&pageindex=6"];
for (var i in linkArray)
{
var content = "";
$('.loadStuffHere').append($(content).load(linkArray[i]+' .posts'));
}
The code above was not tested.
Related
$(function() {
var $items = $('#items');
$.ajax({
type: "GET",
url: 'some-url',
data: {},
success: function(items) {
$.each(items, function(i, item){
item_polys.push(item.polygon);
$items.append(`<a href="somepage.html" onclick="localStorage.setItem('item', '${item.item_id}'); localStorage.setItem('item_poly', '${item.polygon}')";>${item.item_id}</a>`);
});
localStorage.setItem('item_polys', JSON.stringify(item_polys));
},
// Error handling
error: function (error) {
console.log(`Error ${error}`);
},
});
I need 'item_polys' to be saved into local storage before my corresponding html page loads. I would also settle for a way to reload the html page just one time each time after it loads, so that it will populate correctly. Thanks (and sorry if this has been answered already, I couldn't quite find what I was looking for when I searched)
Since you want the ajax request to occur when the user is on the exact same page that the populated elements will be in, I think the only good way of doing this would be to create or display the elements of the page dynamically. (This might be as simple as toggling a display: none on and off, but it depends on what the page is like and what you want.)
So, make a function like populatePage that shows the page, where the default state of the page is a loading screen (or blank, or whatever you want the user to see when the request is in progress). Maybe something like
const populatePage = () => {
const items = JSON.parse(localStorage.items);
for (const item of items) {
$items.append(`<a href="somepage.html" onclick="localStorage.setItem('item', '${item.item_id}'); localStorage.setItem('item_poly', '${item.polygon}')";>${item.item_id}</a>`);
}
$('main').show();
};
where main is the container you want to show when things are ready, and that has styling that hides it by default. Then:
On pageload, check if the item exists in storage. If so, use it, and call populatePage immediately. Otherwise, have the page keep showing the loading banner or blank screen, make the ajax request, and call populatePage when it's finished.
$.ajax({
// ...
success: function (items) {
localStorage.items = JSON.stringify(items);
populatePage();
I've been searching for a way to take the user to a random page when they press a button with JavaScript/jQuery. Everything I've seen has all the pages in an array, and then uses a script to randomly choose an index.
Would it be possible to do something like this without adding all the pages into an array. I don't want to sit there and add every page/image in the directory to a large array and then have the script run, I just want it to go through the appache directory list and grab something by itself.
Can this be done? I know we're supposed to include code we have so far, but this is more of a conceptual question.
Use ajax to get your link:
$.ajax({
method: "GET",
url: "/getRandomLink", // I don't know which server side language you're using, I presume its PHP
dataType: "text", // text will be enought if it only returns a link
success: function(link) {
window.location.href = link;
}
});
Then put this inside an event of your choice. Nice and easy.
UPDATE
The return of your service must be a string with the link. I'm suposing you're using PHP, so will be something like:
<?php
$randomLink = "";// Code to get the random link here
echo $randomLink; // e.g.: http://www.google.com/
?>
Something needs to provide the list of files for your script to randomly choose from. That's going to be either a pregenerated array or an ajax request.
These would work:
Apache directory listing as json
how to get file listing using jquery ajax
...but for your purposes it would make more sense for your server side script to just return a single randomly selected file, instead of using bandwidth for the whole list only for the client to discard all but one.
Edit to reflect the comment given by the OP. Pardon the jQuery.
Assuming the directory index you've got is a standard Apache Auto-Index page:
//jQuery doc.ready, because I'm too lazy to do something better ;)
$(function () {
var links = [];
$.ajax(
{
//url: location.pathname, // Use current page
url: '/directoryname/', //directory index of your choice
success: saveAjaxedLinks
}
);
function saveAjaxedLinks (data, e) {
// Scrape anchors off of page.
// Note -- there might be other anchors on the page
// that you don't want to pick up, say the "up a directory level" anchors.
// you can filter those out if you want, but you'll have to determine the criteria for doing so.
var directory = $('a', data);
//Get anchor nodes and store them.
links = directory.get();
//Assign event listener to button after the data is ready.
$('button#yourbuttonid').on( 'click', onclickGetRandomPage );
//uncomment to do action immediately.
//onclickGetRandomPage();
}
function onclickGetRandomPage (e) {
if ( !!e && !!e.preventDefault ) {
e.preventDefault();
}
//if no links on the index, do nothing.
if ( !links.length ) return;
//Get the a random index from the links.
var rnd = Math.floor( Math.random()*links.length);
for (var i = 0, len = links.length; i < len; i++ ) {
// Make sure there's an actual href inside the random link.
// Also, check to make sure the links arent just hashes. Not necessary if you're just using an apache auto-index.
// If there are certain types of links you don't want (eg. directory roots), you can filter them out here.
if ( !!links[rnd].href && links[rnd].href.replace( links[rnd].hash, '' ) !== (location.href.replace( location.hash, '' ) ) ) {
//console.log(links[rnd].href); //Log out the links if you're just testing
window.location.href = links[rnd].href;
break;
} else {
//That link was no good, get a different one.
rnd = Math.floor( Math.random()*links.length );
}
}
}
});
There are some similar posts on SO about this topic but they are all dealing with search and I am trying to do something different. I have tried to apply some of the logic in answers to other questions here but w/o success. Essentially I just want users to be able to enter a status update ID into a text field, hit a button then display all meta data associated with that tweet. If I leave the callback=? part off of the URL string I get a response back but it's empty, which is obviously due to the security restrictions put in place by the Twitter API.
Here is what I am working with currently:
$.getJSON("http://www.twitter.com/statuses/show/73051651728084992.json?callback=?",
function(Data)
{
if(Data.length)
{
var Content = "";
$.each(Data, function(i, Row)
{
alert("We Have Data");
Content += Row;
});
$("#Result").append(Row);
}
else
alert("No Result for that ID!");
})
Which comes back w/ no data, yet the request does come back w/ a 200 HTTP response. Obviously I am missing something as far as the callback goes, I am just not sure what. Just as a crude proof of concept I was going to output all of the data to the Result div and pretty it up later. Obviously first things first I need to actually have some data to work with!
What am I missing?
Remove the ?callback=? from the url and try again. You are asking Twitter's api to wrap the response in a callback ? which would result in invalid JSON. Also, whenever in doubt, load the url manually in your browser to examine whether the response is correctly formatted.
Also, change to this, since $.getJSON() returns an Object, not a string:
if (Data) {
var Content = "";
..
}
I have looked in lots of places for this, and I'm probably being an idiot because this is done a lot, but here's my situation.
I am trying to display a checkbox next to an e-mail field on my website iff the e-mail has not been used to register already.
What I have is something like this:
$('[name=reg_email]').change( function() {
if(!emailUsed()) {
//Update image to be a green checkmark
} else {
//Update image to be a huge red X
}
}
And my "emailUsed" function should be returning a Javascript boolean variable depending on whether or not the e-mail address is in the database. To facilitate this, I've created a script which will determine if it's there or not. So the emailUsed() function just needs to call the script and return, but I need to wait until readystate == 4 before I return, and all of the methods I have found for waiting for readystate to equal 4 prevent me from returning a value at all:
function emailUsed() {
var req = $.get('scripts/email_used.php?email='+$('[name=reg_email]').val());
//Wait for req.readystate to be 4
return req.responseText == 'True';
}
But nowhere can I find something that explains how to do this and still return a value. Everything seems to use callback functions and this and that, but I can't get THIS method to return a value.
Help, please!
Doing a busy wait for req.readyState === 4 is considered bad design practice. You're tying up the UI thread and preventing the browser from updating. If the server is slow enough to respond, the user will get prompted whether to cancel further processing.
If you take a look at $.get(), it takes a completion function as one of its arguments. You should perform your success/failure logic in this function. You can do this by disabling your Submit button until you get back a success message.
You're missing the point of asynchronous methods. The main point is that there is some calculation to be done, and you don't want to tie up the current thread waiting for that calculation. Therefore, long running methods should not return a value, but instead they should provide a callback that will be passed the status of the call, without making the entire app wait.
I would suggest the following
function emailUsed (callback) {
var req = $.get('scripts/email_used.php?email='+$('[name=reg_email]').val(),
function(data) {
callback(data == 'True');
}
);
}
$('[name=reg_email]').change( function() {
emailUsed(function(isUsed){
if (isUsed) {
//Update image to be a green checkmark
} else {
//Update image to be a huge red X
}
});
}
Background
I'm writing an asynchronous comment system for my website, after reading plenty of tutorials on how to accomplish this I started building one from scratch. The comments are pulled using a JSON request and displayed using Javascript (jQuery). When the user adds a new comment it goes through the hoops and finally is sent via AJAX to the backend where it's added to the database. In the success section of the AJAX request I had the script empty the comments, then repull the new list (including the new post) and redisplay them.
Problem
While that was all nice, since it's making the page much shorter, then much longer it messes up where the user is viewing the page. I wanted to have it readjust the page back down to the end of the comment list (where the add comment form is). It also re-enables the add button, which was disabled when the clicked it to prevent impatient people from spamming.
$('#commentList').empty();
getComments('blog', $('input#blogId').val());
window.location = "#addComment";
$('#comAdd').removeAttr('disabled');
While this worked all well and good in theory, it seemed that the browser was getting ahead of itself and processing the window.location before the getComments function was done. So I read a little more and googled it and it seemed people were saying (for similar problems) to use callback functions, so I came up with this:
$('#commentList').empty();
getComments('blog', $('input#blogId').val(), function() {
window.location = "#addComment";
$('#comAdd').removeAttr('disabled');
});
This generates no javascript errors according to FireFox, but nothing within the callback function is working, it's not re-enabling the button nor changing the window.location.
Any ideas? Better ways to go about it? Do I have a glaring typo that I can't seem to see?
Thanks!
Update
I was under the impression the callback functions were a standard thing you could use.
function getComments(type, id)
{
$.getJSON("/ajax/"+type+"/comments?jsoncallback=&id="+id, function(data) {
for (var x = 0; x < data.length; x++)
{
var div = $("<div>").addClass("comment").appendTo("#commentList");
var fieldset = $("<fieldset>");
var legend = $("<legend>").addClass("commentHeader");
if ( data[x].url == "" )
{
legend.text((x+1) + ' - ' + data[x].name);
}
else
{
$("<a>").attr({href: data[x].url}).text((x+1) + ' - ' + data[x].name).appendTo(legend);
}
legend.appendTo(fieldset);
$("<div>").addClass("date").text(data[x].timestamp).appendTo(fieldset);
$("<p>").addClass("comment").text(data[x].content).appendTo(fieldset);
fieldset.appendTo(div);
}
});
}
This is called on document ready. Pulling all the comments and displaying them inside the #commentList div. When the user submits his/her comment it performs an AJAX request to a PHP script that adds the new comment to the database, upon success of this I have this:
$('#commentList').empty();
getComments('blog', $('input#blogId').val());
window.location = "#addComment";
$('#comAdd').removeAttr('disabled');
Deletes all the comments from the page.
Uses JSON to request the comments again (including the users new one).
Moves the page to the #addComment anchor, which is where their new comment would be displayed.
Re-enables the add comment button.
The problem is that the browser does the window.location line before the getComments function is done rendering all the comments, so as the page grows the user isn't looking anywhere near their new comment.
I expect here the problem is your getComments() function (for which more detail is required). You're supplying a third argument being a callback but does the function actually use a callback? What is it doing?
Certain jQuery functions provide callbacks but this isn't an automatic feature. If you're waiting for a user to type a comment you need to trigger the relevant event when they click "Done" or whatever they do.
Ok, try this:
function get_comments(type, id, callback) {
$.getJSON("/ajax/"+type+"/comments?jsoncallback=&id="+id, function(data) {
for (var x = 0; x < data.length; x++) {
var div = $("<div>").addClass("comment").appendTo("#commentList");
var fieldset = $("<fieldset>");
var legend = $("<legend>").addClass("commentHeader");
if ( data[x].url == "" ) {
legend.text((x+1) + ' - ' + data[x].name);
} else {
$("<a>").attr({href: data[x].url}).text((x+1) + ' - ' + data[x].name).appendTo(legend);
}
legend.appendTo(fieldset);
$("<div>").addClass("date").text(data[x].timestamp).appendTo(fieldset);
$("<p>").addClass("comment").text(data[x].content).appendTo(fieldset);
fieldset.appendTo(div);
if (typeof callback != 'undefined') {
callback();
}
}
});
}
Note: the difference here is that a third argument is supplied to get_comments() which is a callback that'll be called at the end of your $.getJSON() callback. That'll give you the proper ordering you want.
I might also suggest not constructing the HTML like that but including it in your page and hiding/unhiding it as necessary. It tends to be much more performant that dynamic HTML and have less issues (eg new HTML, unless you use $().live() will not have relevant event handlers).
Edit: Made the callback optional as per the comments. With the above code you can call the function without or without the callback.
Simple. Re-enable the button and go to the anchor after you receive the request and process the information. Like so:
function getComments(type, id)
{
// ADDED
$('#commentList').empty();
$.getJSON("/ajax/"+type+"/comments?jsoncallback=&id="+id, function(data) {
for (var x = 0; x < data.length; x++)
{
var div = $("<div>").addClass("comment").appendTo("#commentList");
var fieldset = $("<fieldset>");
var legend = $("<legend>").addClass("commentHeader");
if ( data[x].url == "" )
{
legend.text((x+1) + ' - ' + data[x].name);
}
else
{
$("<a>").attr({href: data[x].url}).text((x+1) + ' - ' + data[x].name).appendTo(legend);
}
legend.appendTo(fieldset);
$("<div>").addClass("date").text(data[x].timestamp).appendTo(fieldset);
$("<p>").addClass("comment").text(data[x].content).appendTo(fieldset);
fieldset.appendTo(div);
}
// ADDED
window.location = "#addComment";
$('#comAdd').removeAttr('disabled');
});
}
Personal opinion: rather than fetching all comments, why not fetch comments from a certain date? When you load the page, include a server time in the response. The Javascript uses this to query behind the scenes (to automatically check for new comments). The JSON response includes a new server time, which is used in the next response.
How would you handle deleted comments? Easy: have a deleted_on column in your database table, query it, and spit that out in the JSON response along with new posts.
Suggestion: instead of #addcomment, ID comments by timestamp.