Code Monkey home page Code Monkey logo

ng-classify's Introduction

ng-classify

License Version Build Status Dependency Status

Convert CoffeeScript classes to AngularJS modules
Write less JavaScript. Write less CoffeeScript. Write less Angular.

Watch the screencast
Demo

Install

Install with npm

$ npm install ng-classify

Usage

CoffeeScript

ngClassify = require 'ng-classify'

content = '''
class Home extends Controller
	constructor: ($log) ->
		$log.info 'homeController instantiated'
'''

angularModule = ngClassify content

JavaScript

var ngClassify = require('ng-classify');

var content = '\
class Home extends Controller\n\
	constructor: ($log) ->\n\
		$log.info \'homeController instantiated\'\
';

var angularModule = ngClassify(content);

Gulp

gulp-ng-classify

$ npm install gulp-ng-classify

Grunt

grunt-ng-classify

$ npm install grunt-ng-classify

Ruby Gem

ng_classify - maintained by pencilcheck

$ gem install ng_classify

Brunch

ng-classify-brunch - maintained by andrejd

$ npm install ng-classify-brunch

Table of Contents

Overview

AngularJS is well suited to take advantage of the CoffeeScript class syntax. However there's still a bit of boilerplate code we have to work through. ng-classify addresses this. Note: all examples are valid CoffeeScript.

Here's how you write a controller using ng-classify

class Admin extends Controller
	constructor: ($scope, someService) ->
		$scope.coolMethod = someService.coolMethod()

which is equivalent to

angular.module('app').controller('adminController', ['$scope', 'someService', function ($scope, someService) {
	$scope.coolMethod = someService.coolMethod();
}]);

Why?

Take the following typical AngularJS controller declaration (same as above)

angular.module('app').controller('adminController', ['$scope', 'someService', function ($scope, someService) {
	$scope.coolMethod = someService.coolMethod();
}]);

So what's wrong with this?

  • App name, angular.module('app').controller, is required within the declaration
    • some avoid this by the use of a global variable, app.controller, which is not good JavaScript hygiene
  • Parameter names are duplicated, one for the getters, '$scope', 'someService', and one for the function parameters, function ($scope, someService)
    • this duplication is required to make the module minifiable
    • some avoid this by the use of ngmin
  • Depending upon the desired naming format, module type (controller) and module name (adminController) have duplication, due to the suffixed controller in this example
  • The function is anonymous (unnamed), making it more difficult to debug
  • Generally verbose

How?

Write AngularJS modules using the following syntaxes. NOTE: {{}} denotes placeholders

class {{appName}} extends {{Animation|Config|Controller|Directive|Factory|Filter|Provider|Run|Service}}
	constructor: ({{params}}) ->
		# module body here

or

class {{name}} extends {{App|Constant|Value}}
	constructor: ->
		return {{value}}

CoffeeScript Classes

The typical way to use CoffeeScript classes with AngularJS is as follows.

# 203 characters
class AdminController
	constructor: ($scope, someService) ->
		$scope.coolMethod = someService.coolMethod()

angular.module('app').controller 'adminController', ['$scope', 'someService', AdminController]

which is equivalent to

// 177 characters
angular.module('app').controller('adminController', ['$scope', 'someService', function AdminController ($scope, someService) {
	$scope.coolMethod = someService.coolMethod();
}]);

with ng-classify, this is all you need

# 116 characters
class Admin extends Controller
	constructor: ($scope, someService) ->
		$scope.coolMethod = someService.coolMethod()

Benefits

  • Removes unnecessary ceremonial code (angular.module('app'))
  • App name is not required when writing a module. It is now configurable.
  • Parameters are needed only once via the constructor function. No need for the array syntax to make your code minifiable.
  • No need to suffix the module name with the module type, e.g. myController, myCtrl, etc.
  • The function is named, making debugging more convenient
  • The syntax is arguably concise. Bring your code to the forefront with the elimination of cruft.

Considerations

  • To avoid the use of global variables, it is advised to use the bare: false CoffeeScript compilation option. see CoffeeScript Usage

Controller As Syntax

AngularJS provides two styles for writing and consuming controllers

  1. $scope
  2. this with Controller as

$scope example

class Admin extends Controller
	constructor: ($scope, someService) ->
		$scope.coolMethod = someService.coolMethod()

view for $scope example

<div ng-controller="adminController">
	<button ng-click="coolMethod()">Cool It Down!</button>
</div>

this example

class Admin extends Controller
	constructor: (someService) ->
		@coolMethod = someService.coolMethod()

view for this example

<div ng-controller="adminController as controller">
	<button ng-click="controller.coolMethod()">Cool It Down!</button>
</div>

Module Types

App

Although there is no AngularJS App module type, it is included for consistency.

class App extends App
	constructor: ->
		return [
			'ngAnimate'
			'ngRoute'
		]

equivalent to

angular.module('app', [
	'ngAnimate',
	'ngRoute'
]);

You may wish to use the then CoffeeScript syntax to highlight your code even more by eliminating the need for extra lines of code and indentation, as follows. Note: this can be leveraged for any CoffeeScript class.

class App extends App then constructor: -> return [
	'ngAnimate'
	'ngRoute'
]

Note: the app name is configured via the appName option, not the class name

Animation

class MyCrazyFader extends Animation
	constructor: ->
		return {
			enter: (element, done) ->
				# run the animation here and call done when the animation is complete

				cancellation = (element) ->
					# this (optional) function will be called when the animation
					# completes or when the animation is cancelled (the cancelled
					# flag will be set to true if cancelled).
		}

equivalent to

angular.module('app').animation('.my-crazy-fader', [function MyCrazyFader () {
	return {
		enter: function (element, done) {
			// run the animation here and call done when the animation is complete

			var cancellation = function (element) {
				// this (optional) function will be called when the animation
				// completes or when the animation is cancelled (the cancelled
				// flag will be set to true if cancelled).
			};

			return cancellation;
		}
	};
}]);

Config

class Routes extends Config
	constructor: ($routeProvider) ->
		$routeProvider
		.when '/home',
			controller: 'homeController'
			templateUrl: 'home.html'
		.when '/about',
			controller: 'aboutController'
			templateUrl: 'about.html'
		.otherwise
			redirectTo: '/home'

equivalent to

angular.module('app').config(['$routeProvider', function Routes ($routeProvider) {
	$routeProvider
	.when('/home', {
		controller: 'homeController',
		templateUrl: 'home.html'
	})
	.when('/about', {
		controller: 'aboutController',
		templateUrl: 'about.html'
	})
	.otherwise({
		redirectTo: '/home'
	});
}]);

Constant

class HttpStatusCodes extends Constant
	constructor: ->
		return {
			'401': 'Unauthorized'
			'403': 'Forbidden'
			'404': 'Not Found'
		}

equivalent to

angular.module('app').constant('HTTP_STATUS_CODES', {
	'401': 'Unauthorized',
	'403': 'Forbidden',
	'404': 'Not Found'
});

Controller

The example below uses the this syntax

class Home extends Controller
	constructor: (userService) ->
		@save = (username) ->
			userService.addUser username

equivalent to

angular.module('app').controller('homeController', ['userService', function Home (userService) {
	this.save = function (username) {
		return userService.addUser(username);
	};
}]);

Directive

class Dialog extends Directive
	constructor: ->
		return {
			restrict: 'E'
			transclude: true
			templateUrl: 'dialog.html'
		}

equivalent to

angular.module('app').directive('dialog', [function Dialog () {
	return {
		restrict: 'E',
		transclude: true,
		templateUrl: 'dialog.html'
	};
}]);

Factory

class Greeting extends Factory
	constructor: ($log) ->
		return {
			sayHello: (name) ->
				$log.info name
		}

equivalent to

angular.module('app').factory('Greeting', ['$log', function Greeting ($log) {
	return {
		sayHello: function (name) {
			$log.info(name);
		}
	};
}]);

Another nice feature is the ability to return classes

class User extends Factory
	constructor: ($log) ->
		return class UserInstance
			constructor: (firstName, lastName) ->
				@getFullName = ->
					"#{firstName} #{lastName}"

usage

user = new User 'Cary', 'Landholt'
fullName = user.getFullName() # Cary Landholt

Filter

class Twitterfy extends Filter
	constructor: ->
		return (username) ->
			"@#{username}"

equivalent to

angular.module('app').filter('twitterfy', [function Twitterfy () {
	return function (username) {
		return '@' + username;
	};
}]);

Provider

class Greetings extends Provider
	constructor: ($log) ->
		@name = 'default'

		@$get = ->
			name = @name

			sayHello: ->
				$log.info name

		@setName = (name) ->
			@name = name

equivalent to

angular.module('app').provider('greetingsProvider', ['$log', function Greetings ($log) {
	this.name = 'default';

	this.$get = function () {
		var name = this.name;

		return {
			sayHello: function () {
				return $log.info(name);
			}
		};
	};

	this.setName = function (name) {
		return this.name = name;
	};
}]);

Run

class ViewsBackend extends Run
	constructor: ($httpBackend) ->
		$httpBackend.whenGET(/^.*\.(html|htm)$/).passThrough()

equivalent to

angular.module('app').run(['$httpBackend', function ViewsBackend ($httpBackend) {
	$httpBackend.whenGET(/^.*\.(html|htm)$/).passThrough();
}]);

Service

class Greeting extends Service
	constructor: ($log) ->
		@sayHello = (name) ->
			$log.info name

equivalent to

angular.module('app').service('greetingService', ['$log', function Greeting ($log) {
	this.sayHello = function (name) {
		return $log.info(name);
	};
}]);

Value

class People extends Value
	constructor: ->
		return [
			{
				name: 'Luke Skywalker'
				age: 26
			}
			{
				name: 'Han Solo'
				age: 35
			}
		]

equivalent to

angular.module('app').value('people',
	[
		{
			name: 'Luke Skywalker',
			age: 26
		}, {
			name: 'Han Solo',
			age: 35
		}
	]
);

Multiple Apps

Although using multiple apps in an AngularJS application is unnecessary, some may still wish to do so.

Simply provide the app name as a parameter to the module type.

In the example below, a Controller is created within the 'common' app.

class Home extends Controller('common')
	constructor: ($log) ->
		$log.info 'homeController instantiated'

equivalent to

angular.module('common').controller('homeController', ['$log', function ($log) {
	$log.info('homeController instantiated');
})];

API

ngClassify(content, options)

content

Required
Type: String
Default: undefined

The content that may contain CoffeeScript classes to convert to AngularJS modules

options

Type: Object
Default: undefined

options.appName

Type: String
Default: 'app'

The name of the AngularJS app

// for example
angular.module('app')
options.prefix

Type: String
Default: ''

To avoid potential collisions, the moduleType prefix may be set (ex: options.prefix = 'Ng')

class Home extends Ng.Controller
	constructor: ($log) ->
		$log.info 'homeController instantiated'
options.animation

Type: Object
Default: {format: 'spinalCase', prefix: '.'}

options.constant

Type: Object
Default: {format: 'screamingSnakeCase'}

options.controller

Type: Object
Default: {format: 'camelCase', suffix: 'Controller'}

options.directive

Type: Object
Default: {format: 'camelCase'}

options.factory

Type: Object
Default: {format: 'upperCamelCase'}

options.filter

Type: Object
Default: {format: 'camelCase'}

options.provider

Type: Object
Default: {format: 'camelCase'}

options.service

Type: Object
Default: {format: 'camelCase', suffix: 'Service'}

options.value

Type: Object
Default: {format: 'camelCase'}

Supported Formats

Format Example
  • | no change camelCase | camelCase lowerCamelCase | lowerCamelCase lowerCase | lowercase screamingSnakeCase | SCREAMING_SNAKE_CASE snakeCase | snake_case spinalCase | spinal-case trainCase | Train-Case upperCamelCase | UpperCamelCase upperCase | UPPERCASE

Contributing

See CONTRIBUTING.md

Changelog

See CHANGELOG.md

License

See LICENSE

ng-classify's People

Contributors

carylandholt avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ng-classify's Issues

How can I write this Factory with ng-classes?

I have this Factory:

  .factory('ItemService', [function() {
    var items = [
      {id: 1, label: 'Item 0'},
      {id: 2, label: 'Item 1'}
    ];
    return {
      list: function() {
        return items;
      },
      add: function(item) {
        items.push(item);
      }
    };

I try in this way but it doesn't work.


class ItemService extends Factory
  constructor: ->
    return {
      items: [
        {id: 1, label: 'Item 0'},
        {id: 2, label: 'Item 1'}
      ]
      list: () ->
        @items
      add: (item) ->
        @items.push(item) 
    }

My controller is

class Main extends Controller
  constructor: ->
    @tab = 'first'

    @open = (tab) =>
      @tab = tag

class Sub extends Controller
  constructor: (ItemService) ->
    @list = () =>
      return ItemService.list
    @add = () =>
      console.log('pippo')

Can you help me?

Run not working properly

Hi,

I have been trying this and looks amazing, thanks.

I have a problem when using it for "RUN"

Here is the code that breaks:

class onLoad extends Run

  constructor: ->

    @ey()

  ey: =>
    console.log 'working'

this(@) refers to Window by the way using this syntax

Add prefix option to moduleTypes (extends)

This can help avoid potential class collisions

class Home extends Ng.Controller
  constructor: ->
    console.log 'homeController instantiated'

options.prefix = 'Ng' or options.prefix = 'Ng.' or options.prefix = 'Ng.My'

Trouble with Provider

Hi,

It's been a year and half since I had the chance to use ng-classify and coffeescript... I seem to be having an issue and can't figure it out.

this is my ng-classify code

# create module
class App extends App('common')
  constructor: ->
    return []

# create provider
class commonConfig extends Provider('common')
  constructor: ->
    @config = {}

    @$get = ->
      { config: @config }

# create the factory 'common'
class common extends Factory('common')
  constructor: ($q, $rootScope, $timeout, commonConfig, logger) ->
    service =
      $broadcast: $broadcast
      $q: $q
      $timeout: $timeout
      logger: logger
      activateController: activateController

    # passthrough of the angular $broadcast service
    $broadcast = ->
      $rootScope.$broadcast.apply $rootScope, arguments

    # global function used to activate a controller once all promises have completed
    activateController = (promises, controllerId) ->
      $q.all(promises).then (eventArgs) ->
        data = controllerId: controllerId
        $broadcast commonConfig.config.controllerActivateSuccessfulEvent, data
        # hide the workingOnIt animation
        #$broadcast commonConfig.config.workingOnItToggleEvent, { show: false }

    return service

which consistently throws a provider issue of commonConfigProvider. yet when I use plain js it works

(function () {
  'use strict';

    // create module
    angular.module('common', [])
    // create provider
    .provider('commonConfig', function () {
        this.config = {};

        this.$get = function () {
            return {
                config: this.config
            };
        };
    })
    // create the factory 'common'
    .factory('common', ['$q', '$rootScope', '$timeout', 'commonConfig', 'logger', common]);

    // function factory 'common'
    function common($q, $rootScope, $timeout, commonConfig, logger) {
        var service = {
                // passthough common angular dependencies
                $broadcast: $broadcast,
                $q: $q,
                $timeout: $timeout,
                // my services
                logger: logger,
                activateController: activateController
            };

        return service;

        // passthrough of the angular $broadcast service
        function $broadcast() {
            return $rootScope.$broadcast.apply($rootScope, arguments);
        }

        // global function used to activate a controller once all promises have completed
        function activateController(promises, controllerId) {
            return $q.all(promises).then(function(eventArgs) {
                var data = { controllerId: controllerId };
                $broadcast(commonConfig.config.controllerActivateSuccessfulEvent, data);
                // hide the workingOnIt animation
                //$broadcast(commonConfig.config.workingOnItToggleEvent, { show: false });
            });
        }
    }
})();

am I missing something? I've spent hours troubleshooting this :(

Bower

I would like bower support, so I can more easily use this with rails (https://rails-assets.org) - the rails gem is out of date, and even if it is updated, it will most likely not be updated in the future. This makes rails-usage much easy.

I made a pull request for this, you can accept it to allow

bower install ng-classify

or in rails:

source 'https://rails-assets.org' do
  gem 'rails-assets-ng-classify', '~> X.X'
end

Thanks!

Accept content other than a single class

cube = (x) ->
  x * x * x

class Home extends Controller
  constructor: ($log) ->
    $log.info 'homeController instantiated'
    $log.info cube(3)

The docs read ngClassify(coffeeScriptClass, options)

Should read ngClassify(content, options)

Classes, method and Constructor...

I have a quick question about ng-classify. Let's take this Service

class Item extends Service
  constructor: ->
      @items = [
        {id: 1, label: 'Item 0'}
        {id: 2, label: 'Item 1'}
      ]

      @list = ->
        @items

      @add = (item) ->
        @items.push item

I cannot understand why everything is inside the constructor...
Is this wrong?

class Item extends Service
  constructor: ->
      @items = [
        {id: 1, label: 'Item 0'}
        {id: 2, label: 'Item 1'}
      ]
      @list()
      @add(item)


  list = ->
    @items

  add = (item) ->
   @items.push item

Chaining

Great module, I like the idea of less code. One question though, is there the ability to chain?

Say I have this:

angular.module( 'sailng.users', [])

.config( ['$stateProvider',function config( $stateProvider ) {
    $stateProvider.state( 'users', {
        url: '/users',
        views: {
            "main": {
                controller: 'UserCtrl',
                templateUrl: 'users/index.tpl.html'
            }
        },
        data:{ pageTitle: 'User' }
    });
}])

.controller( 'UserCtrl',['$scope', '$sails', 'lodash', 'config', 'titleService', 'UserModel','$filter', 'ngTableParams', function UserController( $scope, $sails, lodash, config, titleService, UserModel,$filter, ngTableParams ) {

    ...

}]);

is it possible to chain .module().config().controller() with this module?

Thanks

add a CLI

It would be good if this tool had a CLI. I can write one and PR it, the only thing that id like feedback on is how you would like the options to translate into arguments. Im thinking something like

./ngclassify --controller-format=camel --controller-suffix=Poop --value-format=none app-name=my.app ./input.coffee ./output.js 

Support for Browserify

I'm currently creating an Angular app in CoffeeScript and I use Browserify for module loading, the problem is that it doesn't work with ng-classify, so I thought that this could be possible:

before:

module.export = class Admin extends Controller
  constructor: ($scope) ->

ng-classified:

class Admin
  constructor: ($scope) ->

module.export = angular.module('app').controller 'adminController', ['$scope', Admin]

Resolve dependency injection

When using resolve for ex with the "messages" var.. throws DI error.. because its loaded in the array as a dependency.. but its not.

Is there a way of avoiding this?
Thanks!

ex:

resolve:
lives: (LiveService) ->
LiveService.getAll()

class Home extends Controller
constructor: ($scope, $state, Faye, authenticationService, lives)

turns into

['$scope', '$state', 'Faye', 'authenticationService', 'lives' ...]

Object-Oriented Coffee-script

Hi,

One thing that I miss from other projects (no-angular) is the possibility to create others functions that are siblings of the constructor. Right now I put everything inside the constructor.

It kinds of works with controllers if I define every dependency again (@scope = $scope), but inside functions that have a return inside (directives) it's impossible to do.

Do you know any clean way to do it? It would improve the quality for the code a lot and I have not seen it in any angular project yet, ever. I know it has probably anything to do with ng-classify but it's the closest approach in that direction.

Installation question

Great concept!

I installed ng-classify with npm but I am unclear how to use it. How does it get recognized by the CoffeeScript compiler?

feat: add option that allows you to wrap/transform the class being registered

It would be very useful to us to be able to add new methods, etc to controllers (and perhaps services/factories) that are being registered with angular.

I propose changing this lib the property DI style: MyController.$inject = ['$scope', 'greeter']; so that this can also be transformed, then provide an option to transform all classes:

controller:
  format: 'camelCase'
  suffix: 'Controller'
  transform: (className, obj) ->  obj

i realize that this would mean that this same transform function would have to be included in all the boiler plate code output by ng-classify - this kind of sucks, but maybe I can just attach that transform function on to window.angular or find some other optimization. Even without the optimization, I think this provides us with a great way to solve some cross cutting issues at a small cost of file size

What if i work with multiple modules ?

Thank you for ng-classify, really useful
extends a controller or a service for exemple, will generate only one module name
but in my case i am working on multiple modules, and it will be useful if you develop the
configuration/options side, so then we can define a prefix for every module name

best regards.

Exemple:

App.controller => angular.module('app')
Dashboard.controller => angular.module('dashboard')

istambul, ibrik, coverage, etc

Hi Cary,

Do you have any method, on how you would do test coverage with karma and ng-classify?

I can get coverage with the compiled js, and I'm trying to do the same with the coffee script file directly, to get a nice report, with annotated coffeescript files, but I miss the karma-ng-classify-preprocessor...

bug: provider default formatting incorrect

you have

provider:
  format: 'camelCase'
  suffix: 'Provider'

So if I create a provider like this class Foo extends Provider ng-classify will register it as fooProvider, but angular will register it as fooProviderProvider because it also appends Provider to provider names!

You can try this yourself, create a provider with default settings and try to inject it as fooProvider - it will not be found.

Router not being called.

Hi There,

So I've been having trouble when trying to run my app after compilation.

At the moment I'm keeping all my coffee classes in separate files then using gulp to ngClassify() then concat all the files together which compiles to the following script:

var App;

App = (function() {
  function App() {
    return ['firebase', 'ngRoute'];
  }

  return App;

})();

angular.module('app', new App());

var Routes;

Routes = (function() {
  function Routes($locationProvider, $routeProvider) {
    $locationProvider.html5Mode(true);
    $routeProvider.when('/', {
      templateUrl: 'views/home.html',
      controller: 'homeController'
    }).when('/project/:id', {
      templateUrl: 'views/project.html',
      controller: 'projectController'
    }).otherwise({
      templateUrl: 'views/404.html'
    });
  }

  return Routes;

})();

angular.module('app').config(['$locationProvider', '$routeProvider', Routes]);

var Home;

Home = (function() {
  function Home($scope) {
    $scope.controller = this;
  }

  return Home;

})();

angular.module('app').controller('homeController', ['$scope', Home]);

var Project;

Project = (function() {
  function Project($scope, $routeParams, $firebaseObject) {
    var ref, url;
    $scope.controller = this;
    url = 'https://scorching-fire-8072.firebaseio.com/projects/' + $routeParams.id;
    ref = new Firebase(url);
    $scope.data = $firebaseObject(ref);
  }

  return Project;

})();

angular.module('app').controller('projectController', ['$scope', '$routeParams', '$firebaseObject', Project]);

This looks all good to me but maybe I'm missing something silly here?

Hope you can help!

Thanks,
Scott.

ProviderProvider

Hi Cary,

class Greetings extends Provider

generates:

angular.module('app').provider('greetingsProvider', ['$log', function Greetings ($log) {

I think it should generate:

angular.module('app').provider('greetings', ['$log', function Greetings ($log) {

So that I dont have to configure it with

angular.module('app').config (gretingsProviderProvider) ->

Usually, providers are used to generate configurable services, so we may want to actually generate

angular.module('app').provider('greetingsService', ['$log', function Greetings ($log) {

Unclear documentation for factory

Hi,

After changing almost everything to classify I found that the most difficult part was using Factories.

I ended up using the same syntax as directives. It's the best way to do it?

class test extends Factory

  constructor: ($http, $q, $location) ->

    return {
      search: (query) ->
         # console.log 'search...', query
    }

update docs to include info about mixin best practice

I am interested in your take on how to use this tool with a mixin provider to allow me to have a BaseController that also uses ng-classify. I tried having the base controller extend Controller and concrete controllers extend the base, but that does not work.

The next thought is to use a mixin to augment the the classes that extend Controller.

I think that this is a common use-case with using this tool and I would be interested to know what your take on an implementation would be

demo site

your demo site is down on cloud 9

Problems with requirejs

If I wrap this code

class Admin extends Controller('app.controllers')
    constructor: ($scope, someService) ->
        $scope.coolMethod = someService.coolMethod()

in requirejs

define( ->
  class Admin extends Controller('app.controllers')
    constructor: ($scope, someService) ->
      $scope.coolMethod = someService.coolMethod()
)

compiler will generate smth like this:

define(function() {
  var Admin;
  return Admin = (function(_super) {
    __extends(Admin, _super);

    function Admin($scope, someService) {
      $scope.coolMethod = someService.coolMethod();
    }

    return Admin;

  })(Controller('app.controllers'));
});

Is it possible to generate the same code as before implementing requirejs but in it's wrapper?

The "last" question about Factory (I hope)

Finally I understand how to use ng-classify and it's great. I create with success some controller and some services, but I still have some issue with the Factory.

I try to convert this Factory in coffeescript with ng-classify

angular.module('myApp.services', ['myApp.config'])
// DB wrapper
.factory('DB', function($q, DB_CONFIG) {
    var self = this;
    self.db = null;

    self.init = function() {
        // Use self.db = window.sqlitePlugin.openDatabase({name: DB_CONFIG.name}); in production
        self.db = window.openDatabase(DB_CONFIG.name, '1.0', 'database', -1);

        angular.forEach(DB_CONFIG.tables, function(table) {
            var columns = [];

            angular.forEach(table.columns, function(column) {
                columns.push(column.name + ' ' + column.type);
            });

            var query = 'CREATE TABLE IF NOT EXISTS ' + table.name + ' (' + columns.join(',') + ')';
            self.query(query);
            console.log('Table ' + table.name + ' initialized');
        });
    };

    self.query = function(query, bindings) {
        bindings = typeof bindings !== 'undefined' ? bindings : [];
        var deferred = $q.defer();

        self.db.transaction(function(transaction) {
            transaction.executeSql(query, bindings, function(transaction, result) {
                deferred.resolve(result);
            }, function(transaction, error) {
                deferred.reject(error);
            });
        });

        return deferred.promise;
    };

    self.fetchAll = function(result) {
        var output = [];

        for (var i = 0; i < result.rows.length; i++) {
            output.push(result.rows.item(i));
        }

        return output;
    };

    self.fetch = function(result) {
        return result.rows.item(0);
    };

    return self;
})

My Factory is:

class DatabaseFactory extends Factory 

  constructor: ($q, DBCONFIG) ->
    return {

      init: () ->
        @db = window.openDatabase(DBCONFIG.name, "1.0", "database", -1)
        angular.forEach DBCONFIG.tables, (table) ->
          columns = []
          angular.forEach table.columns, (column) ->
            columns.push column.name + " " + column.type
            return
          execute_query = "CREATE TABLE IF NOT EXISTS " + table.name + " (" + columns.join(",") + ")"
          query(execute_query)
          console.log "Table " + table.name + " initialized"
          return

      query: (query, bindings) ->
        bindings = (if typeof bindings isnt "undefined" then bindings else [])
        deferred = $q.defer()
        @db.transaction (transaction) ->
          transaction.executeSql query, bindings, ((transaction, result) ->
            deferred.resolve result
            return
          ), (transaction, error) ->
            deferred.reject error
            return

          return

        deferred.promise

      fetchAll: (result) ->
        output = []
        i = 0

        while i < result.rows.length
          output.push result.rows.item(i)
          i++
        output

      fetch: (result) ->
        result.rows.item 0

    }

It doesn't work: `Uncaught ReferenceError: query is not defined``

If I use a service everything works but I cannot understand why I can't call query from init.

Lost "this" reference in factory method when I tried to "ng-classify" it.

I am sure this is a simple issue, but confusing nonetheless. I have an angular factory that I am trying to "ng-classify". The existing code looks something like this:

app.factory 'Data', [
  '$log'
  "$q'
  ($log, $q) ->
    getData1: ->
      data1 = $q.defer()
      . . .
      return data1.promise
    getData2: ->
      data2 = $q.defer()
      . . .
      return data2.promise
    getSomeComboData: ->
       comboData = $q.defer()
      $q.all(@getData1, @getData2).then (Data1, Data2) ->
      . . . 
      return ComboData.promise
    . . .
    ]

This works. No problem. Sometimes my controllers need Data1, sometimes Data2, sometimes ComboData. I can imagine other scenarios where a factory method might need to call another public method of the same factory.

This is what I did to "ng-classify" it:

class Data extends Factory
  constructor:  ($log, $q) ->
    return: {
      getData1: ->
        data1 = $q.defer()
        . . .
        return data1.promise
      getData2: ->
        data2 = $q.defer()
        . . .
        return data2.promise
      getSomeComboData: ->
        comboData = $q.defer()
        $q.all(@getData1, @getData2).then (Data1, Data2) ->
        . . . 
        return ComboData.promise
    . . .
    }

The problem is now @getdata1 and @getdata2 are undefined. Somehow the "this" reference to the factory singleton has been lost. Am I missing something?

proposal for multi module support

Hi, Cary

We are looking at using ng-classify in buildbot, but we are not very happy about the filePath based approach

what about something with a syntax like:

class Home extends buildbot.common.Controller
constructor: ($log) ->
$log.info 'homeController instantiated'

or:

class Home extends Controller("buildbot.common")
constructor: ($log) ->
$log.info 'homeController instantiated'

which are both "valid" coffee syntax

Return original content if ng-classify pattern is not found

Anything other than the following two patterns should return the original content.

class {{appName}} extends {{App|Animation|Config|Controller|Directive|Factory|Filter|Provider|Run|Service}}
    constructor: ({{params}}) ->
        # module body here
class {{name}} extends {{App|Constant|Value}}
    @constructor = {{value}}

Currently an exception is thrown.

Provider 'xxx' must return a value from $get factory method.

I'm trying to "classify" an existing angular factory, and I am not sure I understand what this is telling me. This is how it was originally written in coffeescript:

'use strict';

angular.module('App')
.factory 'Data', [
  '$log'
  '$q'
  ($log, $q) -> 

    openDB : ->
      db = new PouchDB 'myDB'
      return db

    getDB: ->
      db = $q.defer()
      db = @openDB()
      db.allDocs {include_docs: true}, (err, res) ->
        if err
          $log.log err
          db.resolve err
        else
          db.resolve res.rows
      return db.promise

#[and so on]

It goes on in the same vein with all the usual CRUD functions like findRecord, addRecord, etc. It works fine, but I wanted to "classify" this code to better encapsulate it for future reuse.

this is how I rewrote it:

class Data extends Factory
  constructor: ($log, $q) ->
    openDB : ->
      db = new PouchDB 'myDB'
      return db

    getDB: ->
      db = $q.defer()
      db = @openDB()
      db.allDocs {include_docs: true}, (err, res) ->
        if err
          $log.log err
          db.resolve err
        else
          db.resolve res.rows
      return db.promise

#[and so on]

However, I am getting the following error:

 Provider 'Data' must return a value from $get factory method.

I'm not sure I understand what is going wrong, and the examples in the API reference do not show a factory with more than one method. Can you help me understand how the classify utility would handle this?

Does not handle nested classes

class A extends Controller
    constructor: (aa, ab) ->
        return class AA extends Service
            constructor: (aaa) ->
                console.log 'perms'

I cannot understand how to use api

I cannot understand how to use the api.

For example: now the Setting controller becomes "settingController". I want to change it to "SettingCrtl"

I see the options, but I don't understand how I can override the default behaviour!

Roberto

AngularJS 1.4

Hi,

It looks like ng-classify breaks with the latest version of angular. I think that it's a error related to the nature of coffee-script.

With the new Angular, for example a directive returns the last function in the Directive

class Some extends Directive

    constructor: ->
        return {

            controller: ($scope) ->
                $scope.someFunction = ->
        }

That will return the function $scope.someFunction and not the whole directive for some reason. But if returning the directive at the end then it works

class Some extends Directive

    constructor: ->
        return {

            controller: ($scope) ->
                $scope.someFunction = ->

                return
        }

JSHint complains "Missing 'new' prefix when invoking a constructor." for App module type

The following:

class App extends App
  constructor: ->
    return []

results in:

var App;

App = (function() {
  function App() {
    return [];
  }

  return App;

})();

angular.module('app', App());

Because App is a constructor function and begins with a capital letter, JSHint expects it to be called with the new keyword.

The following is the expected, JSHint-friendly, output:

var App;

App = (function() {
  function App() {
    return [];
  }

  return App;

})();

angular.module('app', new App());

See http://jshint.com/docs/options/#newcap

Thanks @chasm

Need to add App module to requirement or check if module has registered

I put example controller to check how it works and have been suprised. It was angular error

class Projects extends Controller
  constructor: ($scope) ->
    $scope.init ->
      console.log 'Hello World!'
Uncaught Error: [$injector:nomod] Module 'todo_list' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure that you specify the dependencies as the second argument.
http://errors.angularjs.org/1.3.0-build.3042+sha.76e57a7/$injector/nomod?p0=todo_list

It happen because module was without dependency

angular.module('todo_list').controller('ProjectsCtrl', ['$scope', Projects]);

It requires to create App module with it and not truly documented on usage section
https://github.com/CaryLandholt/ng-classify#coffeescript

It works!

class App extends App
  constructor: ->
    return []

class Projects extends Controller
  constructor: ($scope) ->
    $scope.init ->
      console.log 'Hello World!'

Oh, I've checked down. This section also does not work
https://github.com/CaryLandholt/ng-classify#multiple-apps

class Home extends Controller('common')
    constructor: ($log) ->
        $log.info 'homeController instantiated'
Uncaught Error: [$injector:nomod] Module 'common' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure that you specify the dependencies as the second argument.
http://errors.angularjs.org/1.3.0-build.3042+sha.76e57a7/$injector/nomod?p0=common

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.