I don't write good

I mean, I could, if I really cared about the writing I would sit and think up some points, counterpoints, develop a story, engage the reader.

But instead, I spend that time and effort writing code and I just want to put code samples up with some description of what's going on, so my writing has taken a severe hit over the past decade or so. Although I was reading through some of my old posts and some genuinely made me laugh out loud.  So I write for me, is one aspect of it. Also I structure some sentences weirdly... "So I write for me, is one aspect of it".  This is just evidence of a severe lack of thought process in writing. However, I believe my code is pretty nice.

I remember a writing class I took in college, I had started out, my first paper was a D+ or C-, something bad like that. These were 4-5 page papers on whatever subject with a pre-determined theme. By the end of the semester, I was cranking out As because I learned so much about writing in such a short time. That professor was very good, and I forget his name.

All memories of what I learned in that class are long gone, and you're stuck with dealing with unstructured ramblings with snippets of code strewn about, but at least the image at the top of the page changes every time you refresh the page. So life goes on.

Getting Around Angular Bootstrap Popover Limitations

Using Bootstrap is nice, it's got some good default behaviors and components set up for quickly building a decent looking web application. However, the Angular Bootstrap tools are a little bit behind.

For instance, I was using the popover in my latest project. There is no way that I could find to bind HTML to the body part of the code, like so:

<div popover="Title" popover-content="<strong>Content</strong>"> ... </div>

So, not wanting to change how the popover looks, but at the same time not liking how it was working as an Angular directive, I rolled my own. For now, I just wanted to get it to work and also include HTML in the body, so I hard coded some things, like the fact that for now, I only expect it to show up on the right side of the thing I'm popping it over.

    module.directive("infobox", function(){
        return {
            restrict: "E",
            transclude: true,
            scope: { title: "=", content: "=" },
            template: "<div ng-transclude class='infobox popover right' style='position: absolute; display: none'></div>",
            controller: function($scope){

            },
            link: function(scope, element, attrs){
                var parentWidth = element.parent().outerWidth();
                var infobox = element.find(".infobox");
                infobox.append("<div class='arrow'></div>")
                element.parent()
                    .on("mouseover", function(){
                        var t = angular.element(this);
                        var offset = t.offset(); offset.left += parentWidth;
                        var h = t.outerHeight() / 2;
                        offset.top = offset.top - (infobox.outerHeight() / 2) + h;
                        t.find("div.infobox").show().offset(offset);
                    })
                    .on("mouseout", function(){
                        var t = angular.element(this);    
                        t.find(".infobox").hide();
                    });             }
        }
    });     module.directive("infoboxTitle", function(){
        return {
            restrict: "E",
            transclude: true,
            require: "^infobox",
            template: "<div ng-transclude class='popover-title'></div>"
        }
    })

    module.directive("infoboxBody", function(){
        return {
            restrict: "E",
            transclude: true,
            require: "^infobox",
            template: "<div ng-transclude class='popover-content'></div>"
        }
    })

Then I use it like this:

         <infobox>
             <infobox-title>{{obj.name}}</infobox-title>
             <infobox-body>
                <p>{{obj.description}}</p>
                <div ng-repeat="(key, val) in obj.attributes">
                    <strong>{{lookupAttributeName(key)}}</strong>: {{val}}
                </div>             
            </infobox-body>
         </infobox>

It generates markup that looks like this, and that works

<infobox class="ng-isolate-scope"><div ng-transclude="" class="infobox popover right" style="position: absolute; display: none; top: -73.5px; left: 241px;">
             <infobox-title class="ng-scope"><div ng-transclude="" class="popover-title"><span class="ng-binding ng-scope">Medium Truck</span></div></infobox-title>
             <infobox-body class="ng-scope"><div ng-transclude="" class="popover-content">
                <p class="ng-binding ng-scope">The medium truck</p>
                <!-- ngRepeat: (key, val) in obj.attributes --><div ng-repeat="(key, val) in obj.attributes" class="ng-binding ng-scope">
                    <strong class="ng-binding">Capacity</strong>: 60
                </div><!-- end ngRepeat: (key, val) in obj.attributes --><div ng-repeat="(key, val) in obj.attributes" class="ng-binding ng-scope">
                    <strong class="ng-binding">Employees Maximum</strong>: 2
                </div><!-- end ngRepeat: (key, val) in obj.attributes --><div ng-repeat="(key, val) in obj.attributes" class="ng-binding ng-scope">
                    <strong class="ng-binding">Employees Minimum</strong>: 1
                </div><!-- end ngRepeat: (key, val) in obj.attributes --><div ng-repeat="(key, val) in obj.attributes" class="ng-binding ng-scope">
                    <strong class="ng-binding">N/A</strong>: 15
                </div><!-- end ngRepeat: (key, val) in obj.attributes --><div ng-repeat="(key, val) in obj.attributes" class="ng-binding ng-scope">
                    <strong class="ng-binding">Miles Per Gallon</strong>: 14
                </div><!-- end ngRepeat: (key, val) in obj.attributes -->             
            </div></infobox-body>
         <div class="arrow"></div></div></infobox>

Don't read too much into what my latest project is :)

Pretty!!

I have made my site a bit prettier.  I brought in bootstrap for some UI elements, like tag list and the year accordions on the right side, as well as the fixed header. I don't know how much more I plan on using Bootstrap for this site though, but I use it a lot in other places.

I was messing around with the fonts and decided I could use big bigger post titles as well as a different overall body text font.

Since I'm not the best with colors, I tend to just pick greyscale and use different combinations of various intensities of grey, black and white to get the job done. The header images are where the color is :)

Enjoy!

Fix for Angular 1.3 $resource Not Stripping $ properties anymore

Version 1:

    module.config(["$httpProvider", function($httpProvider){
        $httpProvider.defaults.transformRequest.unshift( function(data){
            if (typeof data == "object"){
                var remove = [];
                for (var i in data) { if (i.indexOf("$") == 0 && i.indexOf("$$") == -1 && typeof(data[i]) != "function") remove.push(i); }
                remove.forEach(function(k){ delete data[k]; });
            }
            return data;
        });
    }])

Version 2:

    module.config(["$httpProvider", function($httpProvider){
        $httpProvider.defaults.transformRequest.unshift( function(data){
            if (typeof data == "object"){
                var copy = angular.copy(data);
                var remove = [];
                for (var i in copy) { if (i.indexOf("$") == 0) remove.push(i); }
                remove.forEach(function(k){ delete copy[k]; });
                return copy;
            }
            return data;
        });
    }])

Let's examine. There's a bit going on here.

$resource registers its own transformRequest functions before ours is defined, but I want mine to load first.

$httpProvider.defaults.transformRequest.unshift

Unshift puts my method at the beginning. The data at this point is an object, whereas if I were to push it to the end, after the $resource transformRequest function, I get a string. It seems a bit more efficient to work with the object first, than to allow $resource to JSON.stringify the data, then for me to load it up through JSON.parse after.

The main difference between Version 1 and Version 2 is that I copy the object in Version 2 so I can delete any property that begins with $, whereas in Version 1 I skipped deleting functions and properties that Angular needed, but then the reference objects were deleted from my actual object, so the list view got messed up, because it's looking for those properties.  So Version 2 is correct.

I add this to my global module, the one that gets bootstrapped to <html>, so that it only has to be registered once, like so:

;(function(angular){
    var module = angular.module("global.app", [...]);
    module.config(["$httpProvider", function($httpProvider){
        $httpProvider.defaults.transformRequest.unshift( function(data){
            var copy = angular.copy(data);
            if (typeof copy == "object"){
                var remove = [];
                for (var i in copy) { if (i.indexOf("$") == 0) remove.push(i); }
                remove.forEach(function(k){ delete copy[k]; });
            }
            return copy;
        });
    }])
})(angular);

And then bootstrap it 

;(function(angular, document){
    angular.element(document).ready(function(){
        angular.bootstrap(angular.element("html"), ["global.app"]);
    })
})(angular, document);

Simple

 

Chrome 37 Keeps Scroll Position On Page Reload

It's pretty neat, but I mostly refresh a page in order to quickly scroll back to the top without having to use the mouse. My workflow is severely detrimented. Page Up will do I suppose.

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!