I am creating a SPA in DurandalJS with MVC, and have jQuery loading a <select> with options loaded from a database. Setting breakpoints i was able to follow the stack all the way down the chain and verify that all of my ajax loading and jQuery calls were occuring, but when I go to check the select box, it is empty, including the inner html of the tag and the dropdown elements themselves.
What's weird though is that the items will load if I navigate to another page and then come back to the original page (since this is an ajax-ified single page application it doesn't actually navigate in the traditional sense.
Why is this happening and how can I fix it?
Code to load the data:
function addProjectSelectorOptions(projects) {
$('#project-picker').empty();
for (var i = 0; i < projects.length; i++) {
console.log(projects[i]);
$('#project-picker').append(new Option(projects[i]["Name"], projects[i]["Id"]));
}
}
function loadData() {
$.ajax({
url: '/ClubhouseData/GetProjects',
type: 'GET',
cache: false,
success: function (results) {
console.log(results);
addProjectSelectorOptions(results);
}
});
};
loadData();
Solved:
I wrapped loadData() in a jQuery onDocumentLoad call and it fixed the problem.
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 am working on a jquery/ajax project. On document ready, I have the following code:
$(document).ready(function () {
$.ajax({
url: '/Main/ReturnGroups/',
dataType: "json",
success: function (data) {
$('.column').each(function (index) {
let indexVar = index;
let colID = $(this).attr("id");
for (let i = 0; i < data.length; i++) {
if ($(this).attr("id") == data[i].ColumnID) {
let thisID = $(this).attr("id");
let thisGroupID = data[i].ID;
$.ajax({
url: '/Main/GetFullGroup/',
data: { groupID: thisGroupID },
success: function (html) {
$('#' + thisID).append(html); //this html inserts a portlet (JqueryUI) based element
}
});
}
}
})
},
complete: function () {
alert($('.portlet').length); //returns 0 (leads me to believe its being run before success function
AddPageProperties(); //this function is supposed to add a bunch of classes to the elements injected in the success function but doesnt actually add the classes when its here
}
});
})
It seems to me that the contents of the complete: function is running asynchronously with the success function. From my understanding the purpose of the complete function is to run once the ajax success (or error) function is completely done.
The code is iterating all the columns and returning all the groups which have the same column id in my database, then passing the groupID to another webmethod which is then querying for all tasks and using the passed in groupID only pulling the tasks that are associated to the group, then using that data to inject a partial view to place the tasks/groups in their respective locations.
Things I've tried:
-Put the AddPageProperties() function in a button click, and after the ajax is finished, click the button. This works exactly as intended.
-use ajaxStop(). While this does work as I want for document ready, once I submit another ajax request it runs the function again, thus duplicating the code. My project uses ajax requests when elements are moved around the screen so this doesnt work.
-Try and get the details of an element to see if the html is even there in the first place when the complete: function() is run. The alert in the code snippet returns 0, which leads me to believe the HTML is not there when that alert is executed.
-using the index of the each function to determine the end of the iteration and then run the function, but again does not apply classes in the function. I tried to again do an alert to see if the elements are present, but they are not.
-set async to false, but the browser just says that its deprecated and it doesnt change any behavior
Any advice on the path towards a solution is appreciated. My goal is once all the HTML is injected, then and only then run this function and never again until page is reloaded sometime later.
I would like to stick with JQuery/ajax as my project is dependent on JQuery for Bootstrap.
I'm not sure if this will actually be possible, since load() is an asynchronous method, but I need some way to basically Load several little bits of pages, one at a time, get some data included in them via JavaScript, and then send that over via Ajax so I can put it on a database I made.
Basically I get this from my page, where all the links I'll be having to iterate through are located:
var digiList = $('.2u');
var link;
for(var i=0;i<digiList.length;i++){
link = "http://www.digimon-heroes.com" + $(digiList).eq(i).find('map').children().attr('href');
So far so good.
Now, I'm going to have to load each link (only a specific div of the full page, not the whole thing) into a div I have somewhere around my page, so that I can get some data via JQuery:
var contentURI= link + ' div.row:nth-child(2)';
$('#single').load('grabber.php?url='+ contentURI,function(){
///////////// And I do a bunch of JQuery stuff here, and save stuff into an object
///////////// Aaaand then I call up an ajax request.
$.ajax({
url: 'insertDigi.php',
type: 'POST',
data: {digimon: JSON.stringify(digimon)},
dataType: 'json',
success: function(msg){
console.log(msg);
}
////////This calls up a script that handles everything and makes an insert into my database.
}); //END ajax
}); //END load callback Function
} //END 'for' Statement.
alert('Inserted!');
Naturally, as would be expected, the loading takes too long, and the rest of the for statement just keeps going through, not really caring about letting the load finish up it's business, since the load is asynchronous. The alert('Inserted!'); is called before I even get the chance to load the very first page. This, in turn, means that I only get to load the stuff into my div before I can even treat it's information and send it over to my script.
So my question is: Is there some creative way to do this in such a manner that I could iterate through multiple links, load them, do my business with them, and be done with it? And if not, is there a synchronous alternative to load, that could produce roughly the same effect? I know that it would probably block up my page completely, but I'd be fine with it, since the page does not require any input from me.
Hopefully I explained everything with the necessary detail, and hopefully you guys can help me out with this. Thanks!
You probably want a recursive function, that waits for one iteration, before going to the next iteration etc.
(function recursive(i) {
var digiList = $('.2u');
var link = digiList.eq(i).find('map').children().attr('href') + ' div.row:nth-child(2)';
$.ajax({
url: 'grabber.php',
data: {
url: link
}
}).done(function(data) {
// do stuff with "data"
$.ajax({
url: 'insertDigi.php',
type: 'POST',
data: {
digimon: digimon
},
dataType: 'json'
}).done(function(msg) {
console.log(msg);
if (i < digiList.length) {
recursive(++i); // do the next one ... when this is one is done
}
});
});
})(0);
Just in case you want them to run together you can use closure to preserve each number in the loop
for (var i = 0; i < digiList.length; i++) {
(function(num) { < // num here as the argument is actually i
var link = "http://www.digimon-heroes.com" + $(digiList).eq(num).find('map').children().attr('href');
var contentURI= link + ' div.row:nth-child(2)';
$('#single').load('grabber.php?url=' + contentURI, function() {
///////////// And I do a bunch of JQuery stuff here, and save stuff into an object
///////////// Aaaand then I call up an ajax request.
$.ajax({
url: 'insertDigi.php',
type: 'POST',
data: {
digimon: JSON.stringify(digimon)
},
dataType: 'json',
success: function(msg) {
console.log(msg);
}
////////This calls up a script that handles everything and makes an insert into my database.
}); //END ajax
}); //END load callback Function
})(i);// <-- pass in the number from the loop
}
You can always use synchronous ajax, but there's no good reason for it.
If you know the number of documents you need to download (you can count them or just hardcode if it's constant), you could run some callback function on success and if everything is done, then proceed with logic that need all documents.
To make it even better you could just trigger an event (on document or any other object) when everything is downloaded (e.x. "downloads_done") and listen on this even to make what you need to make.
But all above is for case you need to do something when all is done. However I'm not sure if I understood your question correctly (just read this again).
If you want to download something -> do something with data -> download another thing -> do something again...
Then you can also use javascript waterfall (library or build your own) to make it simple and easy to use. On waterfall you define what should happen when async function is done, one by one.
I'm fetching data (summarizing timeframes) for my dashboard asynchronously by using $.GET(). The script is simple, I'm waiting that the page (fonts, icons..) is completely rendered by using $(window).load(function () {}.
Then I'm using a document.querySelectorAll('[data-id]'); to search the related ids and start a query in a for loop.
// some date ranges I'm using for the request
var request = [
[moment(), moment(), 'today'],
( ... )
[moment().subtract(1, 'year').startOf('year'), moment().subtract(1, 'year').endOf('year'), 'last-year']
];
// find all data-id elements
var t = document.querySelectorAll('[data-id]');
for (var i = 0; i < t.length; i++) {
// extract the id
var mid = t[i].getAttribute('data-id');
// iterate the request array
for (var j = 0; j < request.length; j++) {
requestData(mid, request[j]);
}
}
function requestData(id, time) {
$.ajax({
url: "/api/v1/data/point/" + id,
type: 'GET',
data: {
from: time[0].format('YYYY-MM-DD'),
to: time[1].format('YYYY-MM-DD'),
sum: true
},
dataType: 'json',
success: function (response) {
// find elements by id stuff and replace the innerHTML with the response value (it is just to long to display here, but nothing special).
}
});
}
Q
While the page is doing ~ 5-12 GET requests, the page is completely blocked and I can not load another page by clicking on a link. So whats basically wrong here? Is the behavior maybe also referable to the power of the web server that those 12 GET requests cause heavy load? I've also noticed that if I'm using jquerys $(document).ready function, that the icons are rendered after $.Ajax finishes - this results in squares instead of icons.
Edit: I thought that maybe the mysql calls by the API are blocking the server?
Edit2: async is true by default (http://api.jquery.com/jquery.ajax/#jQuery-ajax-settings)
You can add async: false in AJAX call.
function requestData(id, time) {
$.ajax({
url: "/api/v1/data/point/" + id,
type: 'GET',
async: false,
data: {
from: time[0].format('YYYY-MM-DD'),
to: time[1].format('YYYY-MM-DD'),
sum: true
},
dataType: 'json',
success: function (response) {
// find elements by id stuff and replace the innerHTML with the response value (it is just to long to display here, but nothing special).
}
});
}
And if thats not work then replace it by true.
Below are my ideas on how you can improve the state:
Have you tracked the timeline of the page(in Timeline tab in Chrome dev tools)? It will show the peaks and downs of page performance. The reason of the bloacking can be different from Ajax.
I am sure you know that the browser can only run a limited amount of requests at the same time, no matter if they are sync of async. In your case it's 6. Can you cache the requests so that you don't do the real requests every time?
I'm adding validation to existing code. The view is loaded using ajax, because there are multiple tabs on the page. I got the validation itself to work, by returning a JSON object. The tab displayed depends on if the JSON object contains errors or not. If there are errors, a new page isn't loaded, and validation errors are displayed at the top of the page.
The problem is that the error messages push the page content down, but doesn't expand its containers (they don't have fixed heights), such that it extends beyond its container. I think it's because the entire page isn't redrawn, how do I fix this? I've tried using innerHTML instead of appending using jQuery, but it doesn't make a difference, the page is still distorted.
$.ajax({
type: "POST",
url: actionURL,
datatype: "json",
data: this.GetParams(),
success: function (data) {
if (data.Error) {
//$("#validationErrors").empty().append('<ul>');
//for(var i=0; i<data.ErrorMessages.length; i++) {
//$('#validationErrors').append('<li>' + data.ErrorMessages[i] + '</li>');
//}
//$("#validationErrors").append('</ul>');
document.getElementById('validationErrors').innerHTML = '<ul><li>Username is required</li></ul>'
}
else {
//load another page
}
});
A workaround is to get the height and add a constant to it. Not the solution I was looking for, but it works for now. I wonder if this is just an IE7 problem, haven't tried it in other browsers.
$('.container).height($('.container).height() + 1)