angularjs - español - crear componente angular 6
¿Cuál es la mejor práctica para crear un componente AngularJS 1.5 en Typescript? (7)
Creo que un buen enfoque es usar angular-ts-decorators . Con él puedes definir Componentes en AngularJS como este:
import { Component, Input, Output } from ''angular-ts-decorators'';
@Component({
selector: ''myComponent'',
templateUrl: ''my-component.html
})
export class MyComponent {
@Input() todo;
@Output() onAddTodo;
$onChanges(changes) {
if (changes.todo) {
this.todo = {...this.todo};
}
}
onSubmit() {
if (!this.todo.title) return;
this.onAddTodo({
$event: {
todo: this.todo
}
});
}
}
y luego regístrelos en su módulo usando:
import { NgModule } from ''angular-ts-decorators'';
import { MyComponent } from ''./my-component'';
@NgModule({
declarations: [MyComponent]
})
export class MyModule {}
Si desea verificar un ejemplo de una aplicación real que lo utiliza, puede verificar este .
Estoy experimentando con la sintaxis de .component()
en Angular 1.5.
Parece que la última moda es codificar el controlador en línea en el componente en lugar de hacerlo en un archivo separado, y puedo ver la ventaja de eso, dado que el modelo repetitivo es mínimo.
El problema es que he estado codificando mis controladores como clases mecanografiadas y me gustaría seguir haciéndolo porque eso parece ser coherente con Angular2.
Mi mejor esfuerzo es algo como esto:
export let myComponent = {
template: ($element, $attrs) => {
return [
`<my-html>Bla</my-html>`
].join('''')
},
controller: MyController
};
class MyController {
}
Funciona, pero no es elegante. ¿Hay una mejor manera?
Estaba luchando con la misma pregunta y puse mi solución en este artículo:
http://almerosteyn.github.io/2016/02/angular15-component-typescript
module app.directives {
interface ISomeComponentBindings {
textBinding: string;
dataBinding: number;
functionBinding: () => any;
}
interface ISomeComponentController extends ISomeComponentBindings {
add(): void;
}
class SomeComponentController implements ISomeComponentController {
public textBinding: string;
public dataBinding: number;
public functionBinding: () => any;
constructor() {
this.textBinding = '''';
this.dataBinding = 0;
}
add(): void {
this.functionBinding();
}
}
class SomeComponent implements ng.IComponentOptions {
public bindings: any;
public controller: any;
public templateUrl: string;
constructor() {
this.bindings = {
textBinding: ''@'',
dataBinding: ''<'',
functionBinding: ''&''
};
this.controller = SomeComponentController;
this.templateUrl = ''some-component.html'';
}
}
angular.module(''appModule'').component(''someComponent'', new SomeComponent());
}
Este es el patrón que uso:
ZippyComponent.ts
import {ZippyController} from ''./ZippyController'';
export class ZippyComponent implements ng.IComponentOptions {
public bindings: {
bungle: ''<'',
george: ''<''
};
public transclude: boolean = false;
public controller: Function = ZippyController;
public controllerAs: string = ''vm'';
public template: string = require(''./Zippy.html'');
}
ZippyController.ts
export class ZippyController {
bungle: string;
george: Array<number>;
static $inject = [''$timeout''];
constructor (private $timeout: ng.ITimeoutService) {
}
}
Zippy.html
<div class="zippy">
{{vm.bungle}}
<span ng-repeat="item in vm.george">{{item}}</span>
</div>
main.ts
import {ZippyComponent} from ''./components/Zippy/ZippyComponent'';
angular.module(''my.app'', [])
.component(''myZippy'', new ZippyComponent());
Estoy usando el siguiente patrón para usar el component angular 1.5 con mecanografiado
class MyComponent {
model: string;
onModelChange: Function;
/* @ngInject */
constructor() {
}
modelChanged() {
this.onModelChange(this.model);
}
}
angular.module(''myApp'')
.component(''myComponent'', {
templateUrl: ''model.html'',
//template: `<div></div>`,
controller: MyComponent,
controllerAs: ''ctrl'',
bindings: {
model: ''<'',
onModelChange: "&"
}
});
Estoy usando un simple decorador de TypeScript para crear el componente
function Component(moduleOrName: string | ng.IModule, selector: string, options: {
controllerAs?: string,
template?: string,
templateUrl?: string
}) {
return (controller: Function) => {
var module = typeof moduleOrName === "string"
? angular.module(moduleOrName)
: moduleOrName;
module.component(selector, angular.extend(options, { controller: controller }));
}
}
entonces puedo usarlo así
@Component(app, ''testComponent'', {
controllerAs: ''ct'',
template: `
<pre>{{ct}}</pre>
<div>
<input type="text" ng-model="ct.count">
<button type="button" ng-click="ct.decrement();">-</button>
<button type="button" ng-click="ct.increment();">+</button>
</div>
`
})
class CounterTest {
count = 0;
increment() {
this.count++;
}
decrement() {
this.count--;
}
}
Puedes probar un jsbin que funcione aquí http://jsbin.com/jipacoxeki/edit?html,js,output
Si quisiera adoptar por completo un enfoque angular 2, podría usar:
module.ts
import { MyComponent } from ''./MyComponent'';
angular.module(''myModule'', [])
.component(''myComponent'', MyComponent);
MyComponent.ts
import { Component } from ''./decorators'';
@Component({
bindings: {
prop: ''<''
},
template: ''<p>{{$ctrl.prop}}</p>''
})
export class MyComponent {
prop: string;
constructor(private $q: ng.IQService) {}
$onInit() {
// do something with this.prop or this.$q upon initialization
}
}
decorators.ts
/// <reference path="../typings/angularjs/angular.d.ts" />
export const Component = (options: ng.IComponentOptions) => {
return controller => angular.extend(options, { controller });
};
Sugiero no usar soluciones personalizadas, sino usar la biblioteca ng-metadata
. Puede encontrarlo en https://github.com/ngParty/ng-metadata . De esta manera, tu código es el más compatible posible con Angular 2. Y como se indica en el archivo Léame, es
Sin hacks. No anula Producción lista
Acabo de cambiar después de usar una solución personalizada de las respuestas aquí, pero es más fácil si usa esta biblioteca de inmediato. De lo contrario, tendrá que migrar todos los pequeños cambios de sintaxis. Un ejemplo sería que las otras soluciones aquí usan la sintaxis
@Component(''moduleName'', ''selectorName'', {...})
mientras Angular 2 usa
@Component({
selector: ...,
...
})
Por lo tanto, si no usa ng-metadata
inmediato, aumentará considerablemente el esfuerzo de migrar su base de código más adelante.
Un ejemplo completo de las mejores prácticas para escribir un componente sería el siguiente :
// hero.component.ts
import { Component, Inject, Input, Output, EventEmitter } from ''ng-metadata/core'';
@Component({
selector: ''hero'',
moduleId: module.id,
templateUrl: ''./hero.html''
})
export class HeroComponent {
@Input() name: string;
@Output() onCall = new EventEmitter<void>();
constructor(@Inject(''$log'') private $log: ng.ILogService){}
}
(copiado de las recetas ng-metadata )