A pleasant walk through computing

Home

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?

Newer   Older