JavaScript throws 'cannot read property ... of undefined' error - javascript

I'm trying to build a basic JQuery app which loads images from Flickr, adds them to an array of jQuery objects, sequentially adds them to the DOM, fades them in, and fades them out in a 3 second cycle. However, in my displayImage function, I cannot use .hide(), .fadeIn() or .fadeOut() because it throws an 'Uncaught TypeError: Cannot read property 'fadeIn' of undefined' error. Here is my code, both the JS and the HTML:
var main = function(){
"use strict";
var url = "http://api.flickr.com/services/feeds/photos_public.gne?tags=cats&format=json&jsoncallback=?";
//Creates the empty array of jQuery image objects
var images = [];
$.getJSON(url, function(flickrResponse){
flickrResponse.items.forEach(function (photo){
var $img = $("<img>").hide();
$img.attr("src", photo.media.m);
//Populates the images array with jQuery objects defined from the Flickr JSON request
images.push($img);
// $("main .photos").append($img);
// $img.fadeIn();
});
});
function displayImage(imgIndex) {
var $displayedImg = images[imgIndex];
$(".photos").fadeOut('slow');
$(".photos").empty();
$(".photos").append($displayedImg);
$displayedImg.fadeIn('slow');
//Function which recursively calls 'displayImage' every three seconds
setTimeout(function(){
imgIndex = imgIndex + 1;
displayImage(imgIndex);
}, 3000);
}
displayImage(0);
};
$(document).ready(main);
And
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Flickr App</title>
<link rel="stylesheet" type="text/css" href="stylesheets/styles.css">
</head>
<body>
<header>
</header>
<main>
<div class = "photos">
</div>
</main>
<footer>
</footer>
<script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
<script src="js/app.js"></script>
</body>
Any ideas what might be undefined? Note that the var $img = $("<img>").hide(); line in the $.getJSONrequest doesn't throw the undefined error!
Thanks very much!
EDIT:
I've also tried to make a synchronous request to fetch the JSON, to make sure it's loaded before the displayImage function is called, and still it throws the same errors:
var main = function(){
"use strict";
var url = "http://api.flickr.com/services/feeds/photos_public.gne?tags=cats&format=json&jsoncallback=?";
var images = [];
//THIS IS WHAT HAS CHANGED
$.ajax({url: url,
dataType: 'json',
async: false,
success: function(flickrResponse){
flickrResponse.items.forEach(function (photo){
var $img = $("<img>").hide();
$img.attr("src", photo.media.m);
images.push($img);
});
}});
function displayImage(imgIndex) {
var $displayedImg = images[imgIndex];
$(".photos").fadeOut('slow');
$(".photos").empty();
$(".photos").append($displayedImg);
$displayedImg.fadeIn('slow');
setTimeout(function(){
imgIndex = imgIndex + 1;
displayImage(imgIndex);
}, 3000);
}
displayImage(0);
};
$(document).ready(main);

You need to wait for the JSON to return before you try to displayImage(0). The JSON request is asynchronous, so your call to displayImage is happening before any JSON has been returned.
I recommend stepping through with a Javascript debugger to better understand what’s going on. You would see then that images is empty, and therefore $displayedImg is undefined.

Related

ajax not loading/retrieving data

I'm doing the FreeCodeCamp course and i'm trying to build a weather app. I found a nice tutorial on how to get the latitude and longitude with geolocation. But now when I try and run the app it doesn't seem to be retrieving the ajax data for me to parse through. I was trying locally and moved it to hosting thinking that might have been it but now I just get a weird error on line one of my html and i don't see anything wrong. Thanks guy here is the code and it's live on weatherapp.boomersplayground.com
index.html
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Weather APP</title>
<link rel="stylesheet" href="style.css">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src='script.js'></script>
</head>
<body>
<div id="forecast">
<h1>Weather at <span id="location"> </span></h1>
<!-- <div id="imgdiv">
<img id="img" src=""/> -->
</div>
<p>It is currently <span id="temp"> </span>F with <span id="desc"> </span></p>
<p>Wind: <span id="wind"></span></p>
</div>
</body>
</html>
script.js
$(document).ready(function(){
var Geo = {};
if (navigator.geolocation){
navigator.geolocation.getCurrentPosition(success,error);
} else {
alert('Geolocation is not supported');
}
function error(){
alert("That's weird! We couldn't find you!");
}
function success(position){
Geo.lat = position.coords.latitude;
Geo.lng = position.coords.longitude;
}
var key = 'c7e3b3ac66e765aa';
var Weather = "http://api.wunderground.com/api/"+ key +"/geolookup/conditions/q/" + Geo.lat + "," + Geo.lng + ".json";
$.ajax({
url : Weather,
dataType : 'jsonp',
success : function(data) {
var location =data['location']['city'];
var temp = data['current_observation']['temp_f'];
var img = data['current_observation']['icon_url'];
var desc = data['current_observation']['weather'];
var wind = data['current_observation']['wind_string'];
}
})
//setting the spans to the correct parameters
$('#location').html(location);
$('#temp').html(temp);
$('#desc').html(desc);
$('#wind').html(wind);
// filling the image src attribute with the image url
// $('#img').attr('src', img);
});
You use the variables initialised at the AJAX response outside of the success callback. You should use them inside the callback, since they're created asynchronously:
$.ajax({
url : Weather,
dataType : 'jsonp',
success : function(data) {
var location =data['location']['city'];
var temp = data['current_observation']['temp_f'];
var img = data['current_observation']['icon_url'];
var desc = data['current_observation']['weather'];
var wind = data['current_observation']['wind_string'];
$('#location').html(location);
$('#temp').html(temp);
$('#desc').html(desc);
$('#wind').html(wind);
}
});
Because you are treating an Asynchronous call as a synchronous one. The Ajax call needs to be in the success callback of getCurrentPosition. You are building the Ajax url before the at and lng is returned.

Unable to push data to handlebars?

I used to use mustache.js for my templates on a quickbase app, but recently decided to switch over to trying handlebars so that I could use the if/then of it for a more appealing template.
However I can not seem to get them to work like mustache did, the Get for my module.js shows in the console, but after that the page doesn't load like it's supposed to (it usually loads the template.html)
module.js
var dbidApplication = "dbidHere";
var dbidTable = "dbidtHere";
var apptoken = "apptokenhere";
$.ajaxSetup({
data: {
apptoken: apptoken
}
});
var promise1 = $.get(dbidApplication, {
a: "dbpage",
pagename: "template.html"
});
var promise2 = $.get(dbidTable, {
act: "API_GenResultsTable",
query: "{3.EX." + kRid + "}",
jsa: 1,
options: "num-1",
});
$.when(promise1, promise2).then(function(html, data) {
//do some stuff with all the data
var template = Handlebars.compile(html[0]);
console.log(html[0]);
console.log(data[0]);
console.log(qdb_data);
$(template(qdb_data)).appendTo("#external");
});
My template has the source for handlebars and the div with id external
template.html
<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/3.0.3/handlebars.runtime.min.js" type="text/javascript"></script>
<title></title>
</head>
<body>
<div id="external"></div>
</body>
</html>
I think you forgot to set qdb_data:
$.when(promise1, promise2).then(function(html, data) {
//do some stuff with all the data
var template = Handlebars.compile(html[0]);
var qdb_data = data[0];
console.log(html[0]);
console.log(data[0]);
console.log(qdb_data);
$(template(qdb_data)).appendTo("#external");
});

JavaScript isn't working on my server

This code is working on other test environment but not on mine.
Do you know why?
I am using Amazon EC2 and Cotendo CDN.
The result I am getting is a blank page.
Thanks in advance!
<html>
<head>
<title>Geo Test</title>
<script type='text/javascript' src='http://www.101greatgoals.com/wp-includes/js/jquery/jquery.js?ver=1.7.1'></script>
<script>
$(document).ready( function() {
$.getJSON( "http://smart-ip.net/geoip-json?callback=?",
function(data){
console.log(data);
var c = data.countryCode;
if(c=="US" || c=="US" ){
document.getElementById('ddd').innerHTML = 'US'; } else {
document.getElementById('ddd').innerHTML = 'Not US';}
/*
this service needs ip
var ip = data.host;
alert(ip);
$.getJSON( "http://freegeoip.net/json/"+ip,
function(data){
console.log(data);
}
);*/
}
);
});?
</script>
</head>
<body>
<div id="ddd"></div>
</body>
</html>
Change this line:
$(document).ready( function() {
to that:
jQuery(document).ready( function($) {
It's necessary, because inside http://www.101greatgoals.com/wp-includes/js/jquery/jquery.js?ver=1.7.1 you've already got a call of jQuery.noConflict(); , so jQuery is not accessible by using the $
...and also remove the ? (see Pointy's comment above)

Dynamically load jQuery templates

For jQuery template:
http://api.jquery.com/category/plugins/templates/
I want to be able to dynamically load the templates from a server, rather than predefining it on the page.
The demos I saw on the projects are using predefined templates. After some research I found out that it is possible.
I try doing this and it doesn't work:
<script src="child.html" type="text/x-jquery-tmpl"></script>
I tried doing this and it doesn't work:
$(function () {
$.get("child.html", function (data) {
//Add template
$.template("tmplChild", data);
});
//template binds before async call is done
$.tmpl("tmplChild").appendTo("body");
});
And finally, I have get it down to the following hack:
so.html (This is the main page):
<html>
<head>
<title></title>
</head>
<body>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js"></script>
<script type="text/javascript" src="http://ajax.microsoft.com/ajax/jquery.templates/beta1/jquery.tmpl.js"></script>
<script type="text/javascript" src="so.js"></script>
<script type="text/javascript">
$(function () {
initTemplates(templateReady);
});
function templateReady() {
$.tmpl("tmplChild").appendTo("body");
}
</script>
</body>
</html>
child.html (This is the child template)
<h1>Child Loaded</h1>
so.js (This is my hack for ajaxly loading the js templates)
function initTemplates(callback) {
var templateUrl = "child.html";
var templateName = "tmplChild";
initTemplate(templateUrl, templateName, callback);
}
function initTemplate(url, name, callback) {
var opts =
{
type: "GET",
url: url,
dataType: ($.browser.msie) ? "text" : "xml",
success: function (data) {
xmlCallback(data, name, callback);
},
error: function (x) {
xmlCallback(x.responseText, name, callback);
}
}
$.ajax(opts);
}
function xmlCallback(data, name, callback) {
if (typeof data != "string") {
if (window.ActiveXObject) {
var str = data.xml;
data = str;
}
// code for Mozilla, Firefox, Opera, etc.
else {
var str = (new XMLSerializer()).serializeToString(data);
data = str;
}
}
//only takes strings!
$.template(name, data);
callback();
}
And here's what I don't like about it.
This doesn't work on Chrome
It seems like a lot of code just to load some template
I lost the ability to use $(document).ready(). I must now put all my code in this templateReady() method to be "template safe".
Is there a way around this?
Thanks,
Chi
Just load the template body as simple text and forget about putting it in a dummy <script> block. You can use $.tmpl(body, params) to populate the template and turn it into a string for appending to the DOM.
The whole thing with "not really script" <script> blocks is just a convenience useful in some situations.
edit — example:
$.get("/some/url/for/a/template", function(templateBody) {
var expandedTemplate = $.tmpl(templateBody, { param1: 0, param2: "Hello World" });
});
If the goal is to fetch a unique template each time you get data via ajax, then you might try fetching the template at the same time and include it in your data, that is if you have the luxury of modifying the returned object (anonymous object in .Net). Then you can store the template anywhere you want and you only need 1 ajax call for both the data and the template.
Refer here:
https://www.npmjs.com/package/jlate
use CDN:
<script src="https://cdn.jsdelivr.net/combine/npm/lodash,npm/jlate#0.0.2/jlate/JLate.min.js"></script>
HTML Code:
<body>
<div>
<jlate id="my_temp" src="template/jlate_title.html" type="template">
Loading...
</jlate>
</div>
</body>
Javascript:
$$("#my_temp").jlate({ title: "sample title"});

jquery noob problem with variables (scope?)

I'm trying to retrieve data from a php file named return that just contains
<?php
echo 'here is a string';
?>
I'm doing this through an html file containing
<!DOCTYPE html>
<html>
<head>
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
<script>
var x;
$.get("return.php", function(data){
x = data;
})
function showAlert() {alert(x);}
$(document).ready(function(){
alert(x);
});
</script>
</head>
<body>
<input type = "button" value = "Click here" onClick="showAlert();">
</body>
</html>
When the button is clicked it retrieves and displays the code fine, but on the $(document).ready thing, it displays "undefined" instead of the data in return.php. Any solutions?
Thanks.
the document.ready is running before the $.get has returned the msg probably
var x;
function showAlert() {alert(x);}
$(document).ready(function(){
$.get("return.php", function(data){
x = data;
showAlert();
})
});
that should work fine
The ajax probably has not loaded yet.
var x;
function showAlert() {alert(x);}
$(document).ready(function(){
$.get("return.php", function(data){
x = data;
alert(x);
});
});
It isn't a question of scope, it's a question of order of events. $.get is an asynchronous call, so it may not finish yet by the time your page loads in the browser (it's a fairly small page so I imagine it loads quite quickly).

Categories

Resources