Wrap body.getAsync() inside a sync function - javascript

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);
});
}

Related

Creating a callback on javascript function

I've been searching and either I don't understand or can't find anything that's relevant to my issue. Basically, I have a function
function Loading() {
jQuery("#loading").fadeToggle(500);
}
And I want to be able to run something to the effect of
Loading(function() { });
Which executes the script in the function() {} when I want it to (within the function)
pass a callback into Loading:
function Loading(callback) {
jQuery("#loading").fadeToggle(500, callback);
}
As per the jQuery docs: Jquery
function Loading(callback) {
jQuery("#loading").fadeToggle(500,callback);
}
Loading(calloncomplete);
function calloncomplete() {
\\do something
}
use done method
function Loading(callback) {
jQuery("#loading").fadeToggle(500).done(callback);
}

return doesnot work with pagemethods

I wonder how to return a value using page methods. the following code gives me error
function main()
{
PageMethods.custref(ddlpf.options[ddlpf.selectedIndex].value,custref1.value,custSuc,custErr);
function custSuc(boo)
{
if(boo==true)
{message("Cust ref already exists");btn_enable(false);make_null();return;}
}
function custErr(){}
Pagemethods.set("true",suc,err);
function suc(res){//code}
function err(){}
}
my problem is even the message displayed, "set" pagemethod is working
change it as the following
function main()
{
PageMethods.custref(ddlpf.options[ddlpf.selectedIndex].value,custref1.value,custSuc,custErr);
function custSuc(boo)
{
if(boo==true)
{message("Cust ref already exists");btn_enable(false);make_null();return;}
Pagemethods.set("true",suc,err);
function suc(res){//code}
function err(){}
}
function custErr(){}
}

Returning from a parent function from inside a child function - Javascript

I'm relatively new to coding in JavaScript, and I've came across a problem. I like to nest functions to keep things orderly, but how would I exit from a parent function from inside a child function?
example:
function foo1() {
function foo2() {
//return foo1() and foo2()?
}
foo2();
}
See update under the fold
You can't. You can only return from the child function, and then return from the parent function.
I should note that in your example, nothing ever calls foo2 (As of your edit, something does). Let's look at a more real example (and one that comes up a lot): Let's say we want know if an array contains an entry matching some criterion. A first stab might be:
function doesArrayContainEntry(someArray) {
someArray.forEach(function(entry) {
if (entryMatchesCondition(entry)) {
return true; // Yes it does <-- This is wrong
}
});
return false; // No it doesn't
}
You can't directly do that. Instead, you have to return from your anonymous iterator function in a way to stop the forEach loop. Since forEach doesn't offer a way to do that, you use some, which does:
function doesArrayContainEntry(someArray) {
return someArray.some(function(entry) {
if (entryMatchesCondition(entry)) {
return true; // Yes it does
}
});
}
some returns true (and stops looping) if any call to the iterator function returns true; it returns false if no call to the iterator returned true.
Again, that's just one common example.
You've referred to setInterval below, which tells me that you're almost certainly doing this in a browser environment.
If so, your play function almost certainly has already returned by the time you want to do what you're talking about, assuming the game has any interaction with the user other than alert and confirm. This is because of the asynchronous nature of the environment.
For example:
function play() {
var health = 100;
function handleEvent() {
// Handle the event, impacting health
if (health < 0 {
// Here's where you probably wanted to call die()
}
}
hookUpSomeEvent(handleEvent);
}
The thing is, that play will run and return almost immediately. Then the browser waits for the event you hooked up to occur, and if it does, it triggers the code in handleEvent. But play has long-since returned.
Make a note whether the parent function should also return.
function foo1() {
bool shouldReturn = false;
function foo2() {
shouldReturn = true; // put some logic here to tell if foo1() should also return
return;
}
if (shouldReturn) {
return;
} else {
// continue
}
}
It only says that you can't return the parent function in the child function, but we can do a callback and make it happen.
function foo1(cb = () => null) {
function foo2() {
cb();
}
foo2();
}
foo1(() => {
// do something
});
We can use Promises for this:
const fun1 = async () => {
const shouldReturn = await new Promise((resolve, reject) => {
// in-game logic...
resolve(true)
})
if(shouldReturn) return;
}
if you wanna return from the parent function, then just resolve with true
Based on your comment, something like this might work as a main game loop.
function play() {
var stillPlaying = true;
while(stillPlaying) {
... play game ...
stillPlaying = false; // set this when some condition has determined you are done
}
}

Immediate object initialization confusion

I am working on a js file that makes use of JScroll. The callback for the jsp-scroll-y event is defined in the following function
function initWall() {
//callback from jqueryscrollpane
Scroll_TimeLine_Instance = function (event, scrollPositionY, isAtTop, isAtBottom){
//get more content
if (isAtBottom) {
GetMoreDate(objid, vwrsid, secid, orgid, incflwr, qty, mintlid, maxtlid, successGetTimeLineCallback, failureGetTimeLineCallback);
}
}();
}
Another function is defined that then binds this callback to the jsScroll
function reapplyScroll() {
Utilities.DestroyScrollBar($(_target).closest('.widgetBody'));
Utilities.ApplyScrollBar($(_target).closest('.widgetBody'), false, Scroll_TimeLine_Instance);
}
Utilities.ApplyScrollBar = function (element, showScrollBar, scrollCallback) {
$(element).jScrollPane({
horizontalGutter: 5,
verticalGutter: 5,
'showArrows': false
}).bind('jsp-scroll-y', scrollCallback);
if (!showScrollBar) {
$(element).find('.jspDrag').hide();
}
}
The callback was never called, and I found this was because it was undefined. If I remove the Immediate object initialization (); from after the creation of the function everything works fine.
Can anyone explain this? I don't understand why it was being called immediate anyway, so i assume this is an error on the part of whoever created it, and I have no idea why it would cause this variable to be undefined?
It is undefined because the function (that is immediately called) does not return any value
So it seems indeed that this is a bug of the library..
Either remove the (); at the end, or if you want to call it right there as well just invoke it in the following line
function initWall() {
//callback from jqueryscrollpane
Scroll_TimeLine_Instance = function (event, scrollPositionY, isAtTop, isAtBottom){
//get more content
if (isAtBottom) {
GetMoreDate(objid, vwrsid, secid, orgid, incflwr, qty, mintlid, maxtlid, successGetTimeLineCallback, failureGetTimeLineCallback);
}
}; /// this is assigning the function to our variable
Scroll_TimeLine_Instance (); // this is the invokation
}

How to delay a function from returning until after clicks have occurred

The following confirmDialog function is called midway through another jquery function. When this confirmDialog returns true the other function is supposed to continue... but it doesn't. The reason for this seems to be that the entire confirmDialog function has already executed (returning false) by the time the continue button gets clicked. How can I delay it returning anything until after the buttons have been clicked?
(Or, if I'm completely on the wrong track, what is the problem and how do I fix it?)
function confirmDialog(message) {
....
$('input#continue', conf_dialog).click(function() {
$(this).unbind();
$('p',conf_dialog).fadeOut().text('Are you really sure you want to '+message).fadeIn();
$(this).click(function() {
$(conf_dialog).remove();
return true;
});
});
$('input#cancel', conf_dialog).click(function() {
$(conf_dialog).remove();
return false;
});
}
Im' not sure you can.
AFAIK only built-in function like confirm, alert or prompt can be blocking while asking for an answer.
The general workaround is to refactor your code to use callbacks (or use the built-in functions). So that would mean splitting your caller function in two, and executing the second part when the input is obtained.
In confirmDialog, you're setting up event handlers, that will execute when events are fired, not when confirmDialog is run. Another issue, is that you return true or false inside the event function, so that won't apply to the outer function confirmDialong.
The part that relies on the button presses would need to be re-factored. Perhaps put it in another function, and call it from the click handlers:
var afterConfirm = function(bool) {
if(bool) {
//continue clicked
} else {
//cancel clicked
}
//do for both cases here
}
//inside confirmDialog input#continue
$(this).click(function() {
$(conf_dialog).remove();
afterConfirm(true);
});
You may want to look into using Deferred objects. Here are two links that explain them.
http://www.sitepen.com/blog/2009/03/31/queued-demystifying-deferreds/
http://api.dojotoolkit.org/jsdoc/1.3/dojo.Deferred
Using a Deferred you could take your calling function:
function doSomething () {
// this functions does something before calling confirmDialog
if (confirmDialog) {
// handle ok
} else {
// handle cancel
}
// just to be difficult lets have more code here
}
and refactor it to something like this:
function doSomethingRefactored() {
// this functions does something before calling confirmDialog
var handleCancel = function() { /* handle cancel */};
var handleOk = function() { /* handle ok */};
var doAfter = function() { /* just to be difficult lets have more code here */};
var d = new dojo.deferred();
d.addBoth(handleOk, handleCancel);
d.addCallback(doAfter);
confirmDialog(message, d);
return d;
}
ConfirmDialog would have to be
updated to call d.callback() or
d.errback() instead of returning true
or false
if the function that calls
doSomething needs to wait for
doSomething to finish it can add its
own functions to the callback chain
Hope this helps... it will make a lot more sense after reading the sitepen article.
function callingFunction() {
$('a').click(function() {
confirmDialog('are you sure?', dialogConfirmed);
// the rest of the function is in dialogConfirmed so doesnt
// get run unless the confirm button is pressed
})
}
function dialogConfirmed() {
// put the rest of your function here
}
function confirmDialog(message, callback) {
...
$('input#continue', conf_dialog).click(function() {
callback()
$(conf_dialog).remove();
return false;
}),
$('input#cancel', conf_dialog).click(function() {
$(conf_dialog).remove();
return false;
})
...
}
You could add a timeout before the next function is called
http://www.w3schools.com/htmldom/met_win_settimeout.asp

Categories