No Angular 1.xx você simplesmente solicita o mesmo serviço e acaba com a mesma instância, possibilitando o compartilhamento dos dados no serviço.
Agora no Angular 2 tenho um componente que faz referência ao meu serviço. Posso ler e modificar os dados no serviço, o que é bom. Quando tento injetar o mesmo serviço em outro componente, parece que recebo uma nova instância.
O que estou fazendo errado? É o próprio padrão que está errado (usando um serviço para compartilhar dados) ou preciso marcar o serviço como um singleton (em uma instância do aplicativo) ou algo assim?
Estou no 2.0.0-alpha.27/
btw
Eu injeto um serviço por meio de appInjector
(editar: agora providers
) na @Component
anotação e, em seguida, salvo uma referência no construtor. Ele funciona localmente no componente - apenas não entre os componentes (eles não compartilham a mesma instância de serviço) como eu pensei que fariam.
ATUALIZAÇÃO : a partir do Angular 2.0.0 agora temos @ngModule onde você definiria o serviço sob a providers
propriedade em dito @ngModule
. Isso garantirá que a mesma instância desse serviço seja passada para cada componente, serviço, etc. nesse módulo.
https://angular.io/docs/ts/latest/guide/ngmodule.html#providers
ATUALIZAÇÃO : Muita coisa aconteceu com o desenvolvimento do Angular e do FE em geral. Como @noririco mencionou, você também pode usar um sistema de gerenciamento de estado como o NgRx: https://ngrx.io/
fonte
Respostas:
Um singleton de serviço é uma boa solução. Outra maneira -
data/events bindings
.Aqui está um exemplo de ambos:
class BazService{ n: number = 0; inc(){ this.n++; } } @Component({ selector: 'foo' }) @View({ template: `<button (click)="foobaz.inc()">Foo {{ foobaz.n }}</button>` }) class FooComponent{ constructor(foobaz: BazService){ this.foobaz = foobaz; } } @Component({ selector: 'bar', properties: ['prop'] }) @View({ template: `<button (click)="barbaz.inc()">Bar {{ barbaz.n }}, Foo {{ prop.foobaz.n }}</button>` }) class BarComponent{ constructor(barbaz: BazService){ this.barbaz = barbaz; } } @Component({ selector: 'app', viewInjector: [BazService] }) @View({ template: ` <foo #f></foo> <bar [prop]="f"></bar> `, directives: [FooComponent, BarComponent] }) class AppComponent{} bootstrap(AppComponent);
Assista ao vivo
fonte
viewInjector
.providers: [MyService]
. Removendo os provedores, tornou-se a única instância do aplicativoO comentário de @maufarinelli merece sua própria resposta porque até que eu vi, eu ainda estava batendo minha cabeça contra a parede com esse problema, mesmo com a resposta de @Alexander Ermolov.
O problema é que, quando você adiciona um
providers
ao seucomponent
:@Component({ selector: 'my-selector', providers: [MyService], template: `<div>stuff</div>` })
Isso faz com que uma nova instância de seu serviço seja injetada ... em vez de ser um singleton .
Portanto, remova todas as instâncias do seu
providers: [MyService]
em seu aplicativo, exceto nomodule
, e funcionará!fonte
Você deve usar entradas e saídas de um decorador @Component. Aqui está o exemplo mais básico do uso de ambos;
import { bootstrap } from 'angular2/platform/browser'; import { Component, EventEmitter } from 'angular2/core'; import { NgFor } from 'angular2/common'; @Component({ selector: 'sub-component', inputs: ['items'], outputs: ['onItemSelected'], directives: [NgFor], template: ` <div class="item" *ngFor="#item of items; #i = index"> <span>{{ item }}</span> <button type="button" (click)="select(i)">Select</button> </div> ` }) class SubComponent { onItemSelected: EventEmitter<string>; items: string[]; constructor() { this.onItemSelected = new EventEmitter(); } select(i) { this.onItemSelected.emit(this.items[i]); } } @Component({ selector: 'app', directives: [SubComponent], template: ` <div> <sub-component [items]="items" (onItemSelected)="itemSelected($event)"> </sub-component> </div> ` }) class App { items: string[]; constructor() { this.items = ['item1', 'item2', 'item3']; } itemSelected(item: string): void { console.log('Selected item:', item); } } bootstrap(App);
fonte
ngFor
,No modelo de componente pai:
<hero-child [hero]="hero"> </hero-child>
No componente filho:
fonte
Existem muitos caminhos. Este é um exemplo de propagação entre elementos pais e filhos. Isso é muito eficiente.
Enviei um exemplo que permite ver o uso de ligação de dados de duas maneiras em dois formulários. Se alguém puder fornecer uma amostra plunkr, isso seria muito bom ;-)
Você pode procurar outra maneira usando um provedor de serviços. Você pode dar uma olhada neste vídeo também para referência: ( Compartilhando dados entre componentes em Angular )
mymodel.ts (dados para compartilhar)
// Some data we want to share against multiple components ... export class mymodel { public data1: number; public data2: number; constructor( ) { this.data1 = 8; this.data2 = 45; } }
Lembre-se: deve haver um pai que irá compartilhar "mymodel" com os componentes filhos.
Componente pai
import { Component, OnInit } from '@angular/core'; import { mymodel } from './mymodel'; @Component({ selector: 'app-view', template: '<!-- [model]="model" indicates you share model to the child component --> <app-mychild [model]="model" > </app-mychild>' <!-- I add another form component in my view, you will see two ways databinding is working :-) --> <app-mychild [model]="model" > </app-mychild>', }) export class MainComponent implements OnInit { public model: mymodel; constructor() { this.model = new mymodel(); } ngOnInit() { } }
Componente filho, mychild.component.ts
import { Component, OnInit,Input } from '@angular/core'; import { FormsModule } from '@angular/forms'; // <-- NgModel lives here import { mymodel } from './mymodel'; @Component({ selector: 'app-mychild', template: ' <form #myForm="ngForm"> <label>data1</label> <input type="number" class="form-control" required id="data1 [(ngModel)]="model.data1" name="data1"> <label>val {{model.data1}}</label> label>data2</label> <input id="data2" class="form-control" required [(ngModel)]="model.data2" name="data2" #data2="ngModel"> <div [hidden]="data2.valid || data2.pristine" class="alert alert-danger"> data2 is required </div> <label>val2 {{model.data2}}</label> </form> ', }) export class MychildComponent implements OnInit { @Input() model: mymodel ; // Here keywork @Input() is very important it indicates that model is an input for child component constructor() { } ngOnInit() { } }
Nota: Em alguns casos raros, pode ocorrer um erro quando o código HTML é analisado, porque o modelo não está "pronto" para ser usado na inicialização da página. Nesse caso, prefixe o código HTML com uma condição ngIf:
<div *ngIf="model"> {{model.data1}} </div>
fonte
Depende, se houver um caso simples
a) A -> B -> C A tem dois filhos B e C e se você quiser compartilhar dados entre A e B ou A e C, use (entrada / saída)
Se você deseja compartilhar entre B e C, você também pode usar (entrada / saída), mas sugere-se usar o serviço.
b) Se a árvore for grande e complexa. (se houver tantos níveis de conexões de pais e filhos.) E, neste caso, se você quiser compartilhar dados, eu sugeriria ngrx
Ele implementa a arquitetura de fluxo que cria uma loja do lado do cliente para a qual qualquer componente pode se inscrever e pode atualizar sem criar qualquer condição de corrida.
fonte