Grunt: TypeError at node.js:891

If you ever get this:


node.js:891
var fn = runInThisContext(source, this.filename, true);
^
TypeError: undefined is not a function
at createWritableStdioStream (node.js:555:18)
at process.stdout (node.js:613:16)
at write (something/node_modules/grunt/lib/grunt/log.js:78:12)
at writeln (something/node_modules/grunt/lib/grunt/log.js:85:3)
at Object.log.writeln something/node_modules/grunt/lib/grunt/log.js:96:3)
at writeln (something/node_modules/grunt/lib/grunt/fail.js:39:13)
at Object.fail.fatal (something/node_modules/grunt/lib/grunt/fail.js:55:3)
at process.uncaughtHandler (something/node_modules/grunt/lib/grunt.js:123:10)
at process.EventEmitter.emit (events.js:95:17)
at process._fatalException (node.js:272:26)

Know that you shouldn’t do this:


grunt.registerTask('concat', ['concat']);

That is all.

angular-history: A history (undo/redo) service for AngularJS

We (Decipher) just released version 0.3.0 of this bad boy and now it has support for batching, or transactions, or whatever you want to call it. You can make multiple changes to many models within a context and it will let you undo them all at once, without the headache of receiving 10s or 100s of individual events.

Check it out here: angular-history

AngularJS: Heavy-Handed Anchor Tag Disable Directive

As you may or may not know, the a tag has no disabled attribute, so you can’t use ngDisabled on it like you would on a button. This ends up creating a lot of ngShow/ngHide usages on a tags which just wastes a lot of time and markup.

Behold, a solution. Not necessarily the best one, but it works.

Usage:

<div ng-controller="MyCtrl"> 
  <a ng-click="alert()" a-disabled="true">some link</a>
</div>

And the directive:

var myApp = angular.module('myApp', []);

function MyCtrl($scope) {
    $scope.alert = function () {
        alert('hi');
    };
}



myApp.directive('aDisabled', function ($compile) {
    return {
        restrict: 'A',
        priority: -99999,
        link: function (scope, element, attrs) {
            scope.$watch(attrs.aDisabled, function (val, oldval) {
                if ( !! val) {
                    element.unbind('click');
                } else if (oldval) {
                    element.bind('click', function () {
                        scope.$apply(attrs.ngClick);
                    });
                }
            });
        }
    };
});

This hasn’t been tested much, but basically all this says is “unbind any bound click events if the value of this attribute is true.” This works because the priority is so low, the directive will generally link last.

Would be interested in other solutions as well, especially more elegant ones. :D

Update 1

I realize this thing, once you use it, will never let you re-enable the ngClick. I’ll spend some time on Monday seeing if I can’t find a workaround.

Update 2

Here it is Tuesday and I have a better solution. See above and Fiddle.

My Gruntfile.js: An example Gruntfile and My Workflow

I’m building a site on the MEAN stack; codename Zoltar. To build and run my tasks, I use the wonderful Grunt. I’d like to explore the Gruntfile.js and explain what does what and why I chose to do it that way. Hopefully this example will assist people trying to solve the same (common) problems.

Let’s look at the entire Gruntfile.js, then we can dig into each section.

Continue reading

grunt-contrib-uglify creates invalid source maps

It took me a little while to figure this one out. Uglify2 was uglifying and creating my source maps for sure, but when I looked in the console it would report the wrong line/file.

Until this issue is resolved, you must remove the banner option from your config. In a project of mine, codenamed Zoltar, this is my configuration, which is now working:

    uglify: {
      options: {
        report: 'min',
        sourceMap: 'public/javascripts/dist/<%= pkg.name %>-<%= pkg.version %>.map.js',
        sourceMapRoot: '/',
        sourceMapPrefix: 1,
        sourceMappingURL: '/javascripts/dist/<%= pkg.name %>-<%= pkg.version %>.map.js'
      },
      dist: {
        files: {
           // sources.json is a list of 3rd-party JS libs, in the correct order
           // generated dir is full of ngmin-generated files
          'public/javascripts/dist/<%= pkg.name %>-<%= pkg.version %>.min.js': [
            grunt.file.readJSON('sources.json').concat('public/javascripts/dist/generated/**/*.js')
          ]
        }
      }
    },

Again, you must remove the banner option from the config, until this issue is resolved.

AngularJS & jQuery: Coaxing a $.Deferred out of AngularJS

You probably won’t ever want to do this, but I actually had occasion to as sort of a AngularJS/jQuery bridge.

var myApp = angular.module('myApp', []);
 
$(function () {
    var body = $('body'),
        injector = body.injector(),
        giveMeJQueryPromise = function ($log, $timeout) {
            var dfrd = $.Deferred();
            $log.log('deferring');
            $timeout(angular.noop, 2000).then(function () {
                dfrd.resolve('deferred');
            });
            return dfrd.promise();
        };
    jqpromise = injector.invoke(giveMeJQueryPromise);
    jqpromise.then(function (res) {
        console.log(res);
    });
});

Bonus: working fiddle and example of doing entirely too much without any more markup than an ngApp directive (lives in the body tag).

AngularJS: Service Inheritance

You might want to have services inherit from each other. Here’s a way to do it:

var myApp = angular.module('myApp', []);
 
var baseService = function () {
    this._state = {};
};
baseService.prototype.getState = function () {
    return this._state;
};
baseService.prototype.setState = function (state) {
    this._state = state;
};
 
var chartService = function () {
    this._seriesParam = {};
};
chartService.prototype = Object.create(baseService.prototype);
chartService.prototype.getSeriesParam = function () {
    return this._seriesParam;
};
chartService.prototype.setSeriesParam = function (seriesParam) {
    this._seriesParam = seriesParam;
};
 
myApp.service('baseService', baseService);
myApp.service('chartService', chartService);
 
function MyCtrl($scope, chartService) {
 
    var state = {
        foo: 'bar'
    },
    seriesParam = {
        baz: 'spam'
    };
 
    chartService.setState(state);
    $scope.state = chartService.getState();
 
    chartService.setSeriesParam(seriesParam);
    $scope.seriesParam = chartService.getSeriesParam();
}

Make sure you really want to be doing this though. Dependency injection might serve you just fine.