.when .done function not running - javascript

I have a little script, that saves to json strings to var with the function getJSON. After that I want to create some divs with the content.
For that I create a each for the cat (categories). In the second each, when the repo fits into a cat it should be display too.
But the script never goes to the .when or .each functions.
But with console_log() I see the correct response from the getJSON function.
var repo;
var cat;
$.getJSON("api.php?get_repos&release_id=" + $("#release").find(":selected").data('id'), function (
json) {
repo = json;
});
$.getJSON("api.php?get_cat", function (json) {
cat = json;
});
$.when(repo, cat).done(function(){
$.each(cat, function (i, j) {
$(".tab").append('<button class="tablinks" onclick="openCAT(event, \'' + j.cat_name + '\'">' + j.cat_name + '</button>');
$(".repos").append('<div id="' + j.cat_name + '" class="tabcontent"></div>');
$.each(repo, function (k, v) {
if (v.repo_cat == j.cat_id) {
$("#"+ j.cat_name).append('<div class="repo"></div><p><label><input name="3rdparties[]" type="checkbox" value="' +v.repo_id + '"> ' + v.repo_name +'</label> <i class="icon ion-earth"> Homepage</i> <i class="icon ion-university"> Documentation</i>');
$("#"+ j.cat_name).append('<div class="inside">' + v.repo_desc + '');
$("#"+ j.cat_name).append('<i class="icon ion-flash-off"> Broken Repo</i></div></p></div><br />');
}
});
});
});

There are two issues:
repo,cat are JSON values, not promise or deferred objects, so $.when will not have any effect
repo,cat are only set after the $.getJSON has completed, so will not be available at the time of the $.when
You need to record the jquery promise returned from $.getJSON to be used with $.when:
var repo;
var cat;
var repoPromise = $.getJSON("api.php?get_repos&release_id=" + $("#release").find(":selected").data('id'), function(json) {
repo = json;
});
var catPromise = $.getJSON("api.php?get_cat", function(json) {
cat = json;
});
$.when(repoPromise, catPromise).done(function() {
$.each(cat, function(i, j) {
...
$.each(repo, function(k, v) {
if (v.repo_cat == j.cat_id) {
...
}
});
});
});

Related

Returning data from asynchronous function through callback comes as undefined

The function gets the data from URL and then passes it to another function where the listing is done dynamically based on users in the list of URL. I tried callback but I am getting the following error service.js:9 Uncaught TypeError: callback is not a function
This is the function in one js file:
function GetData(callback, passdata) {
$.ajax({
type: 'GET',
url: 'https://jsonplaceholder.typicode.com/users',
success: function (response) {
debugger;
console.log(response);
return callback(response, passdata);
}
});
}
This is the function in another js file (wherein I want to list the data from the URL):
$(document).ready(function () {
var getData = GetData();
var $data = $('#dataDisplay');
function listData(response, passdata) {
var data = response;
var passeddata = passdata;
$.each(data, function (i, users) {
$data.append('<li>' + '<span>' + users.name + '</span>' + '<br> <span>' + users.email + '</span>' + ' </li>');
});
//adds li dynamically
$("li").append('<i class="material-icons delete">' + "delete" + '</i>');
$("li").append('<i class="material-icons edit">' + "edit" + '</i>');
}
});
You can use anonymous function in document ready =>
GetData(function(result){
// can do further things here..
console.log(result);
}, passdata);
this should fix your error.
For me this worked
function GetData(callback) {
debugger;
$.ajax({
type: 'GET',
url: ' http://localhost:3000/users',
success: function (response) {
console.log(response);
callback(response);
}
});
}
In another js file call the function back and pass the response parameter for that is where the array of the API was saved.
GetData(function (response) {
debugger;
var data = response;
var $data = $('#dataDisplay');
$.each(data, function (i, users) {
$data.append('<li>' + '<span class="table .table-striped .table-hover">' + users.first_name + '</span>' + ' <span class="table .table-striped .table-hover">' + users.email + '</span>' + ' </li>');
});
//adds li dynamically
$("li").append('<i class="material-icons delete ">' + "delete" + '</i>');
$("li").append('<i class="material-icons edit ">' + "edit" + '</i>');
});
});
How can JavaScript know that listData is the callback function if you don't specify it?
You just declared the listData function, but you aren't using it anywhere. There is not any sort of magic that will do it for you :)
Just change
var getData = GetData();
To
var getData = GetData(listData, 'something');

jQuery - Do action when all ajax have completed

I've read about the jQuery's Deferred object, but I can't seem to make much sense out of it, here's my problem, I've got the following code:
function preprocess(form) {
$(form).find(".input input").each(function() {
var required = $(this).attr("required");
var checkField = $(this).closest(".inputcontainer").children(".check");
var errorField = $(this).closest(".inputcontainer").children(".errormessage");
if (typeof required !== 'undefined') {
$(checkField).each(function() {
$(this).css("color", "#FFFF00");
$(this).html("✘");
});
$(errorField).each(function() {
$(this).css("color", "#FFFF00");
$(this).html("(Required)");
});
}
else {
$(checkField).each(function() {
$(this).css("color", "#FFFF00");
$(this).html("✔");
});
$(errorField).each(function() {
$(this).css("color", "#000000");
$(this).html("");
});
}
});
$(form).find("datalist").each(function() {
var datalist = $(this);
callService({
name: "datalist_" + $(this).attr("id"),
data: { },
success: function(json) {
$(json).each(function() {
var html = "";
$(this.options).each(function() {
html += "<option value='" + this.value + "'>";
});
$(datalist).append(html);
});
}
});
});
$(form).find("select").each(function() {
var select = $(this);
callService({
name: "select_" + $(this).attr("name"),
data: { },
success: function(json) {
$(json).each(function() {
var html = "";
$(this.options).each(function() {
html += "<option value='" + this.id + "'>" + this.value + "</option>";
});
$(select).append(html);
});
}
});
});
}
This code prepares a form to be ready to be presented to the user, which involves AJAX calls, which I have wrapped in a callService({}); call, what you can see is the following:
It checks input and puts possibly (Required) next to the fields. (No AJAX)
It loads options from <datalist> and <select>s dynamically. (AJAX)
Then I also have the following (simplified):
function setContent(html, url) {
html = $.parseHTML(html);
$(html).filter("form").each(function() {
preprocess($(this));
});
$("#pagemain").html(html);
}
This gets html from an AJAX call, then calls preprocess on all its forms and updates the #pagemain.
However now data is being displayed before the preprocess has completely finished.
The question: How can I do the $("#pagemain").html(html); after preprocessed ánd involving AJAX processes, have been finished?
Try:
function preprocess(form) {
//Your above code is omitted for brevity
var promises = [];
$(form).find("datalist").each(function() {
var defered = $.Deferred();//create a defered object
promises.push(defered.promise());//store the promise to the list to be resolved later
var datalist = $(this);
callService({
name: "datalist_" + $(this).attr("id"),
data: { },
success: function(json) {
$(json).each(function() {
var html = "";
$(this.options).each(function() {
html += "<option value='" + this.value + "'>";
});
$(datalist).append(html);
});
defered.resolve();//resolve the defered when ajax call has finished
}
});
});
$(form).find("select").each(function() {
var defered = $.Deferred();//create a defered object
promises.push(defered.promise());//store the promise to the list to be resolved later
var select = $(this);
callService({
name: "select_" + $(this).attr("name"),
data: { },
success: function(json) {
$(json).each(function() {
var html = "";
$(this.options).each(function() {
html += "<option value='" + this.id + "'>" + this.value + "</option>";
});
$(select).append(html);
});
defered.resolve();//resolve the defered when ajax call has finished
}
});
});
return promises;
}
Your setContent:
function setContent(html, url) {
html = $.parseHTML(html);
var promises = [];
$(html).filter("form").each(function() {
promises = promises.concat(preprocess($(this)));//Concatenating all promises arrays
});
$.when.apply($,promises).then(function(){// Use $.when to execute a function when all deferreds are resolved.
$("#pagemain").html(html);
});
}
Deferred's can be a little intimidating to learn at first, but, like most things, once the light bulb goes on and you get it, it's pretty simple. The simple setup for creating a deferred object is like this:
var defer = $.Deferred(function(dfd) {
// do the processing you need, and then...
// when processing is complete, make a call to...
dfd.resolve(/* return data goes here, if required */);
}).promise();
// use the deferred object like it was an ajax call
defer.then(/* do the stuff that needed to wait */);
So, using your example:
function setContent(html, url) {
html = $.parseHTML(html);
var defer = $.Deferred(function(dfd) {
$(html).filter("form").each(function() {
preprocess($(this));
});
dfd.resolve();
}).promise();
defer.then($("#pagemain").html(html));
}
neat solution will be using when :
http://api.jquery.com/jQuery.when/
$.when( {//your preprocessing function here
} ).done(function( x ) {
//your done action here
});

Use $.each and if with $.getJSON

Me and $.each aren't good friends, I can't seem to figure out how I should use this statement to print all my data in my JSON file. Another problem is the if statement, I tried it in many ways, but whatever I do, no data is being printed.
My JSON file
[
{
"expo":"pit",
"datum":"05.06.2011 - 05.06.2016",
"img":"images/pit_home.jpg",
"link":"exp1_index.html"
},
{
"expo":"Space Odessy 2.0",
"datum":"17.02 - 19.05.2013",
"img":"images/so_home.jpg",
"link":"exp2_index.html"
}
]
My $.getJSON script
<script type="text/javascript">
function read_json() {
$.getJSON("home.json", function(data) {
var el = document.getElementById("kome");
el.innerHTML = "<td><div class='dsc'>" + data.expo + "<br><em>" + data.datum + "</em></div></td>";
});
}
</script>
So how would I integrate the $.each statement and seperate from that, the if statement?
Try this
$.getJSON("home.json", function (data) {
var html = '',
el = document.getElementById("kome");
$.each(data, function (key, val) {
html += "<td><div class='dsc'>" + val.expo + "<br><em>" + val.datum + "</em></div></td>";
});
el.innerHTML = html;
});
Something like this?
<script type="text/javascript">
function read_json() {
$.getJSON("home.json", function(data) {
var html = '';
$.each(data, function(i, record) {
html += '' +
'<td>' +
'<a href="' + record.link + '" data-ajax="false">' +
'<img src="' + record.img + '">' +
'<div class="dsc">' +
record.expo + '<br>' +
'<em>' + record.datum + '</em>' +
'</div>' +
'</a>' +
'</td>';
});
$('#kome').html(html);
});
}
</script>
Note: I haven't tested this, so there may be a few syntax errors (mostly concerned about the quotes in the string concatenation).
I will note that you don't need jQuery's $.each for this; you can use a basic for-loop:
for (var i = 0; i < data.length; i++) {
var record = data[i];
... stuff...
}
jQuery's .each() is really useful when iterating over elements in the DOM, though. For example, if you wanted to iterate over the elements with class dsc, you could do:
$('.dsc').each(function(i, dsc) {
// Do stuff to the $(dsc) element.
});
Also, you might as well use jQuery's selectors (the $('#kome')) if you're going to use jQuery.
jQuery's API usually has solid examples for stuff; this is one such case.
$.each can iterate arrays [] or objects {}, your json contains both, so first you need to tackle array, that gives you an object on each iteration. Then you can access its properties.
jQuery each documentation
Second thing: to append to innerHTML use "+=" not "=" or you will reset html on each iteration.
var el = document.getElementById("kome");
$.getJSON('ajax/test.json', function(data) {
$.each(data, function(n, linkData) {
el.innerHTML += '' + linkData.expo + '';
});
}

javascript passing values dynamically to a method jquery

$(document).bind('pageinit', function () {
var vendor_id = $.urlParam('vendor_id');
$.ajax({
type: "GET",
url: "http://testservice/testmenu",
data: {
vendor_id: vendor_id
},
error: function () {
alert("Could not get the menu : " + url);
},
success: function parseXml(xml) {
var jsonData = $.parseJSON(xml);
$(jsonData).each(function (index, post) {
$(post).each(function (index, row) {
var finalString = [];
for(var index = 0; index < row.menu.length; index++) {
finalString.push('<div id="collapsibleMenu" data-mini="true" data-role="collapsible" data-inset = "true" data-content-theme="g">');
finalString.push('<h3>' + row.menu[index].category_name + '</h3>');
finalString.push('<ul id="menuDetails" data-role="listview">');
for(var j = 0; j < row.menu[index].products.length; j++) {
var output = ['<li data-icon="addToCart" id="addToCart"> <p>' + row.vendor_menu[index].products[j].prod_name + '</p><p> $' + Number(row.vendor_menu[index].products[j].price).toFixed(2) + '</p>' + '</li>'];
finalString.push(output);
}
finalString.push('</ul></div>');
}
$('#output').append(finalString.join(''));
});
});
$('#output').trigger('create');
}
});
});
function test(prod_id) {
alert("entered test " + prod_id);
addToCart(prod_id, 1);
}
In the following code, where I am doing the following:
<a href="javascript:test("+row.menu[index].products[j].prod_id")">
This is obviously giving me an error. The point is, I need to pass the prod_id dynamically into the javascript test method. I am not sure how to do that. If I just call test without passing prod_id, it works great. Please help!
Try removing the quotes in the argument.
I think I might have figured it out.
Try this.
<a href="javascript:test(\''+row.menu[index].products[j].prod_id+'\')">
This looks like the perfect reason to use a template engine. You might use a Jade template like this:
for post in posts
for row in post
for menu in row.menu
#collapsibleMenu(data-mini="true", data-role="collapsible", data-inset="true", data-content-theme="g")
h3= menu.category_name
ul#menuDetails(data-role="listview")
for product in menu.products
li#addToCart(data-icon="addToCart")
a(href="#", data-product-id=product.prod_id)
p= product.prod_name
p= '$' + Number(product.price).toFixed(2)
Then you can simplify your $.ajax call to:
$.ajax({
// ...
dataType: 'json',
success: function(data) {
$('#output').append(templateFunction(data));
}
});
For the click event, use event delegation:
$('#output').on('click', 'a[data-product-id]', function() {
addToCart(Number($(this).data('product-id')), 1);
});
Easy, yeah? Now change all of your ids to classes, because ids must be unique and yours aren't!

Using Ajax callback variable values in JQuery dynamic click handlers

I'm doing a simple ajax query which retrieves a variable-length list of values as JSON data. I'm trying to make a list based on this data which has click-functions based on the values I got from the JSON query. I can make this work just fine by writing the onClick-methods into the HTML like this:
function loadFooList() {
var list_area = $("#sidebar");
list_area.html("<ul>")
$.ajax({
type: 'GET',
url:'/data/foo/list',
dataType: 'json',
success: function (json) {
$.each(json, function(i, item) {
var link_id = "choosesfoo" + item.id;
list_area.html(list_area.html()
+ "<li> <a href='#' onClick='alert(\"" +
link_id + "\");'>" +
item.name + "</a></li>");
});
list_area.html(list_area.html() + "</ul>");
}
});
}
I don't like writing the onClick-function into the HTML and I also want to learn how to create this same functionality via JQuery click-function.
So the problem is obviously variable-scoping. My naive attempt here obviously won't work because the variables are no longer there when the click happens:
function loadFooList2() {
var list_area = $("#sidebar");
var link_ids = Array();
list_area.html("<ul>")
$.ajax({
type: 'GET',
url:'/data/foo/list',
dataType: 'json',
success: function (json) {
$.each(json, function(i, item) {
var link_id = "choosefoo" + item.id;
list_area.html(list_area.html()
+ "<li> <a href='#' id='" + link_id + "'>"+item.name+"</a></li>");
link_ids.push(link_id);
});
list_area.html(list_area.html() + "</ul>");
for (link_index=0; link_index<link_ids.length; link_index++) {
$("#" + link_ids[link_index]).click(function() {
alert(link_ids[i]);
});
}
}
});
}
Obviously I'd like to do something else than just alert the value, but the alert-call is there as long as I can get that working and move forward.
I understand that I'll have to make some kind of handler-function to which I pass a state-variable. This works for a single value (I can store the whole link_ids array just fine, but then I don't know which of them is the right value for this link), but how would I do this for arbitrary-length lists?
Here is an example from JQuery docs which I'm trying to copy:
// get some data
var foobar = ...;
// specify handler, it needs data as a paramter
function handler(data) {
//...
}
// add click handler and pass foobar!
$('a').click(function(){
handler(foobar);
});
// if you need the context of the original handler, use apply:
$('a').click(function(){
handler.apply(this, [foobar]);
});
And I quess the last example here, "if you need the context of the original handler..." would probably be what I want but I don't know exactly how to get there. I tried to store the current link_id value into this, use it from this in the applied function (using apply()) but I didn't succeed. The necessary values were still undefined according to FireFox. I'm using JQuery 1.3.2.
So what's the right solution for this relatively basic problem?
Use append instead of html():
function loadFooList() {
var ul = $('<ul>');
$.ajax({
type: 'GET',
url:'/data/foo/list',
dataType: 'json',
success: function (json) {
$.each(json, function(i, item) {
var link_id = "choosesfoo" + item.id;
var a = $('<a>').attr('href','#').bind('click', function(e) {
alert(link_id,item_name);
e.preventDefault();
});
$('<li>').append(a).appendTo(ul);
});
ul.appendTo('#sidebar'); // this is where the DOM injection happens
}
});
}
So the problem appears to be getting the link id associated with the link so that your click handler has access to it. Note that if it's alphanumeric it will qualify for the id attribute and you can extract it from there. If it is purely numeric, it will be an illegal id attribute. In that case, you can either use an attribute, like rel, or the jQuery.data() method to store the link id with the link. You can also simplify by using append. I'll show both examples.
var link = $("<li><a href='#' id='" + link_id + "'>" + item.name + "</a></li>";
link.click( function() {
alert( $(this).attr('id') );
});
list_area.append(link);
or (if numeric)
var link = $("<li><a href='#'>" + item.name + "</a></li>";
link.data('identifier', link_id )
.click( function() {
alert( $(this).data('identifier') );
});
list_area.append(link);
Try this:
function loadFooList() {
var list_area = $("#sidebar");
$.ajax({
type: 'GET',
url:'/data/foo/list',
dataType: 'json',
success: function (json) {
var out = '<ul>';
$.each(json, function(i, item) {
var link_id = "choosefoo" + item.id;
out +="<li><a href='#' id='" + link_id + "'>"+item.name+"</a></li>";
});
out +="</ul>"
var $out = $(out);
$out.find('a').click(function(){
var link_id = this.id;
var item_name = $(this).text();
alert(link_id);
alert(link_name);
})
list_area.html($out);
}
});
}
Using multiple appends causing the browser to redraw multiple times in a row. You only want to modify the dom once.

Categories

Resources