OfficeJS addHandlerAsync callback does not execute angular component method - javascript

I am working on an outlook web add-in (in Angular 5) and I am implementing a pinnable task pane and I've been following this documentation from Microsoft : Implement a pinnable task pane in Outlook.
What I want to do is when the selected mail in Outlook was changed, I need to update the content of my task pane UI.
On My Component.TS
I added the following addHandlerSync event listener for change on mail selection:
ngOnInit() {
Office.context.mailbox.addHandlerAsync(Office.EventType.ItemChanged, this.selectMailChanged);
}
selectMailChanged(){
this.getPhoneNumbers() //This function gets phone numbers on the email
}
The error of the above code is
this.getPhoneNumbers is not defined.
I tried enclosing this this.getPhoneNumbers on zone (based on MS Documentation: Trigger the UI update) but it returns zone.run is not defined.
How can I call an angular component method on addHandlerAsync callback?

Good old famous this keyword problems.
You're getting that error message because of the context difference. When you're writing the code, the method selectMailChanged references the method getPhoneNumbers (which I'm hoping you have it implemented) in your component. So coding-wise it looks good.
But when the event kicks in - it doesn't have the context of the component anymore, because it's just calling a callback function - so it doesn't really have all the outside world information except the function that it's calling into. You can read a few good answers about this below:
How to access the correct `this` inside a callback?
https://thenewstack.io/mastering-javascript-callbacks-bind-apply-call/
https://technology.amis.nl/2016/08/23/access-the-original-calling-context-in-a-callback-function-in-typescript/
Move the functionality in getPhoneNumbers to the callback method and you shouldn't have this problem.

Related

Non of the webdriverio methods work to wait until an element is shown using Appium & WebDriverIO (JavaScript)

I am trying to write a test case use in JavaScript with webdriverio (using appium server) for a native android app.
My test case requires me to log in the app, and after logging (which takes 3-4 seconds) I should click a button (element). I tried all of the WebDriverIO APIs like waitForDisplayed, isDisplayed(), non of them work, most the time the error message is that :
TypeError: client.element(...).waitForDisplayed is not a function
at Context.<anonymous> (test-auto-obi-copy.js:142:14)
at processImmediate (internal/timers.js:439:21)
at process.topLevelDomainCallback (domain.js:130:23)
Here is the WebDriverIO Documentation for waitForDisplayed https://webdriver.io/docs/api/element/waitForClickable.html
My code looks like this:
it("should press the profile button", function () {
return client
.element('android=new UiSelector().resourceId("com.example.dev:id/nav_graph_profile")')
.waitForDisplayed(undefined, true)
.click('android=new UiSelector().resourceId("com.example.dev:id/nav_graph_profile")')
.then( function() {
//whatever
})
})
The login test completes succesfully, but after the LOG-IN button is pressed I want to make my test suite "sleep" until the next page loads, to achieve this I was trying to wait until this particular Profile button (element) becomes available, but it seems impossible to wait for it.
Can anyone suggest me what to do in this case, how can I wait?
WebDriverIO changed the names of some of their functions when moving from v4 -> v5 .waitForDisplayed() was one of them, as seen in the changelogs.
WebdriverIO v4 -> .waitForVisible()
WebdriverIO v5 -> .waitForDisplayed()
There's a fair few functions that changed names slightly, so it's worth a look - Additionally, the Docs for v4 still exist though are a little harder to search - Here is the entry for .waitForVisible()
Also, by passing undefined as the first parameter, your delay will only wait for the default 500ms. You'll probably want something like this instead
.waitForDisplayed(5000, true)

Dynamics CRM - JS ReferenceError "X" is not defined

I have a short bit of Javascript that sets fields to optional for certain forms.
I've checked syntax multiple times, checked the execute order in the CRM Form, and there are no references to other JS Libraries.
function getFormName() {
var formName;
formName = Xrm.Page.ui.formSelector.getCurrentItem().getLabel();
if (formName == "EPS Plan Form") {
Xrm.Page.getAttribute("abc_plan_type").setRequiredLevel("none");
Xrm.Page.getAttribute("usi_erisa_plan").setRequiredLevel("none");
Xrm.Page.getAttribute("abc_product").setRequiredLevel("none");
}
}
The error I'm getting seems to be in reference to general syntax issues :
ReferenceError: getName is not defined
at eval (eval at RunHandlerInternal
at RunHandlerInternal
at RunHandlers
at OnScriptTagLoaded
Seems like your event trigger on the form might be configured to call a function called getName...
If you check the form Properties > Events, do you see a call to getName in the OnLoad event? Based on your function name above you'd need it to call getFormName.
And for the record, Xrm.Page is deprecated in favor of passing execution context and using executionContext.getFormContext() (except when referencing the parent page from a web resource, in which case Xrm.Page is still supported, last I heard.)

Javascript structured error handling

I am developing my first Javascript app and I am trying to go object oriented.
There is a basic closure that returns my primary object and every function I invoke rests in that object. Some pseudo code would look like this:
primary = (function(){
var object = {
doSomething = function(){};
},
return {intance:function(return object)}
});
//invocation
primary.instance().doSomething();
What I am trying to achieve is to attach an error handler function to my object, so that whenever there is an internal error, it is cought, and I don't have to wrap every function call in a try catch block.
I tried object.onerrorbut the error went on to window object. Maybe I am getting the concept wrong. I tried searching on Github for some simpler framework that includes structured error handling, but no luck. I am pretty familiar with this in PHP, but I haven't done this so far in Javascript. Can somebody show me an example how it is done right?
EDIT: I know that structured error handling goes further, I am just trying to get a root handler, so that no errors / exceptions can pass on to the window object
Dealing with the error event without a try catch block will halt the execution of your script (except for any asynchronous functions that have already been called).
You can suppress (non-ajax, non-syntax) errors by capturing them on document.body or a more specific object, and stop them being thrown to the user (or reaching the window object) by using e.preventDefault() or return false, and send them to a global/object handler (to inspect or log) by passing the event object as an argument - but any of those options will stop your script execution beyond the point of error. That's the main benefit of a try catch block, and as far as I know there is no way around that.

Javascript error when moving recurring appointments

Using the RadSchedular, a RadWindow appears when moving an appointment in a series of recurring appointments asking me if I want to move them al or just the current appointment.
No matter what I choose an error is thrown telling me that object 'this' does not contain a method called 'get_owner'.
The Telerik.Web.UI dll's are on version 2014.2.724.40 and the project is an ASP.NET project.
The error occurs in a dynamic blank script and looks like this:
_onAppointmentMoveCallback:function(j,h){h.Scheduler._raiseRecurrenceActionDialogClosedEvent(h,false,b.RecurrenceAction.Move);
var k={appointment:h.Appointment,newStartTime:h.NewStart,editingRecurringSeries:j,targetSlot:h.TargetSlot,isAbortedByUser:false};
var i=a.raiseCancellableControlEvent(h.Scheduler,"appointmentMoveEnd",k);
//Error in next if()
if((this.get_owner().get_groupBy()!==g)&&this.get_owner()._webServiceSettings.get_isEmpty()&&h.Appointment.get_resources().indexOf(h.SourceSlot.get_resource())==-1){i=true;
}if(!i){h.Scheduler.moveAppointment(h.Appointment,j,h.SourceSlot,h.TargetSlot);
}else{h.Appointment._abortDrag();
}}
If I understand correctly, this is Telerik's internal code and I can't do anything about it? Is there anyone who encountered the same problem?
These two images reflect on the debugger state:

TypeError when running jasmine specs that use a jQuery plugin built using the Widget factory

I'm using a jQuery plugin called toggleEdit for inline editing.
Everything works fine when the code is actually used in the page.
However, my test suite fails with the following error:
TypeError: Cannot call method 'remove' of undefined
I tracked it down to be triggered from within the clear method of this particular plugin. Its source file can be found here.
There are two relevant bits in that code:
1- The _init function
self.element.addClass("toggleEdit toggleEdit-edit toggleEdit-edit-" +
self._tag(self.element))
//store reference to preview element
.data("toggleEdit-preview", self.p);
As you can see, when the plugin is first instantiated it uses the data structure on self to store the newly created element.
2- The clear function
self.element.data("toggleEdit-preview").remove();
The clear function then tries to access that structure and retrieve the element. That's when, while inside a jasmine spec, it fails with the aforementioned exception.
Has anyone seen anything similar?
EDIT:
This is my spec, it's the simplest piece of code able to reproduce the error:
it("should update the given attribute on the server", function(){
$('#user-details input, #user-details select').toggleEdit(); //this line triggers the error
});
http://alz.so/static/plugins/toggleedit/jquery.toggleedit.js
I was taking a look at the source for toggleEdit and it seems that the only 2 times the function clear is called is just before self.element.data gets set:
if (typeof self.element.data("toggleEdit-preview") !== "undefined") {
self.clear();
self.disableEvents();
}
And at destroy function:
destroy: function() {
var self = this;
self.clear();
self.disableEvents();
$.Widget.prototype.destroy.apply(self, arguments);
}
Since the first call seems to be protected, I ask you a somewhat dumb question: Is it possible that destroy is being called twice?
Found my problem: old version of the jQuery + jQuery UI duo. Upgrading them resolves the exception.

Categories

Resources