No more automatic $promise unwrapping

Like any Philadelphia sports fan says, "BOOOOO!!"

In AngularJS, I liked the cleanliness of the code:

$scope.objects = ObjectAdmin.query();

And as it automatically unwraps the promise, the data updates correctly on the view side, and everything works fine. But I started playing with Angular 1.3 and it no longer does this. Now you have to call:

ObjectAdmin.query().$promise.then(function(data){ $scope.objects = data; })

Which is just ugly. But I guess the team at Angular made the decision for a good reason, but I have to update all of my code. Booooo!!!

This became painfully obvious when attempting to group a multiple select options by a property that is bound as a foreign key, after the promise has resolved.

You can imagine this data structure:

object: {   name: "Test", objectClass: "a_foreign_key" }

objectClass: { key: "a_foreign_key", name: "Object Type" }

Probably easier to think about in a non abstract way (although, in my current project, "Object" is the actual name of the item I'm dealing with).

person: { id: 1, name: "Jason", professionId: 1 }

profession: { id: 1, name: "Software Developer" }

So, when I get the list of "persons", and the list of "profession", I would grab the reference to the profession referenced by the professionId in the person, then assign it to a new property on each person, $professionRef.

so person 1 would like like this:  { id: 1, name: "Jason", professionId: 1, $professionRef: { id: 1, name: "Software Developer" } }

THEN my select list would use the ng-options to this effect:

ng-options="person.name group by person.$professionRef.name for person in persons track by person.id" ng-model="office.bestSmellingDeveloper"

(The use of $professionRef and $resource no longer automatically removing $ properties on POST/PUT is another pain point for me :)

So at the time the $promise resolves, the select list is like F#@% YEAH DATA!!! And it binds itself, but $professionRef isn't updated yet. So it's not grouping by anything and you have a bland list of things. I use the chosen jquery plugin which just makes these look beautiful with bootstrap of course, and I get bummed when it looks fugly.

I realize this wouldn't have worked as is, even with $promise unwrapping, it all depends on when the SELECT chooses to bind its data, and it would typically be immediately after the promise resolves. Really where this affected the code the most was in the chosen plugin I wrote, which looks like this now that I'm not binding promises to it anymore.

    module.directive("ngChosen", function($parse, $timeout){
        return {
            restrict: "A",
            require: "ngModel",
            link: function(scope, element, attrs, ngModel){

                scope.$watch(attrs["ngChosen"], function(){    
                    $timeout(function(){ element.trigger("chosen:updated"); });
                });

                scope.$watch(attrs["ngModel"], function(){
                    $timeout(function(){ element.trigger("chosen:updated"); })
                });
                element.chosen();
            }
        }
    });

But used to look like this:

    module.directive("ngChosen", function($parse, $timeout){
        return {
            restrict: "A",
            require: "ngModel",
            link: function(scope, element, attrs, ngModel){
                var chosen = scope.$eval(attrs["ngChosen"]);

                if (chosen.$promise) {
                    chosen.$promise.then(function(){ $timeout(function(){ element.trigger("chosen:updated"); }); })
                }
                else {
                    scope.$watch(attrs["ngChosen"], function(){    
                        $timeout(function(){ element.trigger("chosen:updated"); });
                     });
                }

                scope.$watch(attrs["ngModel"], function(){
                    $timeout(function(){ element.trigger("chosen:updated"); })
                });
                element.chosen();
            }
        }
    });

But now that Angular is no longer automatically unwrapping promises... well, I guess I could keep the promise unwrapping in the chosen plugin, just in case I have a simple case that I need to bind to it (hardly ever the case), but since I won't be binding $promise objects to select lists most of the time, I can just say I won't bind any even though it's easy. Because I'll be used to unwrapping them manually to handle cases like the aforementioned.

Enjoy!

blog comments powered by Disqus