A pleasant walk through computing

Comment for me? Send an email. I might even update the post!

New Blog Engine

This is just a short post, primarily to test that my new blogging engine is working. I've written a static site generator that I'll announce in the coming month, as well as post on GitHub (or equivalent).

Happy New Year!

Don't use "data" prefix in AngularJS

I lost a couple of hours over this. When creating a directive or attribute name in AngularJS that will be "kebab-cased," do not prefix it with data, such dataFn or dataFromApi. It becomes data-fn or data-from-api and won't work because data- is reserved by javascript for values.

Note: I'm taking a hard line, here. Such a name might work in some cases--but definitely doesn't when trying to invoke an expression passed to an isolate-scope directive.

This will work.

<!DOCTYPE html>
<html>
<head>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.5/angular.min.js"></script>
</head>
<body ng-app="app">
  <div ng-controller="MyController as vm">
    <button ng-click="vm.alert()">From Body</button>
    <my-directive fn="vm.alert()"></my-directive>
  </div>
</body>
</html>

<script>
  angular.module('app',['MyModule']);

  angular.module('MyModule', [])
    .controller('MyController', MyController)
    .directive('myDirective', myDirective);

  function MyController(){
    var vm = this;
    vm.alert = function(){alert('alert');}
  }

  function myDirective() {
    var directive = {      
      scope: {
        fn: '&'
      },
      template: "<button ng-click='fn()'>From Directive</button>"
    }
    return directive;
  }
</script>

This won't work, because data- is reserved by javascript.

<!DOCTYPE html>
<html>
<head>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.5/angular.min.js"></script>
</head>
<body ng-app="app">
  <div ng-controller="MyController as vm">
    <button ng-click="vm.alert()">From Body</button>
    <!-- data-fn WILL NOT WORK -->
    <my-directive data-fn="vm.alert()"></my-directive>
  </div>
</body>
</html>

<script>
  angular.module('app',['MyModule']);

  angular.module('MyModule', [])
    .controller('MyController', MyController)
    .directive('myDirective', myDirective);

  function MyController(){
    var vm = this;
    vm.alert = function(){alert('alert');}
  }

  function myDirective() {
    var directive = {      
      scope: {
        dataFn: '&'
      },
      template: "<button ng-click='dataFn()'>From Directive</button>"
    }
    return directive;
  }
</script>

This works, using the non-reserved my- prefix.

<!DOCTYPE html>
<html>
<head>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.5/angular.min.js"></script>
</head>
<body ng-app="app">
  <div ng-controller="MyController as vm">
    <button ng-click="vm.alert()">From Body</button>
    <!-- my-fn WORKS -->
    <my-directive my-fn="vm.alert()"></my-directive>
  </div>
</body>
</html>

<script>
  angular.module('app',['MyModule']);

  angular.module('MyModule', [])
    .controller('MyController', MyController)
    .directive('myDirective', myDirective);

  function MyController(){
    var vm = this;
    vm.alert = function(){alert('alert');}
  }

  function myDirective() {
    var directive = {      
      scope: {
        myFn: '&'
      },
      template: "<button ng-click='myFn()'>From Directive</button>"
    }
    return directive;
  }
</script>

AngularJS service with var declarations instead of this. assignments

So I spent a couple of hours trying to figure out why a generally very good Angular sample I thought I'd implemented correctly wouldn't work. Specifically, the service had this code:

sulhome.kanbanBoardApp.service('boardService', function ($http, $q, $rootScope) {

    var getColumns = function () {
        return $http.get("/api/BoardWebApi").then(function (response) {
            return response.data;
        }, function (error) {
            return $q.reject(error.data.Message);
        });
    };

which was called this way in the controller.

sulhome.kanbanBoardApp.controller('boardCtrl', function ($scope, boardService) {
    boardService.getColumns();

The problem is, this doesn't work. The proper way to set a function in a service should look like this:

sulhome.kanbanBoardApp.service('boardService', function ($http, $q, $rootScope) {

    this.getColumns = function () {
        return $http.get("/api/BoardWebApi").then(function (response) {
            return response.data;
        }, function (error) {
            return $q.reject(error.data.Message);
        });
    };

See the difference? this.getColumns, not var getColumns.

So, how was this other guy's code working? It was--I downloaded and ran his sample.

A service is a function with nested functions. He returned the functions in the parent function, like so:

sulhome.kanbanBoardApp.service('boardService', function ($http, $q, $rootScope) {

    var getColumns = function () {
        return $http.get("/api/BoardWebApi").then(function (response) {
            return response.data;
        }, function (error) {
            return $q.reject(error.data.Message);
        });
    };

    return {
            getColumns: getColumns
        };

So far, I haven't seen any other samples do it this way. It works, but...why the extra code step?