Friday, November 1, 2013

Angular Promises in TypeScript

If you're like me and love typed languages, TypeScript seems like a great thing and it is.  Though there are some complications to using it along with some of the existing frameworks that are out there.  A lot of this comes from using modules and classes in TypeScript, which you probably are if you are using typeScript in the first place.  When using TypeScript and Angular it can sometimes be hard to get access to things like Angular's $scope deep within the bowels of your classes.

Recently I was working with Azure and handling the asynchronous request callback using an Angular promise.  This presented me with a couple of difficulties:

  • When calling .resolve on the deferral, it was never firing the .when statement on the code that was holding the promise so I never got may data loaded correctly from my factory
  • Inside the deferral callback code in a class, any calls to the classes properties using the 'this' operator were failing with an undefined or null reference error
What to do?  Here was my original non working code:

Calling code:
this.dataAccess.BeginGetRegistrations().then(function (result: Classes.RegistrationDTO[]) {
    for (var i in result) {
        var registrationDTO: Classes.RegistrationDTO = result[i];
        var registration: Registration = new Registration(registrationDTO.Id, this.dataAccess);
        registration.LoadRegistration(registrationDTO.ScreenName, registrationDTO.Email, registrationDTO.Zip, registrationDTO.Gender, registrationDTO.BirthDate);
        this.Add(registration);
    }
});

Asynchronous function in my data access class:
public BeginGetRegistrations(): ng.IPromise<Classes.RegistrationDTO[]>{
    var deferral = this.service.defer<Classes.RegistrationDTO[]>();
    var registrations = DataAccess.client.getTable('Registration');

    registrations.read().done(function (results) {
        var returnValue: Classes.RegistrationDTO[] = [];
        var registration: Classes.RegistrationDTO;
        for (var i in results) {
            var result = results[i];
            registration = current.LoadResult(result);
            returnValue.push(registration);
        }
        deferral.resolve(returnValue);
    }, function(err) {
        throw err.toString();
    });
    return deferral.promise;;
}

I did a little digging around it seemed obvious.  The call to resolve on the deferral needs to happen in a context that Angular is aware of.  In this case, calling resolve inside $apply method on the $rootScope should solve it so the .when statement on the calling code fires.  Since I was way down in the bowls of a class inside a module I had Angular inject the $rootScope into my factory which in turn set it inside my data access class on creation (constructor).  Now my data access class has a reference to the $rootScope in a class level variable called scope.

I rewrote my code hoping to get the .when to fire like this:
public BeginGetRegistrations(): ng.IPromise<Classes.RegistrationDTO[]>{
    var deferral = this.service.defer<Classes.RegistrationDTO[]>();
    var registrations = DataAccess.client.getTable('Registration');

    registrations.read().done(function (results) {
        var returnValue: Classes.RegistrationDTO[] = [];
        var registration: Classes.RegistrationDTO;
        for (var i in results) {
            var result = results[i];
            registration = current.LoadResult(result);
            returnValue.push(registration);
        }
        this.scope.$apply(deferral.resolve(returnValue));
    }, function(err) {
        throw err.toString();
    });
    return deferral.promise;;
}

As soon as I did this, the second problem raised its head.  That is, I couldn't get access to the 'this' keyword and was failing with an undefined or null reference.  This problem manifested in both the BeginGetRegistration method and the calling code.  The solution was simple.  In each of these methods set a local variable equal to the class level 'this' variable so the callback function has access to it and all was well with the world.  My new corrected and working functions:

Calling code:
var current: any = this;
this.dataAccess.BeginGetRegistrations().then(function (result: Classes.RegistrationDTO[]) {
    for (var i in result) {
        var registrationDTO = result[i];
        var registration: Registration = new Registration(registrationDTO.Id, current.dataAccess);
        registration.LoadRegistration(registrationDTO.ScreenName, registrationDTO.Email, registrationDTO.Zip, registrationDTO.Gender, registrationDTO.BirthDate);
        current.Add(registration);
    }
});

Asynchronous function in my data access class:
public BeginGetRegistrations(): ng.IPromise<Classes.RegistrationDTO[]>{
    var deferral = this.service.defer<Classes.RegistrationDTO[]>();
    var registrations = DataAccess.client.getTable('Registration');
    var current: any = this;

    registrations.read().done(function (results) {
        var returnValue: Classes.RegistrationDTO[] = [];
        var registration: Classes.RegistrationDTO;
        for (var i in results) {
            var result = results[i];
            registration = current.LoadResult(result);
            returnValue.push(registration);
        }
        current.scope.$apply(deferral.resolve(returnValue));
    }, function(err) {
        throw err.toString();
    });
    return deferral.promise;;
}

With these fixes in place my Azure mobile code was loading beautifully, asynchronously and Angular binding was handling the data coming back and displaying on the UI exactly as it should.

8 comments:

  1. Hi, Great.. Tutorial is just awesome..It is really helpful for a newbie like me.. I am a regular follower of your blog. Really very informative post you shared here. Kindly keep blogging. If anyone wants to become a Front end developer learn from TypeScript Online Training . or learn thru Javascript Training in Chennai. Nowadays JavaScript has tons of job opportunities on various vertical industry. ES6 Training in Chennai

    ReplyDelete
  2. I appreciate your efforts because it conveys the message of what you are trying to say. It's a great skill to make even the person who doesn't know about the subject could able to understand the subject . Your blogs are understandable and also elaborately described. I hope to read more and more interesting articles from your blog. All the best.

    rpa training in bangalore
    best rpa training in bangalore
    RPA training in bangalore
    rpa course in bangalore
    rpa training in chennai
    rpa online training

    ReplyDelete
  3. Thank you for benefiting from time to focus on this kind of, I feel firmly about it and also really like comprehending far more with this particular subject matter. In case doable, when you get know-how, is it possible to thoughts modernizing your site together with far more details? It’s extremely useful to me 
    python Course in Pune
    python Course institute in Chennai
    python Training institute in Bangalore

    ReplyDelete

  4. Does your blog have a contact page? I’m having problems locating it but, I’d like to shoot you an email. I’ve got some recommendations for your blog you might be interested in hearing.
    AWS Training in Chennai |AWS Training Course in Chennai
    AWS Training in Chennai | AWS Training in Chennai cost
    AWS Training in Chennai | Aws Training Institute in Chennai

    ReplyDelete

  5. Your good knowledge and kindness in playing with all the pieces were very useful. I don’t know what I would have done if I had not encountered such a step like this.
    microsoft azure training in bangalore
    rpa training in bangalore
    best rpa training in bangalore
    rpa online training

    ReplyDelete
  6. All the points you described so beautiful. Every time i read your i blog and i am so surprised that how you can write so well.
    AWS training in sholinganallur
    AWS training in Tambaram
    AWS training in Velachery

    ReplyDelete
  7. Attend The Python training in bangalore From ExcelR. Practical Python training in bangalore Sessions With Assured Placement Support From Experienced Faculty. ExcelR Offers The Python training in bangalore.
    python training in bangalore

    ReplyDelete