So I'm creating a simple Web Page that takes data from a json file and appends a number of paragraphs equal to the number of objects in the json file array:
$(function () {
function init() {
console.log("OK");
var dat;
var i;
load();
fill();
}
function load()
{
$.get("data.json", function (data, status) {
dat=data;
console.log(dat);
})
}
function fill()
{
console.log(dat);
for(i=0; i<dat.length(); i++) $("#container").append("<p>Testing</p> <br/><br/>")
}
$(".front").on("load", init());
});
However when I run the web page the first time I try to do a console log it prints out the data however the second time, inside the fill() function it says:
"Uncaught ReferenceError: dat is not defined"
Any ideas?
There are several problems:
dat is a local variable within your init function, so naturally code in your load function doesn't have access to it.
You're calling init and then passing its return value into on, not hooking up init as a load handler.
$.get is asynchronous, so just calling load and then calling fill won't work, fill will run before the GET has completed.
See comments:
$(function () {
var dat; // *** Make this global to the code (it's not actually global, which is good)
function init() {
load(fill); // *** Pass `fill` into `load`
}
function load(next) // *** Accept the callback to call when ready
{
$.get("data.json", function (data, status) {
dat = data;
console.log(dat);
next(); // *** Call it
})
}
function fill()
{
console.log(dat);
for(i=0; i<dat.length(); i++) $("#container").append("<p>Testing</p> <br/><br/>")
}
$(".front").on("load", init); // *** No () on init, you want to pass the function into `on`, not *call* the function
});
Some other notes:
You might also look into promises.
Unless you need dat for more than fill, consider not having the dat variable at all; just have load call fill with the data as an argument.
Variable dat is in scope of function init() and it doesnt exists outside that function , move variable dat outside function.
var dat;
function init(){
// rest of code
}
Related
So I was following a tutorial to build an Outlook Add-in. However, the demo does not display the body of the message.
I also learned from the doc that I can call the getAsync to access to the body but it does not work. Do I need to use async await here?
Here is the code:
function loadProps() {
$("#attachments").html(buildAttachmentsString(item.attachments));
$("#cc").html(buildEmailAddressesString(item.cc));
$("#conversationId").text(item.conversationId);
$("#from").html(buildEmailAddressString(item.from));
$("#internetMessageId").text(item.internetMessageId);
$("#normalizedSubject").text(item.normalizedSubject);
$("#sender").html(buildEmailAddressString(item.sender));
$("#subject").text(item.subject);
$("#to").html(buildEmailAddressesString(item.to));
$("#body").text(buildEmailBodyString()); //async function
}
function buildEmailBodyString() {
Office.context.mailbox.item.body.getAsync(Office.CoercionType.Text, function callback(resText) {
return resText.value;
});
}
Your issue is that your buildEmailBodyString fires off getAsync and exists immediately. It isn't returning restText.value from the function because the function already existed.
function buildEmailBodyString() {
// 1. Fires function
Office.context.mailbox.item.body.getAsync(Office.CoercionType.Text, function callback(resText) {
// 3. returns a value to nothing
return resText.value;
});
// 2. Exits function
}
One solution here would be to set $("#body") from within the callback:
function buildEmailBodyString() {
Office.context.mailbox.item.body.getAsync(Office.CoercionType.Text, function callback(resText) {
$("#body").text(resText.value);
});
}
You could also drop buildEmailBodyString entirely and call it within loadProps directory. This would simplify the code so it's a bit easier grok down the road:
function loadProps() {
$("#attachments").html(buildAttachmentsString(item.attachments));
$("#cc").html(buildEmailAddressesString(item.cc));
$("#conversationId").text(item.conversationId);
$("#from").html(buildEmailAddressString(item.from));
$("#internetMessageId").text(item.internetMessageId);
$("#normalizedSubject").text(item.normalizedSubject);
$("#sender").html(buildEmailAddressString(item.sender));
$("#subject").text(item.subject);
$("#to").html(buildEmailAddressesString(item.to));
// Retrieve Email Body
Office.context.mailbox.item.body.getAsync(Office.CoercionType.Text, function callback(resText) {
$("#body").text(resText.value);
});
}
I need for a function to be executable only after an object is defined, I'm currently working in a fascade pattern and one method is dependent on another method. in this case 'addNewLayer' fails because 'setFullMap' hasn't finished executing. is there a solution? I'm using jquery and vanilla js so most any solution would be helpful at this point:
var jen = (function(){
function setFullMap(mapID){
jen.map = new Map(mapID);
}
function setLayer(opt){
//execute code here after jen.map is defined
}
return{
samp: function(id, opt){
setFullMap(id);
addNewLayer(opt);
}
};
})();
Thanks
solution:
var jen = (function(){
function setFullMap(mapID, callback) {
jen.map = new Map(mapID);
if(jen.map){
callback();
}
}
return {
samp: function(id, opt){
setFullMap(id, function(){
addNewLayer(opt);
}.bind(this));
}
};
})();
You will have to pass a callback function to setFullMap, and execute it once the function has completed (at the very end, before the closing }).
var jen = (function(){
function setFullMap(mapID, callback){
jen.map = new Map(mapID);
callback();
}
function setLayer(opt){
//execute code here after jen.map is defined
}
return{
samp: function(id, opt){
setFullMap(id, function() {
addNewLayer(opt);
}.bind(this));
}
};
})();
Do not forget using .bind(this) - it is very important in order to keep the original this in your callback function.
Edit:
Actually that would not work work if the Map constructor is a-synchronous. If you do not have access to the constructor and/or you cannot pass it a callback, then presumably the only (and sad) option would be to use a setTimeout or (easier) setInterval, continuously checking at defined intervals if the operation has been completed, and then fire the callback.
You could use a callback parameter:
function setFullmap(mapId,callback) {
jen.map = new Map(mapId);
callback();
}
....
samp: function(id, opt){
setFullMap(id,function() {
addNewLayer(opt);
});
}
When u dont have a way to manipulate the Map Object then u need to use a loop:
var loop=self.setInterval(function(){
if(jen.map) {
//execute code here after jen.map is defined
console.log(typeof jen.map);
window.clearInterval(loop);
}
},50);
Check jsfiddle:
http://jsfiddle.net/9yv5t/1/
I have checked the docs and it seems that there are various events you could listen to.
For example:
var m = new Map(...);
m.on('load', function () {
//execute code when the first layer is ready
});
var l = new Layer(...);
l.on('load', function () {
//execute code when the layer has been initialized
});
It's also carefully stated for the Layer.load event:
fires after layer properties for the layer are successfully populated.
This event must be successful before the layer can be added to the
map.
In short i want to overwrite a javascript function with a newer one, but in that newer function i want to be able to call the old one. So for example:
function test()
{
alert('original');
}
// then some time later
function test()
{
alert('new function');
}
// call function
test();
In this case only the last test() is invoked. So the new function is alerted.
But is there a way to call the first test() method aswell? SO both test() function get invoked?
The reason i need this is because a web application generates an onSave() method. This function is triggered when a form is saved through Ajax.
I want to do some additional things when the form is saved but i can't just change the original onSave() function. That is why i'm looking for a way to extend it.
How can i do this?
function test()
{
console.log('original');
}
var test = function (oldFn) {
// /\
// -------
// \/
return function () { // <- return a new function which will get stored in `test`
oldFn(); // use the passed `oldFn`
console.log('new function'); // the new code
};
}(test); // <- pass in the old function, we do this, to avoid reference problems
// call function
test();
Why don't you create a new function and put inside the function test() so that when the function test() is called then the new function is called too..
e.g.
function test(){
//code
your_new_function();
}
function your_new_function(){
//code
}
Use below instead of making same name function
$(document).ajaxComplete(function() {
// do your work
});
You can't create two functions of same name
I'm using a jQuery json function inside another function, how can I return an array made in the jQuery function as the return value of my parent function?
this is the basic setup
function getFlickrSet(flickr_photoset_id){
var images = [];
images = $.getJSON(url, function(data){ return data; // I HAVE THE DATA HERE };
return images // I HAVE NO DATA HERE
}
var myImages = getFlickrSet(23409823423423);
alert(myImages); // this gives me nothing
I have set up an example on jsfiddle right here, if you could tell me where my code is wrong, I would greatly appreciate it.
Thank you!
You can't. Instead, pass in a function:
function getFlickrSet(flickr_photoset_id, when_ready){
var images = [];
$.getJSON(url, function(data){
// prepare images
when_ready( images );
});
}
getFlickrSet(nnnn, function(images) {
alert(images);
});
Why can't you do that? Because the "$.getJSON()" call is asynchronous. By the time that the callback function is called (where you wrote, "I HAVE THE DATA HERE"), the outer function has returned already. You can't make the browser wait for that call to complete, so instead you design the API such that code can be passed in and run later when the result is available.
Well, Ajax is asynchronous (that's what the 'A' stands for), so you must do this in an asynchronous way, which boils down to callbacks. What you need to do is pass a callback function to your outer function that you want to be called ("called back," if you will) when the Ajax request completes. You could just give it 'alert' like this:
function getFlickrSet(flickr_photoset_id) {
images = $.getJSON(url, alert); // <-- just the name of the function, no ()
}
var myImages = getFlickrSet(23409823423423);
// => An alert pops up with the data!
...but more likely you'd write something like this:
function doSomethingWithData(data) { // we'll use this later
alert(data); // or whatever you want
}
function getFlickrSet(flickr_photoset_id, callback) {
// new parameter here for a function ------^
// to be given here -------v
images = $.getJSON(url, callback);
return images // I HAVE NO DATA HERE
}
var myImages = getFlickrSet(23409823423423, doSomethingWithData);
// => Your function `doSomethingWithData` will be called the data as a parameter
// when the $.getJSON request returns.
Is there anyway to calling a function from another function .. little hard to explain. heres in example. One function loads html page and when ready it calls the original function.
I think i need to pass in a reference but unsure how to do this... if i set it to "this" - it doesn't seem to work
ANy ideas?
order.prototype.printMe = function(){
order_resume.loadthis("myTestPage.html", "showData");
}
order.prototype.testme= function(){
alert("i have been called");
}
//Then when in "loadthis" need to call
orderRsume.prototype.loadthis= function(){
// DO SOME STUFF AND WHEN LOADS IT ARRIVES IN OnReady
}
order.prototype.OnReady= function(){
/// NEED TO CALL ORIGINAL "testme" in other function
}
It's not clear for me what you really want to do. In JS functions are first-class objects. So, you can pass function as a parameter to another function:
Cook("lobster",
"water",
function(x) { alert("pot " + x); });
order.somefunc = function(){
// do stuff
}
order.anotherone = function(func){
// do stuff and call function func
func();
}
order.anotherone(order.somefunc);
And if you need to refer to unnamed function from it's body, following syntax should work:
order.recursivefunc = function f(){
// you can use f only in this scope, afaik
f();
};
I slightly changed the signature of your loadthis function aloowing it to be passed the order to actually load.
I also assumed that your doSomeStuff function accepts a callback function. I assumed that it may be an AJAX call so this would be trivial to call a callback function at the end of the AJAX call. Comment this answer if you need more info on how to fire this callback function from your AJAX call.
order.prototype.printMe = function(){
order_resume.load(this, "myTestPage.html", "showData");
}
order.prototype.testme= function(){
alert("i have been called");
}
//Then when in "loadthis" need to call
orderRsume.prototype.load = function(order, page, action){
// DO SOME STUFF AND WHEN LOADS IT ARRIVES IN OnReady
doSomeStuff(page, action, function()
{
order.OnReady();
});
}
order.prototype.OnReady= function(){
/// NEED TO CALL ORIGINAL "testme" in other function
this.testme();
}