Original article: 48 answers on StackOverflow to the most popular Angular questions

He recopilado las preguntas sobre Angular más comunes en StackOverflow, con sus respuestas.  Estas preguntas fueron elegidas en base a su puntuación. Ya seas un experto o un principiante, puedes aprender de las experiencias de otros.

Tabla de contenidos

¡Disfruta!

Angular - Promise vs Observable

551+ votos? 150,497+ vistas
Rohit pregunta,

¿Alguien puede explicar la diferencia entre Promise y Observable en Angular?

Un ejemplo de cada uno sería útil para comprender los dos. ¿En qué escenario podemos utilizar cada caso?

Günter Zöchbauer contesta, (686+ votos)

Promise

Una Promise se encarga de un solo evento cuando una operación asincrona (async) completa sea con éxito o error.

Nota: Hay librerias de promesas ( Promise ) que permiten la cancelación, pero ES6 Promise no lo permite.

Observable

Un Observable es como un Stream (en muchos lenguages) y permite pasar cero o más eventos donde se llama a los suscriptores para cada evento.

A menudo se prefiere un Observable a una  Promise porque proporciona las características de Promise y más. Con un Observable no importa si se desea trabajar con 0, 1 o múltiples eventos. Se puede utilizar la misma API en cada caso.

Un Observable también tiene la ventaja sobre una Promise de que es cancelable. Si ya no se necesita el resultado de una solicitud HTTP a un servidor o alguna otra operación asincrónica costosa, la Subscription de un Observable permite cancelar la suscripción, mientras que una Promise llamará a la devolución de llamada  (callback), exitosa o fallida, incluso si ya no se necesita.

Observable proporciona operadores como map, forEach, reduce, ... similares a los de un arreglo.

También hay operadores poderosos como retry(), o replay(), ... que suelen ser bastante útiles.

Source
Top

Diferencia entre Constructor y ngOnInit

444+ votos? 190,166+ vistas
Haseena P A pregunta,

Angular proporciona el gancho de ciclo de vida (lifecycle hook) ngOnInit por defecto.

¿Por qué usar ngOnInit , si ya tenemos constructor constructor?

Pardeep Jain contesta, (512+ votos)

El Constructor es un método predeterminado de la clase que se ejecuta cuando se crea una instancia de la clase y garantiza la inicialización adecuada de los campos en la clase y sus subclases.  Angular, o mejor dicho, Dependency Injector (DI o Inyector de dependencia) analiza los parámetros del constructor y cuando crea una nueva instancia al llamar a new MiClase() intenta encontrar proveedores que coincidan con los tipos de parámetros del constructor, los resuelve y los pasa al constructor como

new MiClase(argumentos);

ngOnInit es un enlace de ciclo de vida que Angular2 llama para indicar que Angular ha terminado de crear el componente.

Hay que importar OnInit para usarlo (realmente implementar OnInit no es obligatorio, pero se considera una buena práctica):

import {Component, OnInit} from '@angular/core';

Luego para usar el método de OnInit tenemos que implementarlo en la clase así.

export class App implements OnInit{
  constructor(){
     //se llama la primera vez, antes de ngOnInit()
  }
  
  ngOnInit(){
     //se llama despues del constructor y despues de la primera llamada a ngOnChanges() 
  }
}

Implementa esta interfaz para ejecutar lógica de inicialización después de que las propiedades enlazadas a datos de tu directiva (directive) hayan sido inicializadas. ngOnInit es llamado justo después de que las propiedades enlazadas a datos de la directiva  hayan sido revisadas por primera vez, y antes de que sus hijos sean revisados. Solamente es invocado una vez cuando la directiva es instanciada.

La mayor parte del tiempo se usa ngOnInit para las declaraciones e inicializaciones y así evitar trabajar en el constructor. El constructor solamente debe usarse para inicializar miembros de la clase, pero no para hacer un "trabajo" real.

Por lo tanto, deberías usar constructor() para establecer Dependency Injection (inyección de dependencia) y poco más. Es mejor empezar con el código de ejecución en ngOnInit()  - es donde/cuando se han resuelto los enlaces de los componentes.

Source
Top

Error: "Can’t bind to 'ngModel' since it isn’t a known property of 'input'"; No se puede vincular a 'ngModel' ya que no es una propiedad conocida de 'input'

442+ votos? 246,901+ vistas
abreneliere pregunta,

Tengo el siguiente error al iniciar mi aplicación de Angular, incluso si el componente no se muestra.

Tengo que comentarlo para que mi aplicación funcione.

zone.js:461 Unhandled Promise rejection: Template parse errors:
Can't bind to 'ngModel' since it isn't a known property of 'input'. ("
    <div>
        <label>Creado:</label>
        <input  type="text" [ERROR ->][(ngModel)]="test" placeholder="foo" />
    </div>
</div>"): InterventionDetails@4:28 ; Zone: <root> ; Task: Promise.then ; Value:

Aquí esta el fichero:

import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { Intervention } from '../../model/intervention';

@Component({
    selector: 'intervention-details',
    templateUrl: 'app/intervention/details/intervention.details.html',
    styleUrls: ['app/intervention/details/intervention.details.css']
})

export class InterventionDetails
{
    @Input() intervention: Intervention;
    public test : string = "toto";
}
abreneliere contesta, (674+ votos)

En app.module.ts, he añadido :

import { FormsModule } from '@angular/forms';

[...]

@NgModule({
  imports: [
    [...]
    FormsModule
  ],
  [...]
})

Source
Top

Vinculación de HTML en Angular

385+ votos? 227,115+ vistas
Aviad P. pregunta,

Estoy escribiendo una aplicación en Angular, y tengo una respuesta HTML que quiero mostrar. ¿Cómo lo hago? Si uso {{myVal}} codifica todos los caracteres HTML .

Necesito de alguna manera vincular el html interno de un div al valor de la variable.

prolink007 contesta, (691+ votos)

La sintaxis correcta es:

<div [innerHTML]="theHtmlString"></div>

Funciona en 5.2.6

Source
Top

Angular/RxJs - ¿Cuándo debo dejar de suscribir de 'Subscription'?

320+ votos? 69,606+ vistas
Sergey Tihon pregunta,

¿Cuándo debo guardar las instancias de Subscription e invocar unsubscribe() durante el ciclo de vida de NgOnDestroy y cuándo puedo sencillamente ignorarlas?

Guardar todas las suscripciones introduce mucho desorden en el código del componente.

La guía de Angular para cliente de HTTP lo indica de esta manera:

getHeroes() {
  this.heroService.getHeroes()
                   .subscribe(
                     heroes => this.heroes = heroes,
                     error =>  this.errorMessage = <any>error);
}

Pero la de Angular de navegación dice:

Eventualmente, navegaremos a otro sitio. El enrutador eliminará este componente del DOM y lo destruirá. Necesitamos hacer limpieza antes de que esto suceda. En concreto, debemos eliminar la suscripción (unsubscribe) antes de que Angular destruya el componente. No hacerlo puede provocar una pérdida de memoria.

Dejamos la suscripción de nuestro Observable en ngOnDestroy.

private sub: any;

ngOnInit() {
  this.sub = this.route.params.subscribe(params => {
     let id = +params['id']; // (+) convierte la cadena 'id' a un numero
     this.service.getHero(id).then(hero => this.hero = hero);
   });
}

ngOnDestroy() {
  this.sub.unsubscribe();
}
seangwright contesta, (508+ votos)

— — Editado 3 — La solución ‘oficial’ (2017/04/09)

Hablé con Ward Bell sobre esta pregunta en NGConf (incluso le mostré esta respuesta que dijo que era correcta) pero me dijo que el equipo de docs para Angular tenía una solución a esta pregunta que aún no está publicada (aunque están trabajando para que se apruebe). También me dijo que podía actualizar mi respuesta en SO con la siguiente recomendación oficial.

La solución que todos deberíamos usar en el futuro es agregar un campo private ngUnsubscribe: Subject = new Subject(); a todos los componentes que tienen llamadas  .subscribe() a Observables dentro del código de la clase.

Luego llamamos this.ngUnsubscribe.next(); this.ngUnsubscribe.complete(); en nuestro ngOnDestroy() .

La salsa secreta es (como ya indica @metamaker) llamar a .takeUntil(this.ngUnsubscribe) antes de nuestra llamada a  .subscribe() lo que garantiza que las suscripciones se eliminen antes de que se destruya el componente.

Ejemplo:

import { Component, OnDestroy, OnInit } from '@angular/core';
import 'rxjs/add/operator/takeUntil';
// import { takeUntil } from 'rxjs/operators'; // para rxjs ^5.5.0 lettable operators
import { Subject } from 'rxjs/Subject';

import { MiServicio } from '../mi-cosa.service';

@Component({
    selector: 'mi-cosa',
    templateUrl: './mi-cosa.component.html'
})
export class MiCosaComponent implements OnDestroy, OnInit {
    private ngUnsubscribe: Subject = new Subject();
    
    constructor(
        private miServicio: MiServicio,
    ) { }
    
    ngOnInit() {
        this.miServicio.getCosas()
            .takeUntil(this.ngUnsubscribe)
            .subscribe(cosas => console.log(cosas));
            
        /* si se usan lettable operators in rxjs ^5.5.0
        this.migServicio.getCosas()
            .pipe(takeUntil(this.ngUnsubscribe))
            .subscribe(cosas => console.log(cosas));
        */
        
        this.miServicio.getOtrasCosas()
            .takeUntil(this.ngUnsubscribe)
            .subscribe(cosas => console.log(cosas));
            
    }
    
    ngOnDestroy() {
        this.ngUnsubscribe.next();
        this.ngUnsubscribe.complete();
    }
}

— — Editado 2 (2016/12/28)

fuente 5

En el tutorial de Angular, el capítulo de rutas ahora dice esto: “El enrutador ( Router) maneja los observables que proporciona y localiza las suscripciones. Las suscripciones se limpian cuando el componente es destruido, protegiendo contra pérdidas de memoria, por lo que no necesitamos cancelar la suscripción de los parámetros de ruta observables.” — Mark Rajcok

— — Editado 1

Fuente 4

En este  video de NgEurope Rob Wormald dice que no necesitas eliminar la suscripción.  También menciona el servicio  http y ActivatedRoute.params en este video de Noviembre 2016.

— — Repuesta Original

TLDR:

Para esta pregunta hay 2 tipos de Observables - de valor finito y valor infinito.

Las Observables http producen valores finitos (1) algo similar a un evento del DOM ( event listener ) produce Observables de valores infinitos.

Si llamas de forma manual a subscribe (sin usar una pipe asíncrona), haz un unsubscribe de las Observables infinitas .

No te preocupes por las finitas , RxJs se encargara de ellas.

Fuente 1

He localizado una respuesta de Rob Wormald en Angular Gitter.

Dice que (reorganizado para que esté más claro y el énfasis es mío)

Si es una secuencia de un solo valor (como una solicitud http (request)) la limpieza manual no es necesaria (suponiendo que te suscribes en el controller de manera manual)

Debería decir "si es una secuencia que termina" (como son las de secuencia de un solo valor, como la http)

Si la secuencia es infinita, deberías elimnar la suscripción (unsubscribe) lo que se consigue usando la pipe asíncrona.

También comenta en este video de youtube sobre Observables que se limpian ellas mismas... en el contexto de las Observables que terminan (como las Promesas (promeses), que siempre terminan porque siempre producen un valor y terminan - nunca nos hemos preocupado de eliminar las suscripciones de promesas para que limpien escuchadores de eventos  xhr (event listeners)).

Fuente 2

También en  la guía Rangle de Angular 2:

En la mayoría de los casos no necesitamos eliminar la suscripción (unsubscribe) a no ser que queramos cancelar antes de tiempo o la Observable dure más que lo que necesita nuestra suscripción. El comportamiento por defecto de los operadores de Observable es eliminar la suscripción tan pronto como los mensajes de .complete() o .error() son publicados. Ten en cuenta que RxJS fue diseñado para utilizarse en modo "dispara y olvidate" en la mayoría de los casos.

Qué quiere decir que nuestra Observable dura más que lo que necesita nuestra suscripción?

Se refiere a cuando una suscripción es creada dentro de un componente que es destruido antes de que la Observable termine.

Entiendo esto así, si suscribimos a una solicitud (request)  http o a una observable que emite 10 valores y nuestro compenente es destruido antes de que esa solicitud  http vuelva o los 10 valores sean emitidos no tenemos ningún problema.

Cuando la solicitud vuelve o el décimo valor es emitido la Observable se completará y todos los recurdos seran liberados.

Fuente 3

El artículo original hacía referencia a un ejemplo en una página que ya no se encuentra.

Source
Top

¿Cómo puedo seleccionar un elemento en una plantilla componente?

263+ votos? 265,966+ vistas
Aman Gupta pregunta,

¿Alguién sabe como obtener un elemento definido en la plantilla (template) de un componente? Polymer lo hace muy fácil con  $ and $$.

Me pregunto como hacerlo en Angular.

En este ejemplo de un tutorial:

import {Component} from '@angular/core'

@Component({
    selector:'mostrar'
    template:`
     <input #miNombre(input)="actualizarNombre(miNombre.value)"/>
     <p>Mi nombre : {{miNombre}}</p>
    `
    
})
export class MostrarComponent {
    miNombre: string = "Aman";
    actualizarNombre(input: String) {
        this.miNombre = input;
    }
}

¿Cómo puedo obtener la referencia a los elementos p o input dentro de la misma clase?

Brocco contesta, (149+ votos)

Puedes obtener la referencia al elemento del DOM con ElementRef inyectandolo en el constructor:

constructor(miElemento: ElementRef) { ... }

Source
Top

¿Cuales son los equivalentes de ngShow y ngHide en Angular?

261+ votos? 206,651+ vistas
Mihai Răducanu pregunta,

Tengo un número de elementos que quiero hacer visibles bajo ciertas condiciones.

En AngularJS haría esto:

<div ng-show="miVar">alguna cosa</div>

¿Cómo lo hago en Angular?

Günter Zöchbauer contesta, (445+ votos)

Enlaza con la propiedad  hidden :

[hidden]="!miVar"

Ver también

hidden tiene algunos problemas porque puede tener conflictos con CSS para la propierdad display.

En este ejemplo de Plunker  some  no desaparece porque tiene un estilo (style).

:host {display: block;}

(Puede que funcione de manera diferente en navegadores diferentes — Yo he usado Chrome 50)

Para evitar ese problema

Lo puedes solucionar añadiendo

[hidden] { display: none !important;}

A un estilo (style) global en index.html.

otro problema

hidden="false"
hidden="{{false}}"
hidden="{{estaEscondido}}" // estaEscondido = false;

es lo mismo que

hidden="true"

y no mostrata el elemento.

hidden="false" asigna la cadena "false" lo que se considera true (porque no es una cadena vacía).
Solamente el valor  false o quitar el atributo hará que se muestre el elemento.

Usar {{}} también convierte la expression a una cadena y no funcionará como esperamos.

Solamente usando  [] funciona como esperamos porque este false es asignado  false en lugar de  "false".

*ngIf vs [hidden]

*ngIf quita el contenido del DOM mientras que [hidden] cambia la propiedad display para que no se muestre el contenido, pero el contenido sigue en el DOM.

Source
Top

Como empaquetar una aplicación de Angular para producción

258+ votos? 111,603+ vistas
Pat M pregunta,

Me gustaría conocer la mejor forma y la más actual (y espero que la más sencilla)  para empaquetar Angular (version 2, 4, …) para producción en un servidor en activo.

Por favor, incluid la versión de Angular en las respuestas para que pueda saber que hacer dependiendo de las versiones.

Nicolas Henneaux contesta, (267+ votos)

2.x, 4.x, 5.x (TypeScript) con Angular CLI

Configurar una vez

  • npm install -g @angular/cli
  • ng new ficheroDelProyecto crea una aplicación nueva.

Configuran el empaquetado

  • ng build --prod (en la línea de comando en el directorio ficheroDelProyecto)
  • marca prod para empaquetado para producción (ver la documentación para las opciones de prod).
  • Comprime los recursos con Brotli con el siguiente commando for i in dist/*; do brotli $i; done

lo paquetes se generan por defecto en ficheroDelProyecto/dist/

Output

Tamaños con Angular 5.2.8 con CLI 1.7.2

  • dist/main.[hash].bundle.js El paquete de tu aplicación [ tamaño: 151 KB para una nueva vacía de CLI , 36 KB comprimida].
  • dist/polyfill.[hash].bundle.js con dependencias (@angular, RxJS...) [tamaño: 58 KB para una nueva de Angular CLI vacía, 17 KB comprimida].
  • dist/index.html punto de entrada de la aplicación.
  • dist/inline.[hash].bundle.js webpack loader (cargador).
  • dist/style.[hash].bundle.css definiciones de estilo (style).
  • dist/assets recursos copiados de los de Angular CLI según la configuración.

Despliegue (deployment)

Puedes ver un avance de tu aplicación con ng serve --prod en tu servidor para local HTTP y así la aplicación con los ficheros para producción es accesible desde http://localhost:4200.

Para la verdadera producción, tienes que desplegar los ficheros del directorio  dist en el servidor  HTTP de tu elección.

Source
Top

BehaviorSubject vs Observable

250+ votos? 122,248+ vistas
Kevin Mark pregunta,

Estoy informandome sobre patrones en Angular RxJs y no entiendo la diferencia entre BehaviorSubject y un Observable.

Según lo veo yo, un BehaviorSubject es un valor que puede cambiar en el tiempo (uno se puede suscribir a ese valor y los suscriptores reciben el valor actualizado). Esto parece que es precisamente lo que es un Observable.

¿Cuándo usarías un Observable o un BehaviorSubject? ¿Cuál ofrece más ventajas si es que uno ofrece más que el otro?

Shantanu Bhadoria contesta, (425+ votos)

BehaviorSubject es un tipo de sujeto (subject), un subject es un tipo de observable así que te puedes suscribir a él como a cualquier otro observable. Lo que hace único a BehaviorSubject es:

  • Necesita un valor inicial ya que siempre debe devolver un valor incluso si no ha recibido un next()
  • Cuando encuentra una suscripción, le devuelve el último valor del sujeto (subject).  Un observable común en Angular solo dispara cuando recibe un  onnext
  • En cualquier momento se puede sacar el valor mas reciente del sujeto (subject) en código no observable usando el método getValue().

Las características únicas de un sujeto (subject) en comparación con un observable son:

  • Es un observador (observer) además de un observable, por lo tanto, puedes mandar valores a un subject ademas de suscribirte a él.

Además, puedes obtener un observable de behaviorSubject utilizando  el método asobservable() de BehaviorSubject.

Un Observable es un genérico, y BehaviorSubject técnicamente es un subtipo de Observable porque BehaviorSubject es un Observable con unas características particulares.

Ejemplo con BehaviorSubject:

// Behavior Subject

// a es un valor inicial. Si hay una suscripcion
// despues de esto, le llega "a" inmediatamente
let bSubject = new BehaviorSubject("a"); 

bSubject.next("b");

bSubject.subscribe((value) => {
  console.log("Suscripcion recibe", value); // suscripcion recibe b, 
                                          // esto no pasaria 
                                          // en un observable generico
                                          // o un subject generico por defecto
});

bSubject.next("c"); // suscripcion recibe c
bSubject.next("d"); // Suscipcion recibe d

Ejemplo 2 con un sujeto común:

// Sujecto comun

let subject = new Subject(); 

subject.next("b");

subject.subscribe((value) => {
  console.log("suscripcion recibe", value); // suscripcion no recibe nada                                                 // en este punto
});

subject.next("c"); // suscripcion recibe c
subject.next("d"); // suscripcion recibe d

Un observable puede crearse con Subject o BehaviorSubject usando subject.asobservable().  La diferencia es que no se pueden mandar valores a un observable usando  next() .

En servicios en Angular, yo usaría BehaviorSubject para un servidor de datos ya que estos servicios a menudo se inicializan antes del componente y BehaviorSubject  te asegura que el componente que consuma este servicio recibe el valor mas reciente de los datos incluso si no hay cambios desde que se creo la suscripcion a estos datos.

Source
Top

@Directive vs @Component en Angular

239+ votos? 61,582+ vistas
Prasanjit Dey pregunta,

¿Cuál es la diferencia entre @Component y @Directive en Angular? Parece que ambas tienen los mismos atributos y hacen lo mismo.

¿Cuáles son los escenarios donde usar cada uno y cuándo es preferible uno sobre otro?

jaker contesta, (327+ votos)

Un @Component requiere una view (página donde mostrarlo) pero un @Directive no.

Directives

Un @Directive de Angular es parecido a uno de de Angular 1.0 con la opción restrict: 'A' (Los directives no están limitados a usarse solamente como atributos). Los directives añaden comportamiento a un elemento del DOM que ya existe,  o a una instancia de un componente que ya existe. Un ejemplo de cuando usar un directive sería para guardar cuando un elemento recibe un click.

import {Directive} from '@angular/core';

@Directive({
    selector: "[guardaEnClick]",
    hostListeners: {
        'click': 'onClick()',
    },
})

class GuardaEnClick {
    constructor() {}
    onClick() { console.log('El elemento ha recibido un click !'); }
}

Y se usaría así:

<button guardaEnClick>Yo guardo cuando recibo un click!<;/button>

Components

Un component (componente), en lugar de añadir/modificar un comportamiento, crea su propia view (página , jerarquía de los elementos del DOM) con su comportamiento adjunto. Un ejemplo de un component para una tarjeta de visita:

import {Component, View} from '@angular/core';

@Component({
  selector: 'tarjeta-visita',
  template: `
    <div>
      <h1>{{nombre}}</h1>
      <p>{{ciudad}}</p>
    </div>
  `
})
class TarjetaVisita {
  @Input() nombre: string
  @Input() ciudad: string
  constructor() {}
}

Y se usaría así:

<tarjeta-visita [nombre]="'foo'" [ciudad]="'bar'"></tarjeta-visita>

TarjetaVisita es un componente UI que se puede reusar en cualquier sitio de nuestra aplicación, incluso dentro de otros componentes. Estos componentes son lo que básicamente constituye la UI (user interface, interfaz de usuario) de nuestra aplicación.

En resumen

Usa un component cuando quieras un conjunto de elementos del DOM que quieras reusar, y que tengan un comportamiento particular a ese componente. Usa un directive cuando quieras tener un comportamiento reusable que suplemente el comportamiento de elementos del DOM.

Source
Top

Error de Angular HTTP GET en TypeScript : http.get(…).map is not a function in [null] (http.get(...).map no es una función en [null])

233+ votos? 141,917+ vistas
Claudiu pregunta,

Tengo un problema con HTTP en Angular.

Quiero conseguir con GET una lista en JSON y mostrarla en la página.

Clase en el servicio

import {Injectable} from "angular2/core";
import {Hall} from "./hall";
import {Http} from "angular2/http";
@Injectable()
export class HallService {
    public http:Http;
    public static PATH:string = 'app/backend/' 
    
    constructor(http:Http) {
        this.http=http;
    }
    
    getObtenerHalls() {
           return this.http.get(HallService.PATH + 'hall.json').map((res:Response) => res.json());
    }
}

Y en  HallListComponent llamo al método getObtenerHalls del servicio:

export class HallListComponent implements OnInit {
    public halls:Hall[];
    public _Id:number;
    
    constructor(private _router:Router,
                private _routeParams:RouteParams,
                private _servicio:HallService) {
        this._Id = +_routeParams.get('id');
    }
    
    ngOnInit() {
        this._servicio.getObtenerHalls().subscribe((halls:Hall[])=>{ 
            this.halls=halls;
        });
    }
}

Pero me da una excepción:

TypeError: this.http.get(...).map is not a function in [null]

hall-center.component

import {Component} from "angular2/core";
import {RouterOutlet} from "angular2/router";
import {HallService} from "./hall.service";
import {RouteConfig} from "angular2/router";
import {HallListComponent} from "./hall-list.component";
import {HallDetailComponent} from "./hall-detail.component";
@Component({
    template:`
        <h2>mi app</h2>
        <router-outlet></router-outlet>
    `,
    directives: [RouterOutlet],
    providers: [HallService]
})

@RouteConfig([
    {path: '/',         name: 'HallCenter', component:HallListComponent, useAsDefault:true},
    {path: '/hall-list', name: 'HallList', component:HallListComponent}
])

export class HallCenterComponent{}

app.component

import {Component} from 'angular2/core';
import {ROUTER_DIRECTIVES} from "angular2/router";
import {RouteConfig} from "angular2/router";
import {HallCenterComponent} from "./hall/hall-center.component";
@Component({
    selector: 'mi-app',
    template: `
        <h1>Factoria</h1>
        <a [routerLink]="['HallCenter']">Hall - Vista General</a>
        <router-outlet></router-outlet>
    `,
    directives: [ROUTER_DIRECTIVES]
})

@RouteConfig([
    {path: '/hall-center/...', name:'HallCenter',component:HallCenterComponent,useAsDefault:true}
])
export class AppComponent { }

tsconfig.json

{
  "compilerOptions": {
    "target": "ES5",
    "module": "system",
    "moduleResolution": "node",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "removeComments": false,
    "noImplicitAny": false
  },
  "exclude": [
    "node_modules"
  ]
}
Thierry Templier contesta, (416+ votos)

Creo que tienes que importar esto:

import 'rxjs/add/operator/map'

O en general, si quieres usar mas métodos de observables, puedes importar:

import 'rxjs/Rx';

ADVERTENCIA: Esto importa todos los más de 50 operadores y los añade a la aplicación lo que afecta el tamaño y el tiempo de carga.

Source
Top

¿Cómo se puede usar jQuery con Angular?

233+ votos? 246,869+ vistas
Waog pregunta,

¿Alguien puede decirme cómo usar jQuery con Angular?

class MiComponent {
    constructor() {
        // como acceder a los elementos del DOM desde aqui
    }
}

Sé que existen soluciones alternativas, como manipular la clase o el id  del elemento del DOM , pero me gustaría una manera más limpia de hacerlo.

werenskjold contesta, (258+ votos)

JQuery en Angular2 es pan comido comparado com ng1. Si estás usando TypeScript podrías referenciar el paquete de jQuery de typescript (o también de sus definiciones).

tsd install jquery --save
o
typings install dt~jquery --global --save

El de las definiciones no te hace falta ya que también podrías usar  any como  $ or jQuery

En tu componente de Angular puedes acceder a un elemento del DOM con @ViewChild() Una vez que la vista (view) se haya inicializado puedes usar la propiedad nativeElement del objecto y pasarla a jQuery.

Declarando $ (o jQuery) como JQueryStatic te da una referencia a jQuery con tipo.

import {bootstrap}    from '@angular/platform-browser-dynamic';
import {Component, ViewChild, ElementRef, AfterViewInit} from '@angular/core';
declare var $:JQueryStatic;

@Component({
    selector: 'ng-escogido',
    template: `<select #selecElemento>
        <option *ngFor="#elemento of elementos" [value]="elemento" [selected]="elemento === valorSeleccionado">{{elemento}} opcion</option>
        </select>
        <h4> {{valorSeleccionado}}</h4>`
})
export class NgEscogidoComponent implements AfterViewInit {
    @ViewChild('selecElemento') el:ElementRef;
    elementos = ['Primero', 'Segundo', 'Tercero'];
    valorSeleccionado = 'Segundo';
    
    ngAfterViewInit() {
        $(this.el.nativeElement)
            .chosen()
            .on('change', (e, args) => {
                this.valorSeleccionado = args.selected;
            });
    }
}

bootstrap(NgEscogidoComponent);

Puedes verlo en plunker: http://plnkr.co/edit/Nq9LnK?p=preview

tslint te dirá que chosen no es una propiedad en $.  Para corregirlo puedes añadir una definición a la interfaz de JQuery en tu fichero *.d.ts

interface JQuery {
    chosen(options?:any):JQuery;
}

Source
Top

Excepción en Angular: No provider for Http (No hay proveedor de HTTP)

230+ votos ? 142,976+ vistas
daniel pregunta,

Me sale esto EXCEPTION: No provider for Http! en mi aplicación de Angular. ¿Qué estoy haciendo mal?

import {Http, Headers} from 'angular2/http';
import {Injectable} from 'angular2/core'

@Component({
    selector: 'greetings-ac-app2',
    providers: [],
    templateUrl: 'app/greetings-ac2.html',
    directives: [NgFor, NgModel, NgIf, FORM_DIRECTIVES],
    pipes: []
})
export class GreetingsAcApp2 {
    private str:any;
    
    constructor(http: Http) {
    
        this.str = {str:'test'};
        http.post('http://localhost:18937/cuenta/registrausuario/',
            JSON.stringify(this.str),
            {
                headers: new Headers({
                    'Content-Type': 'application/json'
                })
            });
Philip Miglinci contesta, (381+ votos)

Importa HttpModule

import { HttpModule } from '@angular/http';

@NgModule({
    imports: [ BrowserModule, HttpModule ],
    providers: [],
    declarations: [ AppComponent ],
    bootstrap: [ AppComponent ]
})
export default class AppModule { }

platformBrowserDynamic().bootstrapModule(AppModule);

Es mejor separar el código en dos ficheros diferentes.

Source
Top

Can’t bind to ‘formGroup’ since it isn’t a known property of ‘form’ (No se puede enlazar a 'formGroup' porque no es una propiedad conocida de 'form')

227+ votos? 127,130+ vistas
johnnyfittizio pregunta,

EL PROBLEMA:

¡por favor! Estoy intentando construir una aplicación de Angular2 muy sencilla pero no funciona.

VERSION DE ANGULAR:

Angular 2.0.0 Rc5

EL ERROR:

Can't bind to 'formGroup' since it isn't a known property of 'form'
SP8f73A8L3lPs6fS9frNubiN5UEniPY2yj3p

EL CÓDIGO:

La vista:

<form [formGroup]="nuevaTareaForm" (submit)="crearNuevaTarea()">
    <div class="form-group">
        <label for="nombre">Nombre</label>
        <input type="text" name="nombre" required>
    </div>
     <button type="submit" class="btn btn-default">Enviar</button>
</form>

El controller - componente:

import { Component } from '@angular/core';
import { FormGroup, FormControl, Validators, FormBuilder }  from '@angular/forms';
import {FormsModule,ReactiveFormsModule} from '@angular/forms';
import { Tarea } from './tarea';

@Component({
    selector: 'tarea-anadir',
    templateUrl: 'app/tarea-anadir.component.html'
    
})

export class TareaAnadirComponent {

    nuevaTareaForm: FormGroup;
    
    constructor(fb: FormBuilder) 
    {
        this.nuevaTareaForm = fb.group({
            nombre: ["", Validators.required]
        });
    }
    
    anadirNuevaTarea()
    {
        console.log(this.nuevaTareaForm.value)
    }
    
}

The ngModule:

import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule }   from '@angular/forms';

import { routing }        from './app.routing';
import { AppComponent }  from './app.component';
import { TareaServicio } from './tarea.servicio'

@NgModule({
    imports: [ 
        BrowserModule,
        routing,
        FormsModule
    ],
    declarations: [ AppComponent ],
    providers: [
        TareaServicio
    ],
    bootstrap: [ AppComponent ]
})

export class AppModule { }

LA PREGUNTA:

¿Por qué me sale ese error?

Stefan Svrkota contesta, (465+ votos)

RC5 - SOLUCIÓN

Necesitas importar import { REACTIVE_FORM_DIRECTIVES } from '@angular/forms' en tu controller y añadirlo a tus directives en @Component.

Cuando tengas eso solucionado, puede que te de otro error porque no has añadido formControlName="nombre" .

RC6/RC7/VERSIÓN FINAL - SOLUCIÓN

Tienes que importar ReactiveFormsModule de@angular/forms en tu módulo. Aquí tienes el ejemplo importando ReactiveFormsModule :

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { AppComponent }  from './app.component';

@NgModule({
    imports: [
        BrowserModule,
        FormsModule,
        ReactiveFormsModule
    ],
    declarations: [
        AppComponent
    ],
    bootstrap: [AppComponent]
})

export class AppModule { }

Para clarificar, formGroup es un selector para una directive llamada FormGroupDirective que es parte de ReactiveFormsModule, por eso hay que importarlo. Se usa para enlazar un FormGroup existente a un elemento del DOM.

Source
Top

Error DI de Angular— EXCEPTION: Can’t resolve all parameters (Excepción: No se pueden resolver todos los parámetros)

221+ votos ? 142,497+ vistas
Keith Otto pregunta,

He construido una aplicación básica en Angular, pero tengo un problema extraño. No puedo inyectar un servicio en uno de mis componentes. Funciona en cualquiera de los otros tres componentes que tengo.

El servicio es este:

import { Injectable } from '@angular/core';

@Injectable()
export class MovilService {
  pantallaAncho: number;
  pantallaAlto: number;
  
  constructor() {
    this.pantallaAncho = window.outerWidth;
    this.pantallaAlto = window.outerHeight;
    
    window.addEventListener("resize", this.onWindowResize.bind(this) )
  }
  
  onWindowResize(ev: Event) {
    var win = (ev.currentTarget as Window);
    this.pantallaAncho = win.outerWidth;
    this.pantallaAlto = win.outerHeight;
  }
  
}

Y el componente en el que no funciona es:

import { Component, } from '@angular/core';
import { NgClass } from '@angular/common';
import { ROUTER_DIRECTIVES } from '@angular/router';

import {MovilService} from '../';

@Component({
  moduleId: module.id,
  selector: 'pm-header',
  templateUrl: 'header.component.html',
  styleUrls: ['header.component.css'],
  directives: [ROUTER_DIRECTIVES, NgClass],
})
export class HeaderComponent {
  movilNav: boolean = false;
  
  constructor(public ms: MovilService) {
    console.log(ms);
  }
  
}

El error que me da es este:

EXCEPTION: Can't resolve all parameters for HeaderComponent: (?).

Tengo al servicio en la función de bootstrap así que tiene un provider. Y lo puedo inyectar en los constructores de los otros componentes que tengo.

Günter Zöchbauer contesta, (272+ votos)

Importalo directamente en el archivo en que es declarado.

No sé exactamente la causa del problema, pero lo he visto mencionado varias veces (probablemente algún tipo de dependencia circular).

También se podría arreglar cambiando el orden de los exports (no sé los detalles pero también lo he visto mencionado antes)

Source
Top

Angular — Establecer los headers (encabezamientos) para cada request (solicitud)

209+ votos? 205,557+ vistas
Avijit Gupta pregunta,

Necesito establecer headers de autorización (Authorization) una vez que el usuario haya iniciado la sesión, para cada solicitud posterior.

Para establecer los headers para una solicitud (request) particular,

import {Headers} from 'angular2/http';
var headers = new Headers();
headers.append(headerName, value);

// HTTP POST con estos headers
this.http.post(url, data, {
  headers: headers
})
// Hacer algo con la respuesta

Pero no sería factible configurar manualmente para cada solicitud.

¿Cómo configuro los encabezados (headers) solamente una vez cuando el usuario inicia la sesión y también cómo los elimino al cerrar la sesión?

Thierry Templier contesta, (283+ votos)

Podrías tener un servicio que envuelva el objecto Http original de Angular. Algo como esto:

import {Injectable} from '@angular/core';
import {Http, Headers} from '@angular/http';

@Injectable()
export class HttpClient {

  constructor(private http: Http) {}
  
  crearAutorizacionHeader(headers: Headers) {
    headers.append('Authorization', 'Basic ' +
      btoa('username:password')); 
  }
  
  get(url) {
    let headers = new Headers();
    this.crearAutorizacionHeader(headers);
    return this.http.get(url, {
      headers: headers
    });
  }
  
  post(url, data) {
    let headers = new Headers();
    this.crearAutorizacionHeader(headers);
    return this.http.post(url, data, {
      headers: headers
    });
  }
}

Y en vez de inyectar el objecto Http inyecta (HttpClient).

import { HttpClient } from './http-client';

export class MiComponent {
  // inyectamos "nuestro" HttpClient, lo llamo Http por simplificar
  constructor(http: HttpClient) {
    this.http = httpClient;
  }
  
  hacerAlgo() {
    this.http.post(url, data).subscribe(result => {
        // console.log( result );
    });
  }
}

También creo que se podría hacer algo usando múltiples proveedores de la clase Http con tu propia clase que extienda la clase Http .

Source
Top

¿Cómo se puede usar *ngIf else en Angular?

205+ votos? 203,768+ vistas
kawli norman pregunta,

Quiero usar *ngIf else (disponible desde la versión 4) en este ejemplo:

<div *ngIf="isValid">
  contenido ...
</div>

<div *ngIf="!isValid">
 otro contenido...
</div>

¿Cómo puedo hacer lo mismo con  ngIf else ?

Bougarfaoui El houcine contesta, (384+ votos)

Angular 4 y 5:

Usando else :

<div *ngIf="isValid;else otro_contenido">
    contenido ...
</div>

<ng-template #otro_contenido>otro contenido...</ng-template>

También puedes usar then else :

<div *ngIf="isValid;then contenido else otro_contenido">esto se ignora</div>

<ng-template #contentenido>contenido...</ng-template>
<ng-template #otro_contenido>otro contenido...</ng-template>

o then  :

<div *ngIf="isValid;then contenido"></div>

<ng-template #contenido>contenido...</ng-template>

Demo :

Plunker

Detalles:

<ng-template> : Es la implementación de Angular de la etiqueta <template> que de acuerdo a MDN :

El elemento HTML <template> es un mecanismo para mantener el contenido HTML del lado del cliente que no se renderiza cuando se carga una página, pero que posteriormente puede ser instanciado durante el tiempo de ejecución empleando JavaScript.

Source
Top

Error: Angular no provider for NameService (No hay proveedor para NombreServicio)

196+ votos? 186,526+ vistas
M.Svrcek pregunta,

Tengo un problema cargando una clase en un componente de Angular. He intentado solucionarlo durante mucho tiempo incluso poniéndolo en un solo fichero.  Tengo esto.

Application.ts

/// <reference path="../typings/angular2/angular2.d.ts" />

import {Component,View,bootstrap,NgFor} from "angular2/angular2";
import {NombreService} from "./services/NombreService";

@Component({
    selector:'mi-app',
    injectables: [NombreService]
})
@View({
    template:'<h1>Hola {{nombre}}</h1>' +
    '<p>Amigos</p>' +
    '<ul>' +
    '   <li *ng-for="#nombre of nombres">{{nombre}}</li>' +
    '</ul>',
    directives:[NgFor]
})

class MiAppComponent
{
    nombre:string;
    nombres:Array<string>;
    
    constructor(nombreService:NombreService)
    {
        this.nombre = 'Michal';
        this.nombres = nombreService.getObtenNombres();
    }
}
bootstrap(MiAppComponent);

services/NombreService.ts

export class NombreService {
    nombres: Array<string>;
    constructor() {
        this.nombres = ["Alice", "Aarav", "Martín", "Shannon", "Ariana", "Kai"];
    }
    getObtenNombres()
    {
        return this.nombres;
    }
}

Me da el error “No provider for NombreService” …

¿Puede alguien ayudarme?

Klas Mellbourn contesta, (309+ votos)

Tienes que usar providers en lugar de injectables

@Component({
    selector: 'mi-app',
    providers: [NombreService]
})

Source
Top

Vinculando el elemento seleccionado a un object en Angular

194+ votos? 197,048+ vistas
RHarris pregunta,

Soy nuevo en Angular y estoy intentando familiarizarme con las novedades.

Me gustaría vincular un elemento seleccionado a una lista de objectos:

@Component({
   selector: 'miApp',
   template: `<h1>Mi Aplicacion</h1>
              <select [(ngModel)]="valorSeleccionado">
                 <option *ngFor="#p de paises" value="p.id">{{c.nombre}}</option>
              </select>`
})
export class AppComponent{
    paises = [
       {id: 1, nombre: "United States"},
       {id: 2, nombre: "Australia"}
       {id: 3, nombre: "Canada"}
       {id: 4, nombre: "Brazil"}
       {id: 5, nombre: "England"}
     ];
    valorSeleccionado = null;
}

En este caso, parece que valorSeleccionado sería un numero — el id del seleccionado.

Sin embargo, lo que quiero es vincular al objecto país para el que valorSeleccionado es el objecto y no el id.  He intentado esto:

<option *ngFor="#c de paises" value="c">{{c.nombre}}<;/option>

pero parece que no funciona. Parece que pone un objeto en mi valorSeleccionado — pero no el objeto que espero. Lo puedes ver en mi Plunker.

También he intentado cambiar el evento change para asignar el objeto yo mismo basado en el id; pero parece que el evento sucede antes de que se haya vinculado ngModel con el valor actualizado — en ese momento no tengo acceso al valor nuevo.

Hay una forma limpia de vincular un elemento seleccionado a un objeto de Angular 2?

Günter Zöchbauer contesta, (361+ votos)
<h1>Mi Aplicacion</h1>
<select [(ngModel)]="valorSeleccionado">
  <option *ngFor="let p of paises" [ngValue]="p">{{p.nombre}}</option>
</select>

Plunker

NOTA: puedes usar  [ngValue]="p" en lugar de  [ngValue]="p.id" donde p es el objeto para el país.

[value]="..." solamente acepta cadenas
[ngValue]="..." acepta cualquier tipo

actualización

Si el value es un objeto, la instancia preseleccionada debe ser identica a uno de los valores.

desde 4.0.0-beta.7 también se puede comparar así:

<select [compareWith]="compareFn" ...

Cuidado si quieres acceder a this dentro de compareFn.

compareFn = this._compareFn.bind(this);

// o 
// compareFn = (a, b) => this._compareFn(a, b);

_comareFn((a, b) {
   if(this.x ...) {
     ...
}

Source
Top

¿Cuál es la diferencia entre declaraciones, proveedores e importación (import) en NgModule?

188+ votos? 55,432+ vistas
Ramesh Papaganti pregunta,

Estoy intentando entender Angular (también llamado Angular2+), y me he encontrado esto.  

@Module

  1. Imports
  2. Declarations
  3. Providers
Günter Zöchbauer contesta, (277+ votos)

Conceptos de Angular

  • imports hace que las declaraciones exportadas (exports) de otros módulos estén disponibles en el módulo actual
  • declarations : se usan para crear directives (incluyendo componentes y pipes) desde el módulo actual para que esten disponibles para otras directives (como otros componentes) en el mismo módulo. Los selectores de directives, componentes o conductos (pipes) solamente se comparan con el HTML si se declaran o importan.
  • providers se usan para dar a conocer servicios y valores al DI (dependency injection : inyección de dependencias). Se añaden al ámbito raíz (root) y se inyectan a otros servicios o directivas que los tengan como dependencia.

Un caso especial para providers son módulos con carga diferida que obtienen su propio inyector secundario (child). providers de estos tipos de módulos solo se proporcionan a estos módulos de carga diferida (no a toda la aplicación como ocurre con otros módulos).

  • exports hace que los componentes, directives, y pipes (conductos) esten disponibles para los modulos que añadan este módulo a imports. exports también se puede usar para re-exportar módulos como CommonModule y FormsModule, lo que se hace a menudo en módulos compartidos.
  • entryComponents registra componentes para la compilación fuera de línea para que puedan usarse con ViewContainerRef.createComponent(). Los componentes utilizados en las configuraciones del enrutador se agregan implícitamente.

TypeScript (ES2015) imports

import ... from 'foo/bar' son para imports de TypeScript. Los necesitas cuando usas un identificador en un fichero de TypeScript que es declarado en otro fichero de TypeScript.

Los  @NgModule() imports de Angular y el  import de TypeScript son conceptos diferentes.

La mayoría son simplemente la sintaxis ECMAScript 2015 (ES6) de módulo que también usa TypeScript.

Source
Top

En Angular, ¿Cómo se determina la ruta activa?

187+ votos? 100,870+ vistas
Michael Oryl pregunta,

NOTA: Hay muchas respuestas diferentes, la mayoría han sido validas en algún momento. Lo que funciona ha cambiado varias veces a medida que el equipo de Angular ha cambiado el funcionamiento del Router. El Router version 3.0 que será el router en Angular no funciona con algunas de estas soluciones sino que  el mismo router ofrece una solución muy simple. Desde RC.3, la solucián mas aceptada es usar [routerLinkActive] como se muestra aquí.

En una aplicación de Angular (en 2.0.0-beta.0 cuando escribo esto), ¿Cómo se determina cuál es la ruta activa?

Estoy trabajando en una aplicación que usa Bootstrap 4 y necesito una forma de marcar la navegación enlaces/botones (links/buttons) como activos cuando su componente asociado es el que se muestra en la etiqueta  <router-output> .

Sé que puedo mantener el estado yo mismo cuando se pulsa un botón, pero eso no valdría cuando tengo varias trayectorias en la misma ruta (como un menu principal y otro local en el componenete principal).

Cualquier sugerencia o enlace sería apreciado. Gracias.

jessepinho contesta, (229+ votos)

Con el router nuevo de Angular, puedes añadir el atributo [routerLinkActive]="['tu-nombre-de-class']" a todos tus enlaces:

<a [routerLink]="['/home']" [routerLinkActive]="['is-active']">Home</a>

O la forma simplificada sin el array si solo se necesita una clase:

<a [routerLink]="['/home']" [routerLinkActive]="'is-active'">Home</a>

Source
Top

Opciones CLI SASS de Angular

187+ votos? 106,289+ vistas
JDillon522 pregunta,

Soy nuevo en Angular y vengo de la comunidad Ember. Estoy intentando usar el nuevo Angular-CLI basado en Ember-CLI.

Necesito saber la mejor manera de trabajar con SASS en un nuevo proyecto de Angular. He intentado usar el repo ember-cli-sass para ver si podía seguirlo ya que hay un número de componentes comunes enAngular-CLI que están basados en módulos de Ember-CLI.

No ha funcionado pero no estoy seguro de estar configurando las cosas bien.

Además, ¿Cuál es la mejor manera de organizar estilos en un nuevo proyecto de Angular? Estaría bien tener el fichero sass en la misma carpeta que el componente.

Mertcan Diken contesta, (323+ votos)

Cuando estés creando el proyecto, utiliza esto:

ng new Mi_Nuevo_Proyecto --style=sass

Esto crea tus ficheros con el estilo sass determinado.

Si quieres tu propia sintaxis de scss crea el proyecto de esta manera :

ng new Mi_Nuevo_Proyecto --style=scss

Si estás cambiando el estilo en tu proyecto:

ng set defaults.styleExt scss

CLI hace el resto.

Source
Top

Activar la detección de cambios en Angular manualmente

186+ votos? 102,556+ vistas
jz87 pregunta,

Estoy escribiendo un componente en Angular con la propierdad Mode(): string. Me gustaría darle un valor programáticamente y no como respuesta a un evento. El problema es que no teniendo un evento del navegador, una plantilla enlazando a {{Mode}} no se muestra actualizada. ¿hay alguna manera de activar el cambio manualmente?

Mark Rajcok contesta, (345+ votos)

Prueba alguna de estas:

  • ApplicationRef.tick() - similar a $rootScope.$digest() de AngularJS's-- i.e., chequear el árbol de herarquía completo.
  • NgZone.run(callback) - similar a $rootScope.$apply(callback) -- i.e., evalua la función de callback dentro de la zona de Angular. Creo, pero no lo sé seguro, que esto acaba comprobando todo el árbol del componente después de ejecutar la función callback.
  • ChangeDetectorRef.detectChanges() - similar a $scope.$digest() -- i.e., comprueba solamente este componente y sus hijos.

Puedes inyecar ApplicationRef, NgZone, o ChangeDetectorRef en tu componente.

Source
Top

Angular y Typescript: No se pueden encontrar los nombres.

184+ votos? 181,472+ vistas
user233232 pregunta,

Estoy usando Angular (versión 2) con TypeScript (versión 1.6) y al compilar me salen estos errores:

Error TS2304: Cannot find name 'Map'.
    node_modules/angular2/src/core/change_detection/parser/locals.d.ts(4,42): Error TS2304: Cannot find name 'Map'.
    node_modules/angular2/src/core/facade/collection.d.ts(1,25): Error TS2304: Cannot find name 'MapConstructor'.
    node_modules/angular2/src/core/facade/collection.d.ts(2,25): Error TS2304: Cannot find name 'SetConstructor'.
    node_modules/angular2/src/core/facade/collection.d.ts(4,27): Error TS2304: Cannot find name 'Map'.
    node_modules/angular2/src/core/facade/collection.d.ts(4,39): Error TS2304: Cannot find name 'Map'.
    node_modules/angular2/src/core/facade/collection.d.ts(7,9): Error TS2304: Cannot find name 'Map'.
    node_modules/angular2/src/core/facade/collection.d.ts(8,30): Error TS2304: Cannot find name 'Map'.
    node_modules/angular2/src/core/facade/collection.d.ts(11,43): Error TS2304: Cannot find name 'Map'.
    node_modules/angular2/src/core/facade/collection.d.ts(12,27): Error TS2304: Cannot find name 'Map'.
    node_modules/angular2/src/core/facade/collection.d.ts(14,23): Error TS2304: Cannot find name 'Map'.
    node_modules/angular2/src/core/facade/collection.d.ts(15,25): Error TS2304: Cannot find name 'Map'.
    node_modules/angular2/src/core/facade/collection.d.ts(94,41): Error TS2304: Cannot find name 'Set'.
    node_modules/angular2/src/core/facade/collection.d.ts(95,22): Error TS2304: Cannot find name 'Set'.
    node_modules/angular2/src/core/facade/collection.d.ts(96,25): Error TS2304: Cannot find name 'Set'.
    node_modules/angular2/src/core/facade/lang.d.ts(1,22): Error TS2304: Cannot find name 'BrowserNodeGlobal'.
    node_modules/angular2/src/core/facade/lang.d.ts(33,59): Error TS2304: Cannot find name 'Map'.
    node_modules/angular2/src/core/facade/promise.d.ts(1,10): Error TS2304: Cannot find name 'Promise'.
    node_modules/angular2/src/core/facade/promise.d.ts(3,14): Error TS2304: Cannot find name 'Promise'.
    node_modules/angular2/src/core/facade/promise.d.ts(8,32): Error TS2304: Cannot find name 'Promise'.
    node_modules/angular2/src/core/facade/promise.d.ts(9,38): Error TS2304: Cannot find name 'Promise'.
    node_modules/angular2/src/core/facade/promise.d.ts(10,35): Error TS2304: Cannot find name 'Promise'.
    node_modules/angular2/src/core/facade/promise.d.ts(10,93): Error TS2304: Cannot find name 'Promise'.
    node_modules/angular2/src/core/facade/promise.d.ts(11,34): Error TS2304: Cannot find name 'Promise'.
    node_modules/angular2/src/core/facade/promise.d.ts(12,32): Error TS2304: Cannot find name 'Promise'.
    node_modules/angular2/src/core/facade/promise.d.ts(12,149): Error TS2304: Cannot find name 'Promise'.
    node_modules/angular2/src/core/facade/promise.d.ts(13,43): Error TS2304: Cannot find name 'Promise'.
    node_modules/angular2/src/core/linker/element_injector.d.ts(72,32): Error TS2304: Cannot find name 'Map'.
    node_modules/angular2/src/core/linker/element_injector.d.ts(74,17): Error TS2304: Cannot find name 'Map'.
    node_modules/angular2/src/core/linker/element_injector.d.ts(78,184): Error TS2304: Cannot find name 'Map'.
    node_modules/angular2/src/core/linker/element_injector.d.ts(83,182): Error TS2304: Cannot find name 'Map'.
    node_modules/angular2/src/core/linker/element_injector.d.ts(107,37): Error TS2304: Cannot find name 'Map'.
    node_modules/angular2/src/core/linker/proto_view_factory.d.ts(27,146): Error TS2304: Cannot find name 'Map'.
    node_modules/angular2/src/core/linker/view.d.ts(52,144): Error TS2304: Cannot find name 'Map'.
    node_modules/angular2/src/core/linker/view.d.ts(76,79): Error TS2304: Cannot find name 'Map'.
    node_modules/angular2/src/core/linker/view.d.ts(77,73): Error TS2304: Cannot find name 'Map'.
    node_modules/angular2/src/core/linker/view.d.ts(94,31): Error TS2304: Cannot find name 'Map'.
    node_modules/angular2/src/core/linker/view.d.ts(97,18): Error TS2304: Cannot find name 'Map'.
    node_modules/angular2/src/core/linker/view.d.ts(100,24): Error TS2304: Cannot find name 'Map'.
    node_modules/angular2/src/core/linker/view.d.ts(103,142): Error TS2304: Cannot find name 'Map'.
    node_modules/angular2/src/core/linker/view.d.ts(104,160): Error TS2304: Cannot find name 'Map'.
    node_modules/angular2/src/core/render/api.d.ts(281,74): Error TS2304: Cannot find name 'Map'.
    node_modules/angular2/src/core/zone/ng_zone.d.ts(1,37): Error TS2304: Cannot find name 'Zone'.

Este es el código:

import 'reflect-metadata';
import {bootstrap, Component, CORE_DIRECTIVES, FORM_DIRECTIVES} from 'angular2/core';
@Component({
  selector: 'mi-app',
  template: '<input type="text" [(ng-model)]="titulo" /><h1>{{titulo}}</h1>',
  directives: [ CORE_DIRECTIVES ]
})
class AppComponent {
  titulo :string;
  
  constructor() {
    this.titulo = 'hola angular 2';
  }
}
bootstrap(AppComponent);
basarat contesta, (50+ votos)

Un problema conocido,

La razón principal: el fichero .d.ts incluido implícitamente con TypeScript varía con el objetivo de compilación, así que se necesitan más variables de entorno cuando el objetivo es es5 incluso si las cosas están presentes en runtimes (e.g. chrome).

Source
Top

Angular — ¿Cuál es el significado de module.id en el componente?

181+ votos? 54,337+ vistas
Nishchit Dhanani pregunta,

En una aplicación de Angular, he visto que @Component tiene la propiedadmoduleId. ¿Qué significa?

Y cuando module.id no está definida en ningún sitio, la app aún funciona. ¿Cómo puede seguir funcionando?

@Component({
  moduleId: module.id,
  selector: 'ng-app',
  templateUrl: 'app.component.html',
  styleUrls: ['app.component.css'],
  directives: [AppComponent]
});
Nishchit Dhanani contesta, (145+ votos)

El lanzamiento beta de Angular (desde la versión 2-alpha.51) admite activos relativos para componentes, como templateUrl y  styleUrls en  @Component.

module.id funciona cuando se usa CommonJS. No debe preocuparte como funciona.

Recuerda: establecer moduleId: module.id en @Component es la clave aquí. Si no tienes eso, Angular 2 busca tus ficheros a nivel de la raíz.

Actualizado a 16 Sep 2016:

Si estás usando webpack para empaquetar no necesitas module.id en @Component. Webpack lo añade automáticamente al final del paquete.

Source
Top

¿Cómo se puede obtener una nueva selección en "select" en Angular 2?

175+ votos? 203,064+ vistas
Hongbo Miao pregunta,

Estoy usando Angular 2 (TypeScript).

Quiero hacer algo para una selección nueva, pero cuando llego a onChange() siempre tiene la última selección. ¿Cómo puedo obtener la nueva?

<select [(ngModel)]="dispositivoSeleccionado" (change)="onChange($event)">
    <option *ngFor="#i of dispositivos">{{i}}</option>
</select>

onChange($event) {
    console.log(this.dispositivoSeleccionado);
    // Aqui quiero hacer algo para el nuevo, 
    // pero me sale el anterior, no lo que acabo de seleccionar
}
Mark Rajcok contesta, (370+ votos)

Si no necesitas enlace de datos bidireccional:

<select (change)="onChange($event.target.value)">
    <option *ngFor="let i of dispositivos">{{i}}</option>
</select>

onChange(valorDispositivo) {
    console.log(valorDispositivo);
}

Para enlace de datos bidireccional,  separa el enlace del evento y la propiedad:

<select [ngModel]="dispositivoSeleccionado" (ngModelChange)="onChange($event)" name="sel2">
    <option [value]="i" *ngFor="let i of dispositivo">{{i}}</option>
</select>

export class AppComponent {
  dispositivos = 'uno dos tres'.split(' ');
  dispositivoSeleccionado = 'dos';
  onChange(nuevoValor) {
    console.log(nuevoValor);
    this.dispositivoSeleccionado = nuevoValor;
    // ... otras cosas  ...
}

Si dispositivos es un arreglo de objectos, enlaza ngValue en lugar de value:

<select [ngModel]="dispositivoSeleccionadoObj" (ngModelChange)="onChangeObj($event)" name="sel3">
  <option [ngValue]="i" *ngFor="let i of dispositivosObjectos">{{i.nombre}}</option>
</select>
{{dispositivoSeleccionadoObj | json}}

export class AppComponent {
  dispositivosObjectos = [{nombre: 1}, {nombre: 2}, {nombre: 3}];
  dispositivoSeleccionadoObj = this.dispositivosObjectos[1];
  onChangeObj(nuevoObj) {
    console.log(nuevoObj);
    this.dispositivoSeleccionadoObj = nuevoObj;
    // ... otras cosas ...
  }
}

Plunker — no usa <form>
Plunker - usa <form> y usa las nuevas forms API.

Source
Top

Excepción de Angular: Can’t bind to ‘ngForIn’ since it isn’t a known native property (No se puede vincular a 'ngForIn' porque no es una propiedad nativa conocida.

172+ votos? 48,252+ vistas
Mark Rajcok pregunta,

¿Qué estoy haciendo mal?

import {bootstrap, Component} from 'angular2/angular2'

@Component({
  selector: 'conf-charlas',
  template: `<div *ngFor="let charla in charlas">
     {{charla.titulo}} by {{charla.orador}}
     <p>{{charla.descripcion}}
   </div>`
})
class ConfCharlas {
  talks = [ {titulo: 't1', orador: 'Brian', descripcion: 'charla 1'},
            {titulo: 't2', orador: 'Julie', descripcion: 'charla 2'}];
}
@Component({
  selector: 'mi-app',
  directives: [ConfCharlas],
  template: '<conf-charlas></conf-charlas>'
})
class App {}
bootstrap(App, [])

El error:

EXCEPTION: Template parse errors:
Can't bind to 'ngForIn' since it isn't a known native property
("<div [ERROR ->]*ngFor="let charla in charlas">
Mark Rajcok contesta, (403+ votos)

Dado que esta es por lo menos la tercera vez que he perdido más de 5 minutos en este problema, he pensado en publicar las preguntas y respuestas. Espero que ayude a alguien más en el futuro... ¡probablemente a mí!

Puse in en lugar de of en el ngFor.

Antes de 2-beta.17, debería ser:

<div *ngFor="#charla of charlas">

En beta.17, usa la sintaxis let en lugar de #. Mira la ACTUALIZACIÓN más abajo.

Date cuenta que la sintaxis ngFor se convierte en:

<template ngFor #charla [ngForOf]="charlas">
  <div>...</div>
</template>

Si usamos in , se convierte en

<template ngFor #charla [ngForIn]="charlas">
  <div>...</div>
</template>

Ya que ngForIn no es una directive con una propiedad de input con el mismo nombre (como ngIf), Angular intenta ver si es una propiedad conocida (nativa) del elemento template y si no lo es, sale el error.

ACTUALIZACIÓN— en  2-beta.17, usa  let en lugar de #. Esto cambia lo siguiente:

<div *ngFor="let charla of charlas">

Date cuenta de que ngFor se convierte en:

<template ngFor let-charla [ngForOf]="charlas">
  <div>...</div>
</template>

Si usas  in se convierte en

<template ngFor let-charla [ngForIn]="charlas">
  <div>...</div>
</template>

Source
Top

*ngIf y *ngFor en el mismo elemento causa un error

171+ votos? 85,728+ vistas
garethdn pregunta,

Tengo un problema usando los *ngFor y *ngIf de Angular si los uso en el mismo elemento.

Cuando intento recorrer la colección con *ngFor, la colección se ve como null y da error al intentar acceder a sus propiedades.

@Component({
  selector: 'shell',
  template: `
    <h3>Shell</h3><button (click)="toggle()">Toggle!</button>
    
    <div *ngIf="muestra" *ngFor="let cosa of cosas">
      {{log(cosa)}}
      <span>{{cosa.nombre}}</span>
    </div>
  `
})

export class ShellComponent implements OnInit {

  public cosas:any[] = [];
  public muestra:boolean = false;
  
  constructor() {}
  
  ngOnInit() {
    this.cosas = [
      { nombre: 'abc', id: 1 },
      { nombre: 'huo', id: 2 },
      { nombre: 'bar', id: 3 },
      { nombre: 'foo', id: 4 },
      { nombre: 'thing', id: 5 },
      { nombre: 'other', id: 6 },
    ]
  }
  
  toggle() {
    this.muestra = !this.muestra;
  }
  
  log(cosa) {
    console.log(cosa);
  }
  
}

Sé que lo fácil es mover *ngIf un nivel más arriba pero para casos como recorrer una lista de elementos en una ul, acabaría con un li vacío si la colección no tiene elementos, o mi li está envuelto en contenedores de elementos redundantes.

Ejemplo en plnkr.

Este es el error:

EXCEPTION: TypeError: Cannot read property 'nombre' of null in [{{cosa.nombre}} in ShellComponent@5:12]

¿Estoy haciendo algo mal o es un error?

Günter Zöchbauer contesta, (284+ votos)

Angular2 no permite más de una directiva (directive) estructural en el mismo elemento.
Puedes usar el elemento <ng-container> para separar los elementos con cada directiva estructural, pero no está estampada en el DOM.

<ng-container *ngIf="muestra">
  <div *ngFor="let cosa of cosas">
    {{log(cosa)}}
    <span>{{cosa.nombre}}</span>
  </div>
</ng-container>

<ng-template> (<template> antes de Angular4) te deja hacer lo mismo pero de manera diferente, con una sintaxis confusa y no recomendada

<ng-template [ngIf]="muestra">
  <div *ngFor="let cosa of cosas">
    {{log(cosa)}}
    <span>{{cosa.nombre}}</span>
  </div>
</ng-template>

Source
Top

¿Cuál es el equivalente del $watch de AngularJS en Angular?

169+ votos ? 95,029+ vistas
Erwin pregunta,

En AngularJS se podían especificar watchers (observadores) para observar cambios en las variables usando  $watch de $scope. ¿Cuál es el equivalente de observar cambios de variables (en, por ejemplo, variables de componentes) en Angular?

Mark Rajcok contesta, (226+ votos)

En Angular 2, la detección de cambios es automática… $scope.$watch() y $scope.$digest() D.E.P.

Desafortunadamente, la sección de detección de cambios de la guía para desarrolladores aún no está escrita.

Aquí está como lo entiendo yo:

  • Zone.js  —intercepta todas las API asíncronas en el navegador (cuando Angular está corriendo). Por eso podemos usar setTimeout() dentro de nuestros componentes en lugar de algo como $timeout... porquesetTimeout() se cambia durante en runtime.
  • Angular construye y mantiene un árbol de "detectores de cambio". Hay uno (class) por componente/directive. (Puede obtener acceso a este objeto inyectando ChangeDetectorRef.) Estos detectores de cambios se crean cuando Angular crea componentes. Realizan un seguimiento del estado de todos tus enlaces, para ver si han cambiado. Estos son, en cierto sentido, similares a los  $watches() automáticos que Angular 1 establecería para los enlaces {{}} en la plantilla (template).
    A diferencia de Angular 1, el gráfico de detección de cambios es un árbol dirigido y no puede tener ciclos (esto hace que Angular 2 tenga mucho más rendimiento, como veremos a continuación.).
  • Cuando se dispara un evento (dentro de la zona Angular), se ejecuta el código que escribimos (la devolución de llamada del controlador de eventos).Puede actualizar cualquier tipo de datos que quiera— el modelo de la aplicació compartido/estado y/o el estado de la vista (view) del componente.
  • Después de eso, debido a los ganchos añadidos por Zone.js, ejecuta el algoritmo de detección de cambios de Angular. De forma predeterminada (es decir, si no está utilizando la detección de cambio onPush en ninguno de tus componentes), cada componente del árbol se examina una vez (TTL=1)... desde arriba, en primer orden de profundidad. (Bueno, si estás en modo desarrollador, la detección de cambios se ejecuta dos veces (TTL=2). Realiza comprobaciones de cambios en todos sus enlaces, utilizando esos objetos detectores de cambios.
  • Se llama a los enlaces de ciclo de vida como parte de la detección de cambios.
    Si los datos del componente que deseas ver son una propiedad de entrada primitiva(String, boolean, number), puedes implementar ngOnChanges() para que se te notifique de los cambios.
    Si la propiedad de entrada es un tipo de referencia (object, array, etc.), pero la referencia no cambió (e.g., agregaste un elemento a un arreglo existente), tendrás que implementar ngDoCheck() .
    Solamente debes cambiar las propiedades del componente y/o las propiedades de los componentes descendientes (debido a la implementación de recorrido de un solo árbol -- i.e., flujo de datos unidireccional). Aqui hay un ejemplo en plunker que no lo cumple.
  • Para cualquier cambio de vinculación que se encuentre, los componentes se actualizan y, a continuación, se actualiza el DOM. La detección de cambios ya ha finalizado.
  • El navegador nota los cambios de DOM y actualiza la pantalla.

Otras referencias para saber más:

  • Savkin’s Deteción de cambios reinventada — video (puedes configurar para que se subtitule)
  • El video de Brian y el de Miško sobre Zone.js. El de Brian es sobre Zone.js. El de Miško trata sobre cómo Angular 2 usa Zone.js para implementar la detección de cambios. También habla sobre la detección de cambios en general, y un poco sobre onPush.

Source
Top

Importando lodash en angular2 + aplicaciones typescript

167+ votos? 104,431+ vistas
Davy pregunta,

Me está costando importar los módulos de lodash. He creado mi proyecto con npm+gulp, y sigo chocando con la misma pared. He probado con el lodash convencional, pero también lodash-es.

El paquete de lodash de npm: (tiene un fichero index.js en la carpeta raíz)

import * as _ from 'lodash';

Resultado:

error TS2307: Cannot find module 'lodash'.

El paquete de lodash-es de npm: (tiene un export lodash.js por defecto en la carpeta raíz)

import * as _ from 'lodash-es/lodash';

Resultado:

error TS2307: Cannot find module 'lodash-es'.

Tanto gulp como webstorm tienen el mismo problema.

Lo curioso es que esto no da error:

import 'lodash-es/lodash';

… pero no hay  “_” …

Mi fichero tsconfig.json:

{
  "compilerOptions": {
    "target": "es5",
    "module": "system",
    "moduleResolution": "node",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "removeComments": false,
    "noImplicitAny": false
  },
  "exclude": [
    "node_modules"
  ]
}

Mi gulpfile.js:

var gulp = require('gulp'),
    ts = require('gulp-typescript'),
    uglify = require('gulp-uglify'),
    sourcemaps = require('gulp-sourcemaps'),
    tsPath = 'app/**/*.ts';
    
gulp.task('ts', function () {
    var tscConfig = require('./tsconfig.json');
    
    gulp.src([tsPath])
        .pipe(sourcemaps.init())
        .pipe(ts(tscConfig.compilerOptions))
        .pipe(sourcemaps.write('./../js'));
});

gulp.task('watch', function() {
    gulp.watch([tsPath], ['ts']);
});

gulp.task('default', ['ts', 'watch']);

Si lo entiendo bien, moduleResolution:’node’ en mi tsconfig debería apuntar los imports al fichero node_modules, donde lodash y lodash-es están instalados. También he probado maneras diferentes de importar: trayectorias (paths) absolutas, relativas, pero nada funciona. ¿alguna idea?

Si es necesario puedo poner un pequeño fichero zip.

Taytay contesta, (293+ votos)

Así es como se hace con Typescript 2.0: (tsd y typings están en desuso a favor de lo siguiente):

$ npm install --save lodash

# Esto es lo nuevo: 
$ npm install --save @types/lodash

Luego en tu fichero .ts:

Esto:

import * as _ from "lodash";

O esto (sugerido por @Naitik):

import _ from "lodash";

No sé seguro cual es la diferencia. Nosotros preferimos y usamos la primera sintaxis. Sin embargo, hay quien dice que a ellos no les funciona, y alguien más comentó que la segunda sintaxis es incompatible con módulos de webpack en lazy loaded.

Editado el 27th Febrero, 2017:

Según @Koert abajo, import * as _ from "lodash"; es la única sintaxis que funciona con Typescript 2.2.1, lodash 4.17.4, y @types/lodash 4.14.53. Dice que la otra sintaxis da el error "has no default export" (no tiene export por defecto).

Source
Top

¿Cómo se detecta un cambio de ruta en Angular?

160+ votos? 108,593+ vistas
AngularM pregunta,

Quiero detectar un cambio de ruta en AppComponent.

A partir de entonces, comprobaré el token de usuario global para ver si ha iniciado sesión. Luego, puedo redirigir al usuario si no ha iniciado sesión.

Ludohen contesta, (223+ votos)

En Angular 2 puedes subscribe (evento Rx) a una instancia de Router. Entonces puesdes hacer cosas como esta:

class MiClase {
  constructor(private router: Router) {
    router.subscribe((val) => /*lo que sea*/)
  }
}

Editado (desde rc.1)

class MiClase {
  constructor(private router: Router) {
    router.changes.subscribe((val) => /*lo que sea*/)
  }
}

Editado 2 (desde 2.0.0)

class MiClase {
  constructor(private router: Router) {
    router.events.subscribe((val) => {
        // ver tambien
        console.log(val instanceof NavigationEnd) 
    });
  }
}

Source
Top

Global Events en Angular (eventos globales)

157+ votos ? 83,980+ vistas
skovmand pregunta,

¿hay equivalente a $scope.emit() o $scope.broadcast() en Angular?

Conozco la funcionalidad de EventEmitter , pero según lo entiendo yo, eso emite un evento al elemento HTML padre.

¿Qué pasa si necesito comunicarme entre elementos al misno nivel (siblings) o entre un componente en la raíz del DOM y un elemento anidado a varios niveles de profundidad?

pixelbits contesta, (304+ votos)

No hay equivalente a $scope.emit() o $scope.broadcast() de AngularJS. EventEmitter dentro de un componente es bastante parecido, pero como tu dices, solamente emite al elemento padre inmediato.

En Angular, hay otras alternativas que trato de explicar abajo.

Los enlaces con @Input() permiten que el modelo de aplicación se conecte en un elemento gráfico (raíz a hojas). El comportamiento por defecto de un detector de cambios de un componente es propagar todos los cambios a un modelo de la aplicación para todos los enlaces desde cualquier componente conectado.

Aclarando: Hay dos tipos de modelos: View Models (vista) y Application Models (aplicación). Uno de aplicación se conecta con enlaces @Input(). Uno de view  (vista) es una propiedad de componente (no decorado con @Input()) que está enlazado en la plantilla del componente.

Contestando a tus preguntas:

¿Qué pasa si necesito comunicarme entre componentes hermanos?

  1. Application Model Compartido: Los hermanos pueden comunicarse a través de un modelo de aplicación compartida (al igual que angular 1). Por ejemplo, cuando un hermano realiza un cambio en un modelo, el otro hermano que tiene enlaces al mismo modelo se actualiza automáticamente.
  2. Eventos de Componente: Los componentes hijos pueden emitir un evento al componente padre mediante enlaces @Output(). El componente principal puede manejar el evento y manipular el modelo de aplicación o su propio modelo de vista. Cambios a un Application Model se propagan automáticamente a todos los componentes que se unen directa o indirectamente al mismo modelo.
  3. Eventos de Servicio: Los componentes pueden suscribirse a eventos de servicio. Por ejemplo, dos componentes hermanos pueden suscribirse al mismo evento de servicio y responder modificando sus respectivos modelos. Más sobre esto a continuación.

¿Cómo puedo comunicarme entre un componente raíz y un componente anidado a varios niveles de profundidad?

  1. Application Model Compartido: El modelo de aplicación se puede pasar del componente raíz a subcomponentes profundamente anidados a través de enlaces @Input(). Los cambios en un modelo desde cualquier componente se propagarán automáticamente a todos los componentes que comparten el mismo modelo.
  2. Eventos de Servicio: También puede mover EventEmitter a un servicio compartido, lo que permite que cualquier componente inyecte el servicio y se suscriba al evento. De esa forma, un componente Root puede llamar a un método de servicio (normalmente mutando el modelo), que a su vez emite un evento. Varios niveles más abajo, un componente secundario que también inyectó el servicio y se suscribió al mismo evento, puede manejarlo. Cualquier controlador de eventos que cambie un Application Model compartido, se propagará automáticamente a todos los componentes que dependen de él. Esto debe ser lo más parecido a $scope.broadcast() de Angular 1. La siguiente sección describe esta idea con más detalle.

Ejemplo de un servicio Observable que usa eventos de servicio para propagar los cambios

Cuando se añade un ElementoPendiente, el servicio notifica a sus suscriptores.

export class ElementoPendiente {
    constructor(public nombre: string, public hecho: boolean) {
    }
}
export class ServicioPendiente {
    public elementosAnadidos$: EventEmitter<ElementoPendiente>;
    private pendienteLista: ElementoPendiente[] = [];
    
    constructor() {
        this.elementosAnadidos$ = new EventEmitter();
    }
    
    public lista(): ElementoPendiente[] {
        return this.pendienteLista;
    }
    
    public anadir(elem: ElementoPendiente): void {
        this.pendienteLista.push(elem);
        this.elementosAnadidos$.emit(elem);
    }
}

Un elemento en la raíz se suscribiría de esta forma:

export class RaizComponent {
    private elementoAnadido: ElementoPendiente;
    constructor(servicioPendiente: ServicioPendiente) {
        servicioPendiente.elementosAnadidos$.subscribe(elem => this.onElementoAnadido(elem));
    }
    
    private onElementoAnadido(elem: ElementoPendiente): void {
        // haz algo con el elemento anandido
        this.elementoAnadido = elem;
    }
}

Un elemento hijo unos cuantos niveles más abajo se suscribiría así:

export class NietoComponent {
    private elemementoAnadido: ElementoPendiente;
    constructor(servicioPendiente: ServicioPendiente) {
        servicioPendiente.elementosAnadidos$.subscribe(elem => this.onElementoAnadido(elem));
    }
    
    private onElementoAnadido(elem: ElementoPendiente): void {
        // haz algo con el elemento anadido
        this.elemementoAnadido = elem;
    }
}

Este es el componente que llama al servicio para lanzar el evento (puede estar en cualquier sitio del componente):

@Component({
    selector: 'lista-pendiente',
    template: `
         <ul>
            <li *ngFor="#item of modelo"> {{ item.nombre }}
            </li>
         </ul>
        <br />
        Anadir elemento <input type="text" #txt /> <button (click)="anadir(txt.value); txt.value='';">Anadir</button>
    `
})
export class TriggeringComponent{
    private modelo: ElementoPendiente[];
    
    constructor(private servicioPendiente: ServicioPendiente) {
        this.modelo = servicioPendiente.lista();
    }
    
    anadir(value: string) {
        this.servicioPendiente.add(new ElementoPendiente(value, false));
    }
}

Source
Top

¿Cuales son algunas diferencias entre SystemJS y Webpack?

155+ votos? 60,183+ vistas
smartmouse pregunta,

Estoy creando mi primera aplicación de Angular y me pregunto por qué necesitamos los cargadores de módulos. He intentando encontrarlo en Google y no entiendo por qué hay que instalar uno de ellos para correr la aplicación.

¿No sería suficiente usar  import para cargar cosas de los módulos de node?

He encontrado este ejemplo en un tutorial de Angular (que usa SystemJS) y me hace usar el fichero systemjs.config.js :

/**
 * configuracion para ejemplos
 * ajustar como sea necesario para tu aplicacion
 */
(function(global) {
  // map le dice al System Loader donde buscar
  var map = {
    'app':                        'transpiled', // 'dist',
    '@angular':                   'node_modules/@angular',
    'angular2-in-memory-web-api': 'node_modules/angular2-in-memory-web-api',
    'rxjs':                       'node_modules/rxjs'
  };
  // packages le dice al System loader como cargar cuando no hay nombre de fichero y/o extension
  var packages = {
    'app':                        { main: 'main.js',  defaultExtension: 'js' },
    'rxjs':                       { defaultExtension: 'js' },
    'angular2-in-memory-web-api': { main: 'index.js', defaultExtension: 'js' },
  };
  var ngPackageNames = [
    'common',
    'compiler',
    'core',
    'forms',
    'http',
    'platform-browser',
    'platform-browser-dynamic',
    'router',
    'router-deprecated',
    'upgrade',
  ];
  // ficheros individuales (~300 requests):
  function packIndex(pkgName) {
    packages['@angular/'+pkgName] = { main: 'index.js', defaultExtension: 'js' };
  }
  // empaquetados (~40 requests):
  function packUmd(pkgName) {
    packages['@angular/'+pkgName] = { main: '/bundles/' + pkgName + '.umd.js', defaultExtension: 'js' };
  }
  // la mayoria de entornos deberian usar UMD; algunos (Karma) necesitan los ficheros individuales
  var setPackageConfig = System.packageWithIndex ? packIndex : packUmd;
  // Anadir para los paquetes de Angular
  ngPackageNames.forEach(setPackageConfig);
  var config = {
    map: map,
    packages: packages
  };
  System.config(config);
})(this);

¿Por qué necesitamos este archivo de configuración?
¿Por qué necesitamos SystemJS (o WebPack u otras)?
Finalmente, en tu opinión, ¿qué es mejor?

Thierry Templier contesta, (97+ votos)

Si vas a la página de GitHub de SystemJS, verás la descripción de la herramienta:

Universal dynamic module loader - carga ES6 modules, AMD, CommonJS y global scripts en el navegador y NodeJS.

Como usas módulos en TypeScript o ES6,  necesitas el cargador de módulos. En el caso de SystemJS,  systemjs.config.js nos permite configurar la forma en que se emparejan los nombres de los módulos con sus archivos correspondientes.

Este archivo de configuración (y SystemJS) es necesario si quieres importar el módulo principal de su aplicación explícitamente:

<script>
  System.import('app').catch(function(err){ console.error(err); });
</script>

Cuando usas TypeScript, y configuras el compilador para el módulo commonjs module, el compilador crea código que ya no esta basado en SystemJS. En este ejemplo, el compilador de TypeScript sería así:

{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs", // <------
    "moduleResolution": "node",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "removeComments": false,
    "noImplicitAny": false
  }
}

Webpack es un empaquetador de módulos flexible. Esto quiere decir que llega más lejos y no solamente se ocupa de módulos, también proporciona una manera de empaquetar tu aplicación (concat files, uglify files, …). También proporciona un servidor de desarrolo con carga recarga para el desarrollo.

SystemJS y Webpack son diferentes pero con SystemJS, te queda más trabajo por hacer (con Gulp o SystemJS builder por ejemplo) para empaquetar tu aplicación de Angular2 para producción.

Source
Top

Angular: Can’t find Promise, Map, Set and Iterator (No se puede encontrar Promise, Map, Set y Iterator)

154+ votos? 90,201+ vistas
Stav Alfi pregunta,

Después de instalar Angular, el compilador de Typescript me da errores de que no encuentra  Promise, Map, Set y Iterator.

Hasta ahora los he ignorado pero ahora necesito que Promise funcione.

import {Component} from 'angular2/core';
@Component({
    selector: 'saludos-cmp',
    template: `<div>{{ asyncSaludos | async}}</div>`
})
export class SaludosCmp {
    asyncSaludos: Promise<string> = new Promise(resolve => {
// despues de 1 segundo, la promise resuelve
        window.setTimeout(() => resolve('hola'), 1000);
    });
}

informacion adicional:
npm -v is 2.14.12
node -v is v4.3.1
typescript v is 1.6

The errors:

................ERROS OF MY CODE.................
    C:\Users\armyTik\Desktop\angular2\greeting_cmp.ts
    Error:(7, 20) TS2304: Cannot find name 'Promise'.
    Error:(7, 42) TS2304: Cannot find name 'Promise'.
    .........................................
    C:\Users\armyTik\Desktop\angular2\node_modules\angular2\platform\browser.d.ts
    Error:(77, 90) TS2304: Cannot find name 'Promise'.
    C:\Users\armyTik\Desktop\angular2\node_modules\angular2\src\core\application_ref.d.ts
    Error:(83, 60) TS2304: Cannot find name 'Promise'.
    Error:(83, 146) TS2304: Cannot find name 'Promise'.
    Error:(96, 51) TS2304: Cannot find name 'Promise'.
    Error:(96, 147) TS2304: Cannot find name 'Promise'.
    Error:(133, 90) TS2304: Cannot find name 'Promise'.
    Error:(171, 81) TS2304: Cannot find name 'Promise'.
    C:\Users\armyTik\Desktop\angular2\node_modules\angular2\src\core\change_detection\parser\locals.d.ts
    Error:(3, 14) TS2304: Cannot find name 'Map'.
    Error:(4, 42) TS2304: Cannot find name 'Map'.
    C:\Users\armyTik\Desktop\angular2\node_modules\angular2\src\core\debug\debug_node.d.ts
    Error:(14, 13) TS2304: Cannot find name 'Map'.
    Error:(24, 17) TS2304: Cannot find name 'Map'.
    Error:(25, 17) TS2304: Cannot find name 'Map'.
    C:\Users\armyTik\Desktop\angular2\node_modules\angular2\src\core\di\provider.d.ts
    Error:(436, 103) TS2304: Cannot find name 'Map'.
    Error:(436, 135) TS2304: Cannot find name 'Map'.
    C:\Users\armyTik\Desktop\angular2\node_modules\angular2\src\core\linker\compiler.d.ts
    Error:(12, 50) TS2304: Cannot find name 'Promise'.
    Error:(16, 41) TS2304: Cannot find name 'Promise'.
    C:\Users\armyTik\Desktop\angular2\node_modules\angular2\src\core\linker\dynamic_component_loader.d.ts
    Error:(108, 136) TS2304: Cannot find name 'Promise'.
    Error:(156, 150) TS2304: Cannot find name 'Promise'.
    Error:(197, 128) TS2304: Cannot find name 'Promise'.
    Error:(203, 127) TS2304: Cannot find name 'Promise'.
    Error:(204, 141) TS2304: Cannot find name 'Promise'.
    Error:(205, 119) TS2304: Cannot find name 'Promise'.
    C:\Users\armyTik\Desktop\angular2\node_modules\angular2\src\core\render\api.d.ts
    Error:(13, 13) TS2304: Cannot find name 'Map'.
    Error:(14, 84) TS2304: Cannot find name 'Map'.
    C:\Users\armyTik\Desktop\angular2\node_modules\angular2\src\facade\async.d.ts
    Error:(27, 33) TS2304: Cannot find name 'Promise'.
    Error:(28, 45) TS2304: Cannot find name 'Promise'.
    C:\Users\armyTik\Desktop\angular2\node_modules\angular2\src\facade\collection.d.ts
    Error:(1, 25) TS2304: Cannot find name 'MapConstructor'.
    Error:(2, 25) TS2304: Cannot find name 'SetConstructor'.
    Error:(4, 27) TS2304: Cannot find name 'Map'.
    Error:(4, 39) TS2304: Cannot find name 'Map'.
    Error:(7, 9) TS2304: Cannot find name 'Map'.
    Error:(8, 30) TS2304: Cannot find name 'Map'.
    Error:(11, 43) TS2304: Cannot find name 'Map'.
    Error:(12, 27) TS2304: Cannot find name 'Map'.
    Error:(14, 23) TS2304: Cannot find name 'Map'.
    Error:(15, 25) TS2304: Cannot find name 'Map'.
    Error:(95, 41) TS2304: Cannot find name 'Set'.
    Error:(96, 22) TS2304: Cannot find name 'Set'.
    Error:(97, 25) TS2304: Cannot find name 'Set'.
    C:\Users\armyTik\Desktop\angular2\node_modules\angular2\src\facade\lang.d.ts
    Error:(13, 17) TS2304: Cannot find name 'Map'.
    Error:(14, 17) TS2304: Cannot find name 'Set'.
    Error:(78, 59) TS2304: Cannot find name 'Map'.
    C:\Users\armyTik\Desktop\angular2\node_modules\angular2\src\facade\promise.d.ts
    Error:(2, 14) TS2304: Cannot find name 'Promise'.
    Error:(7, 32) TS2304: Cannot find name 'Promise'.
    Error:(8, 38) TS2304: Cannot find name 'Promise'.
    Error:(9, 35) TS2304: Cannot find name 'Promise'.
    Error:(9, 93) TS2304: Cannot find name 'Promise'.
    Error:(10, 34) TS2304: Cannot find name 'Promise'.
    Error:(11, 32) TS2304: Cannot find name 'Promise'.
    Error:(11, 149) TS2304: Cannot find name 'Promise'.
    Error:(12, 43) TS2304: Cannot find name 'Promise'.
    C:\Users\armyTik\Desktop\angular2\node_modules\angular2\src\http\headers.d.ts
    Error:(43, 59) TS2304: Cannot find name 'Map'.
    C:\Users\armyTik\Desktop\angular2\node_modules\angular2\src\http\url_search_params.d.ts
    Error:(11, 16) TS2304: Cannot find name 'Map'.
    C:\Users\armyTik\Desktop\angular2\node_modules\angular2\src\platform\browser\browser_adapter.d.ts
    Error:(75, 33) TS2304: Cannot find name 'Map'.
    C:\Users\armyTik\Desktop\angular2\node_modules\angular2\src\platform\dom\dom_adapter.d.ts
    Error:(85, 42) TS2304: Cannot find name 'Map'.
    C:\Users\armyTik\Desktop\angular2\node_modules\rxjs\CoreOperators.d.ts
    Error:(35, 67) TS2304: Cannot find name 'Promise'.
    Error:(50, 66) TS2304: Cannot find name 'Promise'.
    Error:(89, 67) TS2304: Cannot find name 'Promise'.
    Error:(94, 38) TS2304: Cannot find name 'Promise'.
    Error:(94, 50) TS2304: Cannot find name 'Promise'.
    C:\Users\armyTik\Desktop\angular2\node_modules\rxjs\Observable.d.ts
    Error:(46, 62) TS2304: Cannot find name 'Promise'.
    Error:(47, 42) TS2304: Cannot find name 'Iterator'.
    Error:(103, 74) TS2304: Cannot find name 'Promise'.
    Error:(103, 84) TS2304: Cannot find name 'Promise'.
    Error:(143, 66) TS2304: Cannot find name 'Promise'.
    Error:(158, 65) TS2304: Cannot find name 'Promise'.
    Error:(201, 66) TS2304: Cannot find name 'Promise'.
    Error:(206, 38) TS2304: Cannot find name 'Promise'.
    Error:(206, 50) TS2304: Cannot find name 'Promise'.
    C:\Users\armyTik\Desktop\angular2\node_modules\rxjs\observable\ForkJoinObservable.d.ts
    Error:(6, 50) TS2304: Cannot find name 'Promise'.
    Error:(7, 58) TS2304: Cannot find name 'Promise'.
    C:\Users\armyTik\Desktop\angular2\node_modules\rxjs\observable\FromObservable.d.ts
    Error:(7, 38) TS2304: Cannot find name 'Promise'.
    Error:(7, 51) TS2304: Cannot find name 'Iterator'.
    C:\Users\armyTik\Desktop\angular2\node_modules\rxjs\observable\PromiseObservable.d.ts
    Error:(9, 31) TS2304: Cannot find name 'Promise'.
    Error:(10, 26) TS2304: Cannot find name 'Promise'.
Kris Hollenbeck contesta, (162+ votos)

Angular RC4 — Angular ^2.0.0 con Typescript 2.0.0

Actualizado 9/19/2016

Para hacer que esto funcione con typescript 2.0.0, he hecho esto.

npm install --save-dev @types/core-js

tsconfig.json

"compilerOptions": {
    "declaration": false,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "mapRoot": "./",
    "module": "es6",
    "moduleResolution": "node",
    "noEmitOnError": true,
    "noImplicitAny": false,
    "outDir": "../dist/out-tsc",
    "sourceMap": true,
    "target": "es5",
    "typeRoots": [
      "../node_modules/@types"
    ],
    "types": [
      "core-js"
    ]
  }

Más sobre @types con typescript 2.0.0.

  1. https://www.npmjs.com/~types

Ejemplo de Install:

npm install --save-dev @types/core-js

Errores de identificador duplicados

Esto seguramente es porque los ecmascript 6 typings ya están siendo importados desde algún otro sitio, posiblemente un versión vieja de es6-shim.

Verifica typings.d.ts y asegúrate de que no hay referencias a es6. Quita cualquier referencia a  es6 de tu directorio de typings si tienes uno.

Por ejemplo:

Esto tendrá un conflicto con types:['core-js'] en typings.json.

{
  "globalDependencies": {
    "core-js": "registry:dt/core-js#0.0.0+20160602141332" 
    // es6-shim tambien tendra conflicto
  }
}

core-js en el arreglo de types en tsconfig.json debería ser el único sitio de donde se importa.

Angular CLI 1.0.0-beta.30

Si usas Angular-CLI, quita el arreglo lib en typings.json. Esto parece que tiene un conflicto con declarar core-js en types.

"compilerOptions" : {
  ...
  // eleminado "lib": ["es6", dom"],
  ...
},
"types" : ["core-js"]

Usuarios de Webstorm/Intellij con Angular CLI

Asegúrate de que el compilador TypeScript incorporado esté deshabilitado. Esto entrará en conflicto con la CLI. Para compilar tu typescript con el CLI puedes configurar como ng serve .

YG2jiM4rYeIBDbXVSaDe3VOIdHlSAH1Z7hmN

Tsconfig compilerOptions lib vs types

Si prefieres no instalar definiciones de core js type hay librerias de es6 que vienen incluidas con typescript. Se usan via la propiedad lib: [] en tsconfig.

Nota: Si --lib no se especifica se inyecta una librería por defecto. Esta libraría inyectada es: ? For --target ES5: DOM,ES5,ScriptHost ? For --target ES6: DOM,ES6,DOM.Iterable,ScriptHost

tl;dr

Brevemente:  "lib": [ "es6", "dom" ] o "types": ["core-js"] se pueden usar para resolver can't find Promise,Map, Set and Iterator. Sin embargo, usar ambos causará errores de identificador duplicado.

Source
Top

¿Cómo se detecta cuando cambia un valor de @Input() en Angular?

154+ votos? 89,893+ vistas
Jon Catmull pregunta,

Tengo un componente padre (CategoriaComponent), un componente hijo (videoListComponent) y un ApiService.

Casi todo funciona i.e. todos los componentes pueden acceder a la API de JSON y obtener los datos relevantes para sus observables.

Ahora mismo videoListComponent obtiene todos los videos, me gustaría filtrar los videos basados en su categoría, y lo consigo pasando el ID categoriaId al hijo con  @Input().

CategoriaComponent.html

<video-list *ngIf="categoria" [categoriaId]="categoria.id"></video-list>

Esto funciona y cuando la categoría del padre CategoriaComponent cambia, el  valor de categoriaId se pasa con @Input() pero necesito detectar esto en VideoListComponent y volver a pedir (re-request) el arreglo con los videos via APIService (con el nuevo categoriaId).

En AngularJS habría usado $watch en la variable. ¿Cuál es la mejor manera de manejar esto?

Alan C. S. contesta, (181+ votos)

En realidad, hay dos formas de detectar y actuar cuando un input cambia en el componente hijo en angular2+ :

  1. Puedes usar ngOnChanges() como se menciona en respuestas anteriores:
    @Input() categoriaId: string; ngOnChanges(cambios: SimpleChanges) { this.hazAlgo(cambios.categoriaId.currentValue); // también puedes usar categoriaId.previousValue y // categoriaId.firstChange para comparar los valores nuevos y viejos }
  2. Ejemplo: Mira en plunker
  3. Además, puedes usar @Input así:
    private _categoriaId: string; @Input() set categoriaId(value: string) { this._categoriaId = value; this.hazAlgo(this._categoriaId); } obtenerCategoriaId(): string { return this._categoriaId; }
  4. Ejemplo: Mira en plunker.

¿QUÉ ENFOQUE SE DEBE UTILIZAR?

Si tu componente tiene varios inputs, si usas ngOnChanges(), te llegarán todos los cambios de todos los inputs a la vez en ngOnChanges(). Con este enfoque, también puedes comparar los valores actual y anterior del input que ha cambiado y actuar en consecuencia.

Sin embargo, si quieres hacer algo cuando ha cambiado un input en particular   (y los otros inputs no te importan), puede ser más sencillo usar un @Input. Sin embargo, este enfoque no te permite  comparar valores actuales y anteriores del input que ha cambiado (lo cual es fácil con ngOnChanges).

EDITADO 2017–07–25: LA DETECCIÓN DE CAMBIO DE ANGULAR PUEDE NO DISPARARSE EN ALGUNAS CIRCUNSTANCIAS

Normalmente, la detección de cambio con @Input y ngOnChanges se dispara cuando el componente padre cambia los datos y los pasa al hijo, siempre que los datos sean de un tipo primitivo de JS (string, number, boolean). Sin embargo, en los siguientes escenarios, no se disparará y tienes que hacer trabajo extra para que funcione.

  1. Si estás usando un objeto anidado o un arreglo (en lugar de un tipo primitivo de JS) para pasar los datos del padre al hijo, la detección de cambio (usando @Input o  ngOnchanges) puede que no se dispare, como se menciona en la respuesta de muetzerich. Para soluciones mira aquí.
  2. Si estás mutando datos fuera del contexto de Angular (i.e., externamente), Angular no sabe que ha habido cambios. Tendrías que usar ChangeDetectorRef o NgZone en tu componente para hacer que Angular sepa que ha habido cambios y se dispare la detección de cambios. Mira aquí.

Source
Top

¿Cómo se pasan argumentos url (query string) a una solicitud (request) de HTTP en Angular?

154+ votos? 157,619+ vistas
Miguel Lattuada pregunta,

Hola,estoy creando una solicitud de HTTP en Angular, pero no sé como anadirle argumentos de URL (cadena de consulta (query)).

this.http.get(StaticSettings.BASE_URL).subscribe(
  (response) => this.onObtenTiempoResultados(response.json()),
  (error) => this.onObtenTiempoError(error.json()),
  () => this.onObtenTiempoCompleto()
);

Mi StaticSettings.BASE_URL es como una url sin parametros: http://enalgunsitio.com/ pero quiero que sea http://enalgunsitio.com/?var1=val1&var2=val2

Donde var1, y var2 son parte del objeto de la solicitud de HTTP? Quiero añadirlos como en un objeto.

{
  query: {
    var1: val1,
    var2: val2
  }
}

y que el módulo de Http haga el trabajo de analizar y descomponer para pasarlo a la cadena de consulta (query) de la URL.

toskv contesta, (216+ votos)

El método HttpClient permite configurar params en sus opciones.

Puedes configurarlo importando HttpClientModule del paquete @angular/common/http.

import {HttpClientModule} from '@angular/common/http';

@NgModule({
  imports: [ BrowserModule, HttpClientModule ],
  declarations: [ App ],
  bootstrap: [ App ]
})
export class AppModule {}

Luego puedes inyectar HttpClient y usarlo en la solicitud.

import {HttpClient} from '@angular/common/http'
import {HttpClient} from '@angular/common/http'

@Component({
  selector: 'mi-app',
  template: `
    <div>
      <h2>Hola {{nombre}}</h2>
    </div>
  `,
})
export class App {
  nombre:string;
  constructor(private httpClient: HttpClient) {
    this.httpClient.get('/url', {
      params: {
        appid: 'id1234',
        cnt: '5'
      },
      observe: 'response'
    })
    .toPromise()
    .then(response => {
      console.log(response);
    })
    .catch(console.log);
  }
}

Tienes un ejemplo aquí.

Para versiones de Angular anteriores a la versión 4 puedes hacer lo mismo con el servicio Http.

El método Http.get toma un objeto que implementa RequestOptionsArgs como un segundo parametro.

El campo search de ese objeto se puede usar para poner una cadena o un objeto URLSearchParams.

Ejemplo:

// Parameters obj-
 let params: URLSearchParams = new URLSearchParams();
 params.set('appid', StaticSettings.API_KEY);
 params.set('cnt', days.toString());
 
 //Http request-
 return this.http.get(StaticSettings.BASE_URL, {
   search: params
 }).subscribe(
   (response) => this.onObtenTiempoResultado(response.json()), 
   (error) => this.onObtenerTIempoError(error.json()), 
   () => this.onObtenerTiempoCompleto()
 );

Source
Top

¿Cómo se despliegan las aplicaciones de Angular?

153+ votos? 89,991+ vistas
Joseph Assem Sobhy pregunta,

¿Cómo se despliegan las aplicaciones de Angular para producción?

Todas las guías que he visto hasta ahora  cuentan con un servidor lite-server para servir y browserSync para reflejar los cambios — pero cuando acabas con el desarrollo ,¿Cómo se publica la aplicación?

Importo todos los ficheros .js compilados en index.html o los "minify" con gulp? ¿funcionará? ¿Necesito SystemJS en la versión de producción?

Amid contesta, (74+ votos)

Estás haciendo dos preguntas a la vez. La primera es como alojar tu aplicación. Y como dice @toskv es una pregunta demasiado amplia como para poderla contestar y depende de muchas cosas. La segunda es más especifica — cómo preparas la versión para el despliegue . Tienes varias opciones:

  1. Despliegala tal cual está. No minificación, concatenación, cambios de nombres etc. Transcompila todo tu proyecto, copia todos los js/css/… resultantes + dependencias al servidor que alojará tu aplicación y ya lo tienes.
  2. Despliega usando herramientas especificas. Como webpack o systemjs builder. Incluyen todas las posibilidades que faltan en #1. Puedes empaquetar todo tu código en un par de ficheros js/css/… a los que haces referencia en tu HTML. Systemjs buider incluso te permite no tener que incluir systemjs como parte del paquete de despliegue.

Sí, lo más probable es que necesites implementar systemjs y muchas otras libraries externas como parte de tu paquete. Y sí que podrás ponerlas en un par de ficheros js a los que hagas referencia en tu HTML. No tienes que referenciar todos tus ficheros js compilados desde la página — systemjs como cargador de módulos se encarga de eso.

Sé que suena lioso— para ayudarte a comenzar con #2 aquí van dos ejemplos sencillos:

SystemJS builder: angular2 seed

WebPack: angular2 webpack starter

Mira como lo hacen — y, con suerte, esto te ayudará a encontrar la forma de agrupar las aplicaciones que crees.

Source
Top

ngFor con index como un atributo con un valor

149+ votos ? 195,294+ vistas
Vivendi pregunta,

Tengo un bucle ngFor sencillo que realiza un seguimiento  index actual. Quiero guardar el valor de ese index en un atributo para poder imprimirlo. Pero no sé como se hace.

Tengo esto:

<ul *ngFor="#elemento of elementos; #i = index" data-index="#i">
    <li>{{elemento}}</li>
</ul>

Quiero guardar el valor #i en el atributo data-index. He probado varias formas pero ninguna me funciona.

Tengo una demo aquí: http://plnkr.co/edit/EXpOKAEIFlI9QwuRcZqp?p=preview

¿Cómo puedo almacenar el valor de index en el atributo data-index ?

Thierry Templier contesta, (284+ votos)

Yo usaría esta sintaxis para establecer el valor del índice en un atributo del elemento HTML:

<ul>
    <li *ngFor="#elemento of elementos; #i = index" [attr.data-index]="i">
        {{elemento}}
    </li>
</ul>

Aquí está el ejemplo con los cambios: http://plnkr.co/edit/LiCeyKGUapS5JKkRWnUJ?p=preview.

Actualizado para los lanzamientos de angular 2 Debes usar let en lugar de  #.

<ul>
    <li *ngFor="let elemento of elementos; let i = index" [attr.data-index]="i">
        {{item}}
    </li>
</ul>

Source
Top

Define constantes globales en Angular 2

149+ votos? 128,101+ vistas
AndreFeijo pregunta,

En Angular 1.x puedes definir constantes así:

angular.module('mainApp.config', [])
.constant('API_ENDPOINT', 'http://127.0.0.1:6666/api/')

¿Cuál sería el equivalente en Angular2 (con Typescript)? No quiero repetir la url base de la API una y otra vez en mis servicios.

AndreFeijo contesta, (159+ votos)

Estos cambios a mi me funcionan en la versión final de Angular 2:

export class AppSettings {
   public static API_ENDPOINT='http://127.0.0.1:6666/api/';
}

Y en el servicio:

import {Http} from 'angular2/http';
import {Message} from '../models/message';
import {Injectable} from 'angular2/core';
import {Observable} from 'rxjs/Observable';
import {AppSettings} from '../appSettings';
import 'rxjs/add/operator/map';

@Injectable()
export class MensajeServicio {

    constructor(private http: Http) { }
    
    obtenerMensajes(): Observable<Message[]> {
        return this.http.get(AppSettings.API_ENDPOINT+'/messages')
            .map(response => response.json())
            .map((messages: Object[]) => {
                return messages.map(message => this.parseData(message));
            });
    }
    
    private parseData(data): Message {
        return new Message(data);
    }
}

Source
Top

Angular — Usar pipes en servicios y componentes

148+ votos? 75,716+ vistas
POSIX-compliant pregunta,

En AngularJS, puedo usar filtros (pipes) dentro de los servicios y controllers usando algo como esto:

$filter('date')(miFecha, 'yyyy-MM-dd');

¿se puede hacer lo mismo en Angular?

cexbrayat contesta, (271+ votos)

Como siempre, en Angular, puedes confiar en la inyección de dependencia:

import { DatePipe } from '@angular/common';
class MiServicio {

  constructor(private fechaPipe: DatePipe) {}
  
  transformaFecha(fecha) {
    this.fechaPipe.transform(miFecha, 'yyyy-MM-dd');
  }
}

Añade DatePipe a tu lista de proveedores en tu módulo; Si se te olvida te da un error  no provider for DatePipe:

providers: [DatePipe,...]

Ten en cuenta que  DatePipe dependía de la Intl API hasta la versión 5, que no es compatible con todos los navegadores (comprueba la compatibilidad).

Si estás usando una versión de Angular más antigua, debes añadir  Intl polyfill a tu proyecto para evitar problemas.

Source
Top

144+ votos? 83,326+ vistas
Lester Burnham pregunta,

Obviamente la versión beta de Angular2 es muy nueva, así que no hay mucha información disponible, pero estoy intentando hacer algo que yo creo es básico en enrutamiento (routing).

Hackeando con el código de inicio rápido y otros fragmentos de la página de https://angular.io he hecho esta estructura:

angular-testapp/
    app/
        app.component.ts
        boot.ts
        routing-test.component.ts
    index.html

Con los ficheros así:

index.html

<html>

  <head>
    <base href="/">
    <title>Angular 2 QuickStart</title>
    <link href="../css/bootstrap.css" rel="stylesheet">
    
    <!-- 1. cargar librerias - libraries -->
    <script src="node_modules/angular2/bundles/angular2-polyfills.js"></script>
    <script src="node_modules/systemjs/dist/system.src.js"></script>
    <script src="node_modules/rxjs/bundles/Rx.js"></script>
    <script src="node_modules/angular2/bundles/angular2.dev.js"></script>
    <script src="node_modules/angular2/bundles/router.dev.js"></script>
    
    <!-- 2. Configurar SystemJS -->
    <script>
      System.config({
        packages: {        
          app: {
            format: 'register',
            defaultExtension: 'js'
          }
        }
      });
      System.import('app/boot')
            .then(null, console.error.bind(console));
    </script>
    
  </head>
  
  <!-- 3. Mostrar la aplicacion -->
  <body>
    <my-app>Cargando...</my-app>
  </body>
  
</html>

boot.ts

import {bootstrap}    from 'angular2/platform/browser'
import {ROUTER_PROVIDERS} from 'angular2/router';

import {AppComponent} from './app.component'

bootstrap(AppComponent, [
    ROUTER_PROVIDERS
]);

app.component.ts

import {Component} from 'angular2/core';
import {RouteConfig, ROUTER_DIRECTIVES, ROUTER_PROVIDERS, LocationStrategy, HashLocationStrategy} from 'angular2/router';

import {RoutingTestComponent} from './routing-test.component';

@Component({
    selector: 'mi-app',
    template: `
        <h1>Componente Router</h1>
        <a [routerLink]="['RoutingTest']">Test de enrutamiento/Routing</a>
        <router-outlet></router-outlet>
        `
})

@RouteConfig([
    {path:'/routing-test', name: 'RoutingTest', component: RoutingTestComponent, useAsDefault: true},
])

export class AppComponent { }

routing-test.component.ts

import {Component} from 'angular2/core';
import {Router} from 'angular2/router';

@Component({
    template: `
        <h2>Test de enrutamiento/routing</h2>
        <p>Algo interesante aquí!</p>
        `
})
export class RoutingTestComponent { }

Pero cuando intento correr la aplicación me da:

EXCEPTION: Template parse errors:
Can't bind to 'routerLink' since it isn't a known native property ("
        <h1>Componente Router</h1>
        <a [ERROR ->][routerLink]="['RoutingTest']">Test de enrutamiento</a>
        <router-outlet></router-outlet>
        "): AppComponent@2:11

He encontrado un problema parecido; router-link directives broken after upgrading to angular2.0.0-beta.0. Pero, el “ejemplo que funciona” en una de las respuestas basadas en código pre-beta —que bien puede funcionar, pero me gustaría saber por qué el código que he creado no funciona.

¡Cualquier sugerencia sería recibida con gratitud!

Günter Zöchbauer contesta, (220+ votos)

>=RC.5

Importa RouterModule

@NgModule({ 
  imports: [RouterModule],
  ...
})

>=RC.2

app.routes.ts

import { provideRouter, RouterConfig } from '@angular/router';

export const routes: RouterConfig = [
  ...
];

export const APP_ROUTER_PROVIDERS = [provideRouter(routes)];

main.ts

import { bootstrap } from '@angular/platform-browser-dynamic';
import { APP_ROUTER_PROVIDERS } from './app.routes';

bootstrap(AppComponent, [APP_ROUTER_PROVIDERS]);

<=RC.1

A tu código le falta

@Component({
    ...
    directives: [ROUTER_DIRECTIVES],
    ...)}

No puedes usar directives como routerLink o router-outlet sin darlas a conocer a tu componente.

Aunque los nombres de las directives se cambiaron para distinguir entre mayúsculas y minúsculas en Angular2, los elementos siguen usando - en el nombre, como <router-outlet> para ser compatibles con las especificaciones de componentes web que requieren un - en el nombre de elementos personalizados.

Registra globalmente

Para que ROUTER_DIRECTIVES este disponible globalmente, añade este provider a bootstrap(...):

provide(PLATFORM_DIRECTIVES, {useValue: [ROUTER_DIRECTIVES], multi: true})

Entonces ya no necesitas añadir ROUTER_DIRECTIVES a cada componente.

Source
Top

Angular: 2 pestañas dinámicas con componentes seleccionados por el usuario por click.

143+ votos? 80,735+ vistas
Cuel pregunta,

Estoy intentando configurar un sistema de pestañas que permita a componentes registrarse a sí mismos (con un título). La primera pertaña es como una bandeja de entrada, hay muchos elementos de acciones/enlaces, y cada uno de estos clicks debe instanciar un componente nuevo, en el click. Las acciones / enlaces vienen de JSON.

El componente instanciado se registrará a si mismo como una nueva pestaña.

No sé si esta es la mejor manera de hacer esto. Por ahora las guías que he visto son para pestañas estáticas, lo cual no ayuda.

Por ahora solamente tengo el servicio para las pestañas que está en main para persistir por toda la app, es más o menos como esto.

export interface ITab { titulo: string; }

@Injectable()
export class PestanaServicio {
    private pestanas = new Set<ITab>();
    
    anadirPestana(titulo: string): ITab {
        let pestana: ITab = { titulo };
        this.pestanas.add(pestana);
        return pestana;
    }
    
    quitarPestana(pestana: ITab) {
        this.pestanas.delete(pestana);
    }
}

Preguntas:

1)¿Cómo puedo tener una lista dinámica en la bandeja de entrada que cree nuevas pestañas (diferentes)? Me imagino que con DynamicComponentBuilder?

2) ¿Cómo pueden los componentes creados desde la bandeja de entrada (al hacer clic) registrarse como pestañas y también mostrarse? Supongo que con ng-content pero no puedo encontrar mucha información al respecto.

Editado: Para aclarar

Piensa en la bandeja de entrada como una bandeja de entrada de correo, los elementos se sacan de JSON y muestran varios elementos. Una vez que se hace clic en uno de los elementos, se crea una nueva pestaña con ‘type’. El tipo (type) es un componente.

Editado2: Image

http://i.imgur.com/yzfMOXJ.png

Günter Zöchbauer contesta, (190+ votos)

actualizado

ejemplo: Angular 5 StackBlitz

actualizado

ngComponentOutlet se añadio a 4.0.0-beta.3

actualizado

Hay un NgComponentOutlet que se está creando que hace algo similar https://github.com/angular/angular/pull/11235

RC.7

Ejemplo Plunker RC.7

// componente de ayuda para anadir nuevos componentes
@Component({
  selector: 'dcl-wrapper',
  template: `<div #target></div>`
})
export class DclWrapper {
  @ViewChild('target', {read: ViewContainerRef}) target: ViewContainerRef;
  @Input() tipo: Type<Component>;
  cmpRef: ComponentRef<Component>;
  private estaLaVistaInicializada:boolean = false;
  
  constructor(private componentFactoryResolver: ComponentFactoryResolver, private compiler: Compiler) {}
  
  actualizarComponente() {
    if(!this.estaLaVistaInicializada) {
      return;
    }
    if(this.cmpRef) {
      // cuando el `tipo` del input cambia destruimos uno
      //creado previamente antes de crear el nuevo     
      this.cmpRef.destroy();
    }
    
    let factory = this.componentFactoryResolver.resolveComponentFactory(this.tipo);
    this.cmpRef = this.target.createComponent(factory)
    // para acceder a la instancia creada
    // this.compRef.instance.unaPropiedad = 'unValor';
    // this.compRef.instance.unOutput.subscribe(val => hazAlgo());
  }
  
  ngOnChanges() {
    this.actualizarComponente();
  }
  
  ngAfterViewInit() {
    this.estaLaVistaInicializada = true;
    this.actualizarComponente();  
  }
  
  ngOnDestroy() {
    if(this.cmpRef) {
      this.cmpRef.destroy();
    }    
  }
}

ejemplo de uso

// Usq dcl-wrapper component
@Component({
  selector: 'mis-pestanas',
  template: `
  <h2>pestanas</h2>
  <div *ngFor="let pestana of pestanas">
    <dcl-wrapper [type]="tab"></dcl-wrapper>
  </div>
`
})
export class Pestanas {
  @Input() pestanas;
}

@Component({
  selector: 'mi-app',
  template: `
  <h2>Hola {{nombre}}</h2>
  <mis-pestanas [pestanas]="tipos"></mis-pestanas>
`
})
export class App {
  //la lista usada para crear las pestanas
  tipos = [C3, C1, C2, C3, C3, C1, C1];
}

@NgModule({
  imports: [ BrowserModule ],
  declarations: [ App, DclWrapper, Tabs, C1, C2, C3],
  entryComponents: [C1, C2, C3],
  bootstrap: [ App ]
})
export class AppModule {}

versiones anteriores

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Esto cambio en Angular2 RC.5

Actualizaré el ejemplo de abajo pero es mi último día antes de las vacaciones.

Este ejemplo de Plunker demuestra como crear componentes de forma dinámica en RC.5

Actualizado— usa ViewContainerRef.createComponent()

Como DynamicComponentLoader es obsoleto, El enfoque se debe actualizar nuevamente.

@Component({
  selector: 'dcl-wrapper',
  template: `<div #target></div>`
})
export class DclWrapper {
  @ViewChild('target', {read: ViewContainerRef}) target;
  @Input() tipo;
  cmpRef:ComponentRef;
  private estaVistaInicializada:boolean = false;
  
  constructor(private resolver: ComponentResolver) {}
  
  actualizaComponente() {
    if(!this.estaVistaInicializada) {
      return;
    }
    if(this.cmpRef) {
      this.cmpRef.destroy();
    }
   this.resolver.resolveComponent(this.tipo).then((factory:ComponentFactory<any>) => {
      this.cmpRef = this.target.createComponent(factory)
      // para acceder a la instancia creada
      // this.compRef.instance.unaPropiedad = 'unValor';
      // this.compRef.instance.unOutput.subscribe(val => hazAlgo());
    });
  }
  
  ngOnChanges() {
    this.actualizaComponente();
  }
  
  ngAfterViewInit() {
    this.estaVistaInicializada = true;
    this.actualizaComponente();  
  }
  ngOnDestroy() {
    if(this.cmpRef) {
      this.cmpRef.destroy();
    }    
  }
}

Plunker ejemplo RC.4
Plunker ejemplo beta.17

Actualizado— usa loadNextToLocation

export class DclWrapper {
  @ViewChild('target', {read: ViewContainerRef}) target;
  @Input() tipo;
  cmpRef:ComponentRef;
  private estaVistaInicializada:boolean = false;
  
  constructor(private dcl:DynamicComponentLoader) {}
  
  actualizaComponente() {
    // ejecuta cada vez que `tipo` cambia pero no antes de la llamada a  `//ngAfterViewInit()` se realiza 
    // para inicializar un `target` 
    if(!this.estaVistaInicializada) {
      return;
    }
    if(this.cmpRef) {
      this.cmpRef.destroy();
    }
    this.dcl.loadNextToLocation(this.tipo, this.target).then((cmpRef) => {
      this.cmpRef = cmpRef;
    });
  }
  
  ngOnChanges() {
    this.actualizaComponente();
  }
  
  ngAfterViewInit() {
    this.estaVistaInicializada = true;
    this.actualizaComponente();  
  }
  
  ngOnDestroy() {
    if(this.cmpRef) {
      this.cmpRef.destroy();
    }    
  }
}

Plunker ejemplo beta.17

original

No entiendo muy bien lo que necesitas pero creo que puede ser esto.

El componente Pestanas toma un arreglo de tipos (types) y crea pestañas (tabs) para cada elemento del arreglo.

@Component({
  selector: 'dcl-wrapper',
  template: `<div #target></div>`
})
export class DclWrapper {
  constructor(private elRef:ElementRef, private dcl:DynamicComponentLoader) {}
  @Input() tipo;
  
  ngOnChanges() {
    if(this.cmpRef) {
      this.cmpRef.dispose();
    }
    this.dcl.loadIntoLocation(this.tipo, this.elRef, 'target').then((cmpRef) => {
      this.cmpRef = cmpRef;
    });
  }
}

@Component({
  selector: 'c1',
  template: `<h2>c1</h2>`
  
})
export class C1 {
}

@Component({
  selector: 'c2',
  template: `<h2>c2</h2>`
})
export class C2 {
}
@Component({
  selector: 'c3',
  template: `<h2>c3</h2>`
  
})
export class C3 {
}

@Component({
  selector: 'mis-pestanas',
  directives: [DclWrapper],
  template: `
  <h2>Pestanas</h2>
  <div *ngFor="let pestana of pestanas">
    <dcl-wrapper [tipo]="pestana"></dcl-wrapper>
  </div>
`
})
export class Pestanas {
  @Input() pestanas;
}

@Component({
  selector: 'mi-app',
  directives: [Pestanas]
  template: `
  <h2>Hola {{nombre}}</h2>
  <mis-pestanas [pestanas]="tipos"></mis-pestanas>
`
})
export class App {
  types = [C3, C1, C2, C3, C3, C1, C1];
}

Plunker ejemplo beta.15 (no está basado en tu Plunker)

También hay una forma de pasar datos al componente creado dinámicamente como (unosDatos pasados como tipo)

this.dcl.loadIntoLocation(this.tipo, this.elRef, 'target').then((cmpRef) => {
  cmpRef.instance.unaPropiedad = unosDatos;
  this.cmpRef = cmpRef;
});

También hay algo de soporte para usar la inyección de dependencia con servicios compartidos.

Source
Top

Delegación: EventEmitter o Observable en Angular

141+ votos? 78,505+ vistas
the_critic pregunta,

Estoy tratando de implementar algo así como un patrón de delegación en Angular. Cuando el usuario hace click en nav-item, me gustaría llamar a una función que luego emita un evento que a su vez debe ser ser tratado por algún otro componente que está escuchando el evento.

El escenario: Tengo un componente Navigation:

import {Component, Output, EventEmitter} from 'angular2/core';

@Component({
    // otras propiedades que no incluyo
    events : ['navchange'], 
    template:`
      <div class="nav-item" (click)="elementoNavSeleccionado(1)"></div>
    `
})

export class Navigation {

    @Output() navchange: EventEmitter<number> = new EventEmitter();
    
    elementoNavSeleccionado(elem: number) {
        console.log('elemento nav seleccionado ' + elem);
        this.navchange.emit(elem)
    }
    
}

El componente que observa:

export class ObservadorComponent {

  // como observo ? 
  // <----------evento observe/register ?-------->
  
  public elementoNavSeleccionado(elem: number) {
    console.log('index del elemento cambiado!');
  }
  
}

La pregunta es, ¿Cómo hago que el componente observe el evento en cuestión?

Mark Rajcok contesta, (306+ votos)

Actualizado 2016–06–27: En lugar de usar Observables, usa uno de esto dos:

  • un BehaviorSubject, recomendado por @Abdulrahman en un comentario, o
  • un ReplaySubject, recomendado por @Jason Goemaat en un comentario

Un Subject es un Observable (así que nos podemos suscribir( subscribe() ) a él) y un observador (Observer) (así que podemos usar  next() para emitir un valor nuevo). Explotamos esta característica. Un Subject permite que los valores notifiquen a muchos observadores (Observers). No explotamos esta propiedad (solamente tenemos un Observer).

BehaviorSubject es una variante de Subject. Tiene noción del "valor actual". Explotamos esto: cuando creamos un ObservingComponent, obtiene el valor del elemento de navegación actual de BehaviorSubject automáticamente.

El código más abajo y en plunker usan BehaviorSubject.

ReplaySubject es otra variante de Subject. Si quieres esperar a que un valor sea producido, usa ReplaySubject(1). Mientras que BehaviorSubject requiere un valor inicial (que se proporcionará de inmediato), ReplaySubject no lo require. ReplaySubject siempre proporcionará el valor más reciente, pero como no require un valor inicial, el servicio puede hacer operaciones asíncronas antes de devolver su primer valor. Igualmente se disparará inmediatamente en llamadas posteriores con el valor más reciente. Si solamente quieres un valor, usa first() en la suscripción. Si usas first() no necesitas borrar la suscripción (unsubscribe).

import {Injectable}      from '@angular/core'
import {BehaviorSubject} from 'rxjs/BehaviorSubject';

@Injectable()
export class NavService {
  // elemento de navegacion Observable 
  private _navItemSource = new BehaviorSubject<number>(0);
  // elemento de navegacion observable - flujo
  navItem$ = this._navItemSource.asObservable();
  // comando de servicio
  changeNav(number) {
    this._navItemSource.next(number);
  }
}

import {Component}    from '@angular/core';
import {NavService}   from './nav.service';
import {Subscription} from 'rxjs/Subscription';

@Component({
  selector: 'obs-comp',
  template: `obs component, item: {{item}}`
})
export class ObservadorComponent {
  item: number;
  subscription:Subscription;
  constructor(private _navService:NavService) {}
  ngOnInit() {
    this.subscription = this._navService.navItem$
       .subscribe(item => this.item = item)
  }
  ngOnDestroy() {
    // evitar la fuga de memoria cuando se destruye el componente
    this.subscription.unsubscribe();
  }
}

@Component({
  selector: 'mi-nav',
  template:`
    <div class="nav-item" (click)="SeleccionadoNavItem(1)">nav 1 (clickeame)</div>
    <div class="nav-item" (click)="SeleccionadoNavItem(2)">nav 2 (clickeame)</div>`
})
export class Navigation {
  item = 1;
  constructor(private _navService:NavService) {}
  SeleccionadoNavItem(item: number) {
    console.log('elemento de nav seleccionado' + item);
    this._navService.changeNav(item);
  }
}

Plunker

Respuesta Original que usa un Observable: (require más lógica y código que BehaviorSubject, así que no lo recomiendo pero puede ser instructivo)

Esta implementación usa Observable en lugar de EventEmitter. A diferencia de mi implementacuión con EventEmitter, esta implementación también guarda el valor seleccionado actualmente ( navItem ) en el servicio, de modo que cuando se crea un componente de observación, puede recuperar el valor actual a través de una llamada API  navItem(), y es notificado de cambios con la Observable ( navChange$).

import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/share';
import {Observer} from 'rxjs/Observer';

export class NavService {
  private _navItem = 0;
  navChange$: Observable<number>;
  private _observer: Observer;
  constructor() {
    this.navChange$ = new Observable(observer =>
      this._observer = observer).share();
    // share() permite varios suscriptores
  }
  changeNav(number) {
    this._navItem = number;
    this._observer.next(number);
  }
  navItem() {
    return this._navItem;
  }
}

@Component({
  selector: 'obs-comp',
  template: `obs component, item: {{item}}`
})
export class ObservadorgComponent {
  item: number;
  subscription: any;
  constructor(private _navService:NavService) {}
  ngOnInit() {
    this.item = this._navService.navItem();
    this.subscription = this._navService.navChange$.subscribe(
      item => this.elementoNavSeleccionado(item));
  }
  elementoNavSeleccionado(item: number) {
    this.item = item;
  }
  ngOnDestroy() {
    this.subscription.unsubscribe();
  }
}

@Component({
  selector: 'mi-nav',
  template:`
    <div class="nav-item" (click)="elementoNavSeleccionado(1)">nav 1 (click me)</div>
    <div class="nav-item" (click)="elementoNavSeleccionado(2)">nav 2 (click me)</div>
  `,
})
export class Navigation {
  item:number;
  constructor(private _navService:NavService) {}
  elementoNavSeleccionado(item: number) {
    console.log('elemento nav seleccionado ' + item);
    this._navService.changeNav(item);
  }
}

Plunker

Source
Top

¿Cómo se añade bootstrap a un proyecto angular-cli?

140+ votos? 166,741+ vistas
Jerome pregunta,

Queremos usar bootstrap 4 (4.0.0-alpha.2) en nuestra app generada con angular-cli 1.0.0-beta.5 (w/ node v6.1.0).

Después de obtener bootstrap y sus dependencias con npm, nuestro primer intento consistió en agregarlos en angular-cli-build.js:

'bootstrap/dist/**/*.min.+(js|css)',  
  'jquery/dist/jquery.min.+(js|map)',  
  'tether/dist/**/*.min.+(js|css)',

e importarlos en index.html

<script src="vendor/jquery/dist/jquery.min.js"></script>
  <script src="vendor/tether/dist/js/tether.min.js"></script>
  <link rel="stylesheet" type="text/css" href="vendor/bootstrap/dist/css/bootstrap.min.css">
  <script src="vendor/bootstrap/dist/js/bootstrap.min.js"></script>

Esto funcionaba con ng serve pero en cuanto creamos la compilación (build) con -prod  dist/vendor todas las dependencias desaparecierón(sorpresa !).

¿Cómo debemos tratar tal escenario? (i.e. cargando los scripts de bootstrap en un proyecto generado con angular-cli ?

Habiamos pensado esto pero no sabemos bien por donde tirar…

  • ¿usar un CDN ? pero preferimos servir estos archivos para garantizar que estarán disponibles
  • ¿copiar dependencias a dist/vendor despues de nuestro ng build -prod ? ¿Pero eso parece algo que angular-cli debería proporcionar ya que 'se ocupa' de la parte de compilación?
  • ¿añadir jquery, bootstrap y tether en src/system-config.ts y de alguna manera ponerlos en el paquete main.ts ? Pero eso parecía incorrecto considerando que no los vamos a usar explícitamente en el código de nuestra aplicación. (a diferencia de moment.js o algo como lodash, por ejemplo)
pd farhad contesta, (202+ votos)

**ACTUALIZACIÓN  IMPORTANTE: ng2-bootstrap ahora es ngx-bootstrap **

ngx-bootstrap funciona con angular 3 y 4.

Actualizado : 1.0.0-beta.11-webpack o posteriores

Primero compruebla tu versión de angular-cli con el siguiente comando en la terminal: ng -v

Si la versión es posterior a  1.0.0-beta.11-webpack sigue estos pasos:

  1. instala ngx-bootstrap y bootstrap:
    npm install ngx-bootstrap bootstrap --save

Eso hoy por hoy installa bootstrap 3, pero puede instalar bootstrap 4 en el futuro. Ten en cuenta que ngx-bootstrap funciona con las dos versiones.

  1. abre src/app/app.module.ts y añade
    import { AlertModule } from 'ngx-bootstrap'; ... @NgModule({ ... imports: [AlertModule.forRoot(), ... ], ... })
  2. abre angular-cli.json e inserta una nueva entrada en el arreglo styles
    "styles": [ "styles.css", "../node_modules/bootstrap/dist/css/bootstrap.min.css" ],
  3. abre src/app/app.component.html y añade
    <alert type="success">hola</alert>

1.0.0-beta.10 o anteriores:

Si tu versión de angular-cli version es 1.0.0-beta.10 o anterior tienes que usar estos pasos.

Vete al directorio del proyecto y escribe

npm install ngx-bootstrap --save

abre angular-cli-build.js y añade esto

vendorNpmFiles: [
   ..................
   'ngx-bootstrap/**/*.js',
    ....................
  ]

ahora abre src/system-config.ts, escribe

const map:any = {
     ..................
   'ngx-bootstrap': 'vendor/ngx-bootstrap',
    ....................
}

y

const packages: any = {
  'ngx-bootstrap': {
    format: 'cjs',
    defaultExtension: 'js',
    main: 'ngx-bootstrap.js'
  }
};

Source
Top

Acceso a key y value de un objecto que utiliza *ngFor

136+ votos? 139,816+ vistas
Pardeep Jain pregunta,

Tengo confusión sobre los objetos  Key y Value en angular2 usando *ngFor para las iteraciones sobre el objeto. Sé que en angular 1.x hay una sintaxis como esta:

ng-repeat="(key, value) in demo"

pero en angular2 eso no me funciona. He probado lo siguiente pero tampoco funciona.  Por favor decidme lo que estoy haciendo mal.

<ul>
  <li *ngFor='#key of demo'>{{key}}</li>
</ul>

demo = {
    'key1': [{'key11':'value11'}, {'key12':'value12'}],
    'key2': [{'key21':'value21'}, {'key22':'value22'}],
  }

Aquí está mi Plunker : http://plnkr.co/edit/mIj619FncOpfdwrR0KeG?p=preview

Quiero obtener  key1 y key2 dinamicamente con *ngFor. He encontrado una idea usando pipe pero no sé como hacerlo. ¿Hay alguna pipe en Angular 2 que me permita hacerlo?

Thierry Templier contesta, (134+ votos)

Puedes crear una pipe personalizada que devuelva la lista de keys para cada elemento.  Algo como esto:

import { PipeTransform, Pipe } from '@angular/core';

@Pipe({name: 'keys'})
export class KeysPipe implements PipeTransform {
  transform(value, args:string[]) : any {
    let keys = [];
    for (let key in value) {
      keys.push(key);
    }
    return keys;
  }
}

y la usas así:

<tr *ngFor="let c of contenido">           
  <td *ngFor="let key of c | keys">{{key}}: {{c[key]}}</td>
</tr>

Editado

También puedes devolver una entrada que contenga la key la la value:

@Pipe({name: 'keys'})
export class KeysPipe implements PipeTransform {
  transform(value, args:string[]) : any {
    let keys = [];
    for (let key in value) {
      keys.push({key: key, value: value[key]});
    }
    return keys;
  }
}

y para usarla:

<span *ngFor="let c of contenido | keys">           
  Key: {{c.key}}, value: {{c.value}}
</span>

Source
Top

Excepción de Angular: Can’t bind to ‘ngFor’ since it isn’t a known native property (No se puede enlazar a 'ngFor' porque no es una propiedad nativa conocida).

134+ votos? 63,054+ vistas
Mark Rajcok pregunta,

¿Qué estoy haciendo mal?

import {bootstrap, Component} from 'angular2/angular2'

@Component({
  selector: 'conf-charlas',
  template: `<div *ngFor="charla of charlas">
     {{charla.titulo}} de {{charla.orador}}
     <p>{{charla.descripcion}}
   </div>`
})
class ConfCharlas {
  talks = [ {titulo: 't1', orador: 'Brian', descripcion: 'talk 1'},
            {titulo: 't2', orador: 'Julie', descripcion: 'talk 2'}];
}
@Component({
  selector: 'mi-app',
  directives: [ConfCharlas],
  template: '<conf-charlas></conf-charlas>'
})
class App {}
bootstrap(App, [])

El error:

EXCEPTION: Template parse errors:
Can't bind to 'ngFor' since it isn't a known native property
("<div [ERROR ->]*ngFor="charla of charlas">
Mark Rajcok contesta, (325+ votos)

Te falta let delante de  charla:

<div *ngFor="let charla of charlas">

Ten en cuenta que desde beta.17 la sintaxis con  #... para declarar variables locales en una directive estructural como NgFor se considera obsoleta. Usa let  en su lugar.
<div *ngFor="#charla of charlas"> ahora es <div *ngFor="let charla of charlas">

Respuesta original:

Te falta  # delante de  charla:

<div *ngFor="#charla of charlas">

Es muy fácil olvidarse de #. Me gustaría que el mensaje de Angular fuera:
se te ha olvidado # otra vez.

Source
Top

¿Cómo se añade font-awesome a un proyecto Angular 2 + CLI

132+ votos? 71,934+ vistas
Nik pregunta,

Estoy usando Angular 2+ y Angular CLI.

¿Cómo agrego font-awesome a mi proyecto?

AIon contesta, (285+ votos)

Desde el lanzamiento final de  Angular 2.0 , la estructura de un proyecto de Angular2 CLI ha cambiado — no necesitas ningunos ficheros de vendedores -no system.js — solamente webpack. Esto es lo que tienes que hacer:

  1. npm install font-awesome --save
  2. En el fichero angular-cli.json encuentra el arreglo styles[] y añade las referencias a font-awesome:
    “apps”: [ { “root”: “src”, “outDir”: “dist”, …. “styles”: [ “styles.css”, “../node_modules/bootstrap/dist/css/bootstrap.css”, “../node_modules/font-awesome/css/font-awesome.css” // -webpack creara un enlacel automaticamente a css con esto!? ], … } ] ]
  3. Pon algunos iconos de font-awesome en cualquier fichero html que quieras:
    <i class=”fa fa-american-sign-language-interpreting fa-5x” aria-hidden=”true”> </i>
  4. Corre ng build y ng serve otra vez - porque los observadores son solamente para la carpeta src y no se observan los cambios en angular-cli.json.
  5. ¡Disfruta de tus impresionantes íconos!

Source
Top

Diferencia entre HTTP y HTTPClient en angular 4

130+ votos? 47,082+ vistas
Aioub Amini pregunta,

Quiero saber cuál usar para crear un servicio web simulado para probar el programa Angular.

AngularInDepth.com contesta, (208+ votos)

Usa la clase HttpClient de HttpClientModule si estás usando Angular 4.3.x a o posterior:

import { HttpClientModule } from '@angular/common/http';

@NgModule({
 imports: [
   BrowserModule,
   HttpClientModule
 ],
 ...
 
 class MyService() {
    constructor(http: HttpClient) {...}

Es una versión mejorada del módulo http de @angular/http con estas mejoras:

  • Los interceptores permiten que la lógica del middleware se inserte en la canalización (pipeline)
  • Objetos de solicitud/respuesta inmutables
  • Eventos de progreso para la carga de solicitudes y la descarga de respuestas
  • Acceso tipado (typed) y síncrono al cuerpo (body) de la respuesta, incluyendo soporte para tipos de JSON
  • JSON se asume y ya no necesitas analizarlo explícitamente
  • Verificación Post-request & testeado del framework basado en vaciado (flush)

En el futuro, el antiguo http client quedará obsoleto.

También ten en cuenta que el antiguo http era inyectado con la clase  Http en lugar del nuevo HttpClient:

import { HttpModule } from '@angular/http';

@NgModule({
 imports: [
   BrowserModule,
   HttpModule
 ],
 ...
 
 class MiServicio() {
    constructor(http: Http) {...}

Además, el nuevo HttpClient parece necesitar tslib en runtime, así que tienes que instalarlo con npm i tslib y actualizar  system.config.js si estás usandoSystemJS:

map: {
     ...
    'tslib': 'npm:tslib/tslib.js',

Y necesitas agregar otro mapeo (mapping) si usas SystemJS:

'@angular/common/http': 'npm:@angular/common/bundles/common-http.umd.js',

Source
Top

Eso es todo por hoy. Si te ha resultado útil este artículo, ayúdame a compartirlo. ? ? ?

Sígueme en Medium o Twitter para leer más sobre Angular, webpack, typescript, nodejs y javascript! ? ? ?