{"id":24083286,"url":"https://github.com/mitranim/ng-decorate","last_synced_at":"2025-06-12T16:34:39.721Z","repository":{"id":31473947,"uuid":"35038016","full_name":"mitranim/ng-decorate","owner":"mitranim","description":"[DEPRECATED] ES7 decorators for AngularJS 1.x","archived":false,"fork":false,"pushed_at":"2015-09-29T17:57:44.000Z","size":260,"stargazers_count":27,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-26T06:56:57.054Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mitranim.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-05-04T14:00:46.000Z","updated_at":"2024-02-13T15:40:53.000Z","dependencies_parsed_at":"2022-09-03T16:40:41.677Z","dependency_job_id":null,"html_url":"https://github.com/mitranim/ng-decorate","commit_stats":null,"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mitranim%2Fng-decorate","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mitranim%2Fng-decorate/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mitranim%2Fng-decorate/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mitranim%2Fng-decorate/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mitranim","download_url":"https://codeload.github.com/mitranim/ng-decorate/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251758724,"owners_count":21639096,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-01-09T23:56:17.424Z","updated_at":"2025-04-30T18:23:16.552Z","avatar_url":"https://github.com/mitranim.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"## Description\n\nES7 decorators for Angular 1.x. Help you:\n\n* Get around Angular's dependency injection while using ES6 modules.\n* Make custom directive declarations very short and semantic.\n* Declare bindables directly on class properties.\n\nPerfect for an ES7 / TypeScript application.\n\nThis readme assumes you're already using [`jspm`](http://jspm.io) and `System`,\nand have an ES6 transpilation workflow with [`babel`](https://babeljs.io/) or\n[`typescript`](https://github.com/Microsoft/TypeScript). If not, here's a guide\nto get you started: [[1]](http://mitranim.com/thoughts/next-generation-today/).\n\n## Contents\n\n* [Installation](#installation)\n* [Directives](#directives)\n  * [`@Component`](#component)\n  * [`@Attribute`](#attribute)\n  * [Directive Options](#directive-options)\n* [Services](#services)\n  * [`@Ambient`](#ambient)\n  * [`@Service`](#service)\n  * [`@Controller`](#controller)\n  * [Service Options](#service-options)\n* [Bindings](#bindings)\n  * [`@bindString`](#bindstring)\n  * [`@bindTwoWay`](#bindtwoway)\n  * [`@bindOneWay`](#bindoneway)\n  * [`@bindExpression`](#bindexpression)\n* [`@autoinject`](#autoinject)\n* [`defaults`](#defaults)\n* [Gotcha](#gotcha)\n* [Alternatives](#alternatives)\n\n## Installation\n\nIn shell:\n\n```sh\nnpm i --save-dev ng-decorate\n# or\njspm install npm:ng-decorate\n```\n\nIn app:\n\n```typescript\nimport {Component, bindTwoWay} from 'ng-decorate';\n\n@Component({\n  selector: 'my-accordeon'\n})\nclass X {\n  @bindTwoWay length: number;\n}\n```\n\n## Directives\n\n`ng-decorate` provides two directive shortcuts: custom element (`@Component`)\nand custom attribute (`@Attribute`).\n\n### `@Component`\n\nDefines a custom element: a directive with a template and an isolated scope.\n\nSimplest usage:\n\n```typescript\nimport {Component} from 'ng-decorate';\n\n@Component({\n  selector: 'my-element'\n})\nclass X {}\n```\n\nWith default settings, this expands to:\n\n```typescript\nangular.module('myElement', ['ng']).directive('myElement', function() {\n  return {\n    restrict: 'E',\n    scope: {},\n    templateUrl: 'my-element/my-element.html',\n    controller: X,\n    controllerAs: 'self',\n    bindToController: true\n  };\n});\nclass X {}\n```\n\nSee [`defaults`](#defaults) for customisation.\n\n### `@Attribute`\n\nDefines a custom attribute.\n\nSimplest usage:\n\n```typescript\nimport {Attribute} from 'ng-decorate';\n\n@Attribute({\n  selector: '[my-attribute]'\n})\nclass X {}\n```\n\nWith default settings, this expands to:\n\n```typescript\nangular.module('myAttribute', ['ng']).directive('myAttribute', function() {\n  return {\n    restrict: 'A',\n    scope: false,\n    controller: X\n  };\n});\nclass X {}\n```\n\nSee [`defaults`](#defaults) for customisation.\n\n### Directive Options\n\nThis applies to both `@Component` and `@Attribute`.\n\nAny passed options will be included into the resulting\n[directive definition object](https://docs.angularjs.org/api/ng/service/$compile#directive-definition-object),\nso you can use the standard directive API on top of `ng-decorate`-specific\noptions. Example:\n\n```typescript\n@Component({\n  selector: 'my-element',\n  scope: {myProperty: '='}\n})\n```\n\n#### `selector` `: string`\n\nRequired. This is the selector string for the resulting directive. For\n`@Attribute`, you can optionally enclose it into brackets:\n\n```typescript\n@Attribute({selector: '[my-attribute]'})\n```\n\n#### `module` `: ng.IModule`\n\nOptional. The directive will be registered under the given angular module, no\nnew module will be created, and other module options will be ignored:\n\n```typescript\n@Component({\n  module: angular.module('myApp'),\n  selector: 'my-element'\n})\n```\n\nI recommend using a single angular \"module\" for the entire application. Angular\ndependencies are kinda fake: all providers (services, etc.) are registered\nglobally in the application injector, and dependencies \"bleed through\" to sister\nmodules. Might as well admit this and keep it simple. The real dependency tree\nof your application is defined by ES6 modules. See [`defaults`](#defaults) for\nsetting up a default angular module.\n\n#### `moduleName` `: string`\n\nOptional. Dictates the name of the new angular \"module\" that will be created:\n\n```typescript\n@Attribute({\n  moduleName: 'app.myAttribute',\n  selector: '[my-attribute]'\n})\n```\n\nIf omitted, defaults to the directive's name, as shown above. See\n[`defaults`](#defaults) for how to set up an implicit module.\n\n#### `dependencies` `: string[]`\n\nOptional. Names of other angular \"modules\" the newly created module depends on.\nThis is necessary when you depend on third party services that need to be\ndependency-injected (see `inject` below):\n\n```typescript\n@Component({\n  selector: 'my-link',\n  dependencies: ['ui.router']\n})\n```\n\nIf omitted, defaults to `['ng']`, as shown above.\n\n#### `inject` `: string[]`\n\n**Deprecated**, see [`@autoinject`](#autoinject).\n\nOptional. Names of angular services that will be dependency-injected and\nautomatically assigned to the class's prototype:\n\n```typescript\n@Component({\n  selector: 'my-element',\n  inject: ['$q']\n})\nclass X {\n  constructor() {\n    console.log(this.$q)\n  }\n}\n```\n\nThis lets you easily get hold of angular services while using ES6 modules for\neverything else. The magic happens during Angular's \"run phase\", before any\ndirectives are instantiated.\n\nSee the [`gotcha`](#gotcha) for the possible dependency injection issues. They\ncan be easily avoided by using just one module.\n\n#### `injectStatic` `: string[]`\n\n**Deprecated**, see [`@autoinject`](#autoinject).\n\nOptional. Works exactly like `inject`, but assigns the injected services to the\nclass as static properties.\n\n```typescript\n@Component({\n  selector: 'my-element',\n  injectStatic: ['$http']\n})\nclass X {\n  constructor() {\n    console.log(X.$http)\n  }\n}\n```\n\n#### Statics\n\nThese directive options can be included as static methods or properties:\n\n```typescript\ntemplate\ntemplateUrl\ncompile\nlink\nscope\n```\n\nExample:\n\n```typescript\n@Attribute({\n  selector: 'svg-icon'\n})\nclass X {\n  @autoinject $templateCache;\n\n  static template($element) {\n    var element = $element[0];\n    var src = 'svg/' + element.getAttribute('icon') + '.svg';\n    return X.$templateCache.get(src);\n  }\n}\n```\n\n## Services\n\n### `@Ambient`\n\nDependency injection helper. It's a strict subset of other decorators in this\nlibrary. Use it when you want to obtain Angular's services without creating any\nnew directives or services.\n\n```typescript\nimport {Ambient, autoinject} from 'ng-decorate';\n\n@Ambient\nclass X {\n  @autoinject $q;\n  @autoinject static $http;\n\n  constructor() {\n    console.log(this.$q)\n    console.log(X.$http)\n  }\n}\n```\n\n(See [`@autoinject`](#autoinject) below.)\n\nJust like with other class decorators, you can include `module`, `moduleName`\nand so on. For this particular decorator, arguments are optional.\n\n### `@Service`\n\nSame as `@Ambient` but registers a new angular service with the given name. The\n`serviceName` option is mandatory. This is useful when you're porting a legacy\napplication, where some parts still rely on Angular's DI.\n\nCreate a service:\n\n```typescript\n@Service({\n   serviceName: 'MySpecialClass'\n})\nclass X {}\n```\n\nGet it in Angular's DI:\n\n```typescript\nangular.module('app').run(['MySpecialClass', function(MySpecialClass) {\n  /* ... */\n}]);\n```\n\n### `@Controller`\n\nSame as `@Ambient` but also registers the class as an \"old school\" controller\nunder the given name. Can optionally publish the class to the DI system, just\nlike `@Service`.\n\nRegister the controller:\n\n```typescript\n@Controller({\n  controllerName: 'X'\n})\nclass X {}\n\n@Controller({\n  controllerName: 'Y',\n  serviceName: 'Y'\n})\nclass Y {}\n```\n\nUse in a template:\n\n```html\n\u003cdiv ng-controller=\"X\"\u003e\u003c/div\u003e\n```\n\nThis type of controller usage is outdated and generally **not recommended**. Use\n`@Component` instead. This decorator is provided to ease migration of legacy\napps to ES6/7.\n\n### Service Options\n\nThis applies to `@Ambient`, `@Service`, and `@Controller`.\n\n#### `module` `: ng.IModule`\n#### `moduleName` `: string[]`\n#### `dependencies` `: string[]`\n\nSee [Directive Options](#directive-options).\n\n## Bindings\n\nDirectly annotate class properties to declare them as bindable. Perfect with\nTypeScript. When used with `@Component` or `@Attribute`, the annotations are\ngrouped and converted into a `scope: {/* ... */}` declaration for the internal\ndirective definition object.\n\nExample:\n\n```typescript\nimport {Component, bindString, bindTwoWay} from 'ng-decorate';\n\n@Component({\n  selector: 'editable'\n})\nclass X {\n  @bindString label: string;\n  @bindTwoWay value: string;\n}\n```\n\nExpands to:\n\n```typescript\nimport {Component} from 'ng-decorate';\n\n@Component({\n  selector: 'editable',\n  scope: {\n    label: '@',\n    value: '='\n  }\n})\nclass X {\n  label: string;\n  value: string;\n}\n```\n\nThis lets you declare bindings directly in the class body and makes them more\nsemantic.\n\n### `@bindString`\n\n```typescript\n@Component({\n  selector: 'my-element'\n})\nclass X {\n  @bindString first: string;\n  @bindString('last') second: string;\n}\n```\n\nExpands to:\n\n```typescript\n@Component({\n  selector: 'my-element',\n  scope: {\n    first: '@',\n    second: '@last'\n  }\n})\nclass X {\n  first: string;\n  second: string;\n}\n```\n\n### `@bindTwoWay`\n\n```typescript\n@Component({\n  selector: 'my-element'\n})\nclass X {\n  @bindTwoWay first: any;\n  @bindTwoWay({collection: true, optional: true, key: 'last'})\n  second: any;\n}\n```\n\nExpands to:\n\n```typescript\n@Component({\n  selector: 'my-element',\n  scope: {\n    first: '=',\n    second: '=*?last'\n  }\n})\nclass X {\n  first: any;\n  second: any;\n}\n```\n\n### `@bindOneWay`\n\nThis is a special feature of `ng-decorate`. It bridges the gap between Angular\n2, where one-way binding is the default, and Angular 1.x, which doesn't support\nit natively.\n\nExample with a hardcoded string:\n\n```html\n\u003ccontrolled-input value=\"'constant value'\"\u003e\u003c/controlled-input\u003e\n```\n\n```typescript\n@Component({\n  selector: 'controlled-input'\n})\nclass X {\n  @bindOneWay value: any;\n\n  constructor() {\n    this.value = 123;         // has no effect\n    console.log(this.value);  // prints 'constant value'\n  }\n}\n```\n\n### `@bindExpression`\n\n```typescript\n@Component({\n  selector: 'my-element'\n})\nclass X {\n  @bindExpression first: Function;\n  @bindExpression('last') second: Function;\n}\n```\n\nExpands to:\n\n```typescript\n@Component({\n  selector: 'my-element',\n  scope: {\n    first: '\u0026',\n    second: '\u0026last'\n  }\n})\nclass X {\n  first: Function;\n  second: Function;\n}\n```\n\n## `@autoinject`\n\nProperties annotated with `@autoinject` are automatically assigned to the prototype\n(instance properties) or class (static properties). You don't need to inject them\nin the constructor.\n\nMust be used with one of the class decorators, like `@Component` or `@Ambient`.\n\n```typescript\nimport {Component, autoinject} from 'ng-decorate';\n\n@Component({\n  selector: 'todo-list'\n})\nclass X {\n  @autoinject $q;\n  @autoinject static $timeout;\n\n  constructor() {\n    console.log(this.$q);\n    console.log(X.$timeout);\n  }\n}\n```\n\nWorks great with TypeScript and property type annotations.\n\nAs an alternative, you can pass arrays of properties as `inject` and\n`injectStatic` to the class decorator (deprecated).\n\nNote that this only works for global services. For contextual dependencies\nlike `$scope`, use constructor injection:\n\n```javascript\nclass X {\n  static $inject = ['$scope', '$element'];\n  constructor($scope, $element) {\n    /* ... */\n  }\n}\n```\n\nWith TypeScript, use the `private` or `public` modifier to automatically assign\nthe injected value to the instance:\n\n```typescript\nclass X {\n  static $inject = ['$scope', '$element'];\n  constructor(private $scope, private $element) {\n    /* ... */\n  }\n}\n```\n\n## `defaults`\n\nThe package is stateful. You can import its configuration object and mutate it\nto set global defaults.\n\nDefault configuration (with type annotations for the sake of clarity):\n\n```typescript\nexport const defaults = {\n  // Default angular module. Supersedes module declarations.\n  module: \u003cng.IModule\u003enull,\n  // Default module name.\n  moduleName: \u003cstring\u003enull,\n  // Controller key. Other common variants include 'ctrl' and 'vm'.\n  controllerAs: 'self',\n  // Generates a template url from an element name. Another common variant:\n  //   'components/elementName/elementName.html'.\n  makeTemplateUrl(elementName: string): string {\n    return elementName + '/' + elementName + '.html';\n  }\n};\n```\n\nExample configuration:\n\n```typescript\nimport {defaults} from 'ng-decorate';\n\ndefaults.module = angular.module('app');\ndefaults.controllerAs = 'vm';\n```\n\nI recommend setting your application's main, or only, module as the default (see\nbelow).\n\n## Gotcha\n\nEach angular \"module\" created or reused by the decorators must be present in the\ndependency tree of your main module (the one that has been bootstrapped via\n`ng-app` or `angular.bootstrap`). If you let the decorators create new\nmodules, you must add them to the dependency list of the main module.\n\nTo avoid this, use a single angular module for the entire application, setting\nit in `defaults` or explicitly passing it to decorators. There's nothing to gain\nby using Angular's fake dependencies that end up sharing the same global\nnamespace in the resulting injector.\n\n## Alternatives\n\n[ng-forward](https://github.com/ngUpgraders/ng-forward) is an upcoming ng1-\u003eng2\nmigration helper based on\n[angular-decorators](https://github.com/mikeryan52/angular-decorators)\nwith input from\n[a1atscript](https://github.com/hannahhoward/a1atscript),\n[angular2-now](https://github.com/pbastowski/angular2-now) and `ng-decorate`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmitranim%2Fng-decorate","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmitranim%2Fng-decorate","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmitranim%2Fng-decorate/lists"}