2016-04-22 9 views
17

Qualcuno può aiutare a vedere se c'è un errore di sintassi qui nel mio modello? Non dà errore, ma non inserisce dati nel modello.il tubo asincrono angular2 non riempie i dati oggetto nel modello

<div *ngIf="(hero | async)"> 
    <h2>{{hero}}</h2> 
    <h2>{{hero.name}} details!</h2> 
    <div> 
    <label>_id: </label>{{hero._id}}</div> 
    <div> 
    <label>name: </label> 
    <input [(ngModel)]="hero.name" placeholder="name" /> 
    </div> 
    <button (click)="goBack()">Back</button> 
</div> 

codice componente

export class HeroDetailComponent implements OnInit { 
    errorMessage: string; 

    //@Input() 
    hero: Observable<Hero>; 

    constructor(
     private _heroService: HeroService, 
     private _routeParams: RouteParams) { 
    } 

    ngOnInit() { 
     let _id = +this._routeParams.get('_id'); 
     this._heroService.loadHero(_id); 
     this.hero = this._heroService.hero$; 
     this.hero.subscribe(data => 
      console.log(data) 
     ) 
    } 

I console.log (dati) stampa oggetto {_id: 11, il nome: "Mr. Nice"} me che che i dati vengono recuperati in modo corretto.

Si visualizza anche il blocco <div>, che significa * ngIf vede l'oggetto come non vuoto.

<h2>{{hero}}</h2> mostra [oggetto oggetto].

Ma perché il {{hero.name}} non viene visualizzato?

+0

Hai un paio di cose mescolato. 'hero' è una proprietà di input, ma poi gli assegni un valore in ngOnInit() - che è dispari. Il valore assegnato è un Observable, che non ha una proprietà 'name', il che spiega perché' {{hero.name}} 'non funzionerà. Questa risposta dovrebbe aiutarti: http://stackoverflow.com/a/34561532/215945 –

+0

Ho aggiornato il post e rimosso @input. Ma è sempre lo stesso. Il tubo asincrono dovrebbe trasformare l'osservabile in oggetto eroe? – Shawn

risposta

48

Gli oggetti sono un po 'complicati con il tubo asincrono. Con un Observable che contiene un array, possiamo usare NgFor e creare una variabile di template locale (hero qui sotto) che viene assegnata a ciascun elemento dell'array dopo che il tubo asincrono estrae l'array dal Observable. Possiamo quindi utilizzare tale variabile in altre parti del modello:

<div *ngFor="let hero of heroes | async"> 
    {{hero.name}} 
</div> 
<!-- we can't use hero here, outside the NgFor div --> 

Ma con un 'osservabile che contiene un singolo oggetto, io non sono a conoscenza di alcun modo per creare una variabile di modello locale che farà riferimento quell'oggetto. Invece, abbiamo bisogno di fare qualcosa di più complicato:

<div>{{(hero | async)?.name}}</div> 

E avremmo bisogno di ripetere che per ogni proprietà dell'oggetto che vogliamo visualizzare. (La riga precedente presuppone che componente struttura hero è osservabile.)

probabilmente è più facile assegnare all'oggetto (cioè all'interno del osservabile, hero$ sotto) a una proprietà del componente, utilizzando la logica componente:

this._heroService.hero$.subscribe(data => this.hero = data.json()); 

e quindi utilizzare NgIf o Elvis/safe navigation operator per visualizzare i dati nella vista:

<div *ngIf="hero">{{hero.name}}</div> 
<!-- or --> 
<div>{{hero?.name}}</div> 
+0

{{(hero | async) ?. name}} non funzionerà. Ho fatto il secondo modo: iscrivermi per ottenere i dati nella proprietà del componente e farne riferimento nel modello. Grazie per aver dedicato del tempo. Lo apprezzo. – Shawn

+3

{{(hero | async)?.name}}
- questo è semplicemente perfetto. Mi ha salvato un sacco di tempo ... –

+0

Impressionante, la seconda via era più facile e diretta :) –

19

Un'altra possibilità sarebbe quella di utilizzare @Input e leva approccio componente intelligente/muta. Nel tuo componente intelligente puoi passare l'oggetto asincrono al componente stupido, quindi nel componente stupido puoi usarlo come un oggetto normale.

L'idea è che il componente intelligente si occupa di logica e dati e il componente stupido gestisce la presentazione.

intelligente componente:

<dumb-component [myHero]="hero$ | async"></dumb-component> 

Dumb classe del componente:

@Input() myHero: Hero; 

modello componente Dumb:

<div>{{ myHero.name }}</div> 
+2

Questo è l'approccio corretto secondo me – Amit

+0

Mi ha salvato molto tempo ed è una soluzione molto migliore rispetto alla risposta accettata A parer mio. – mdziob

+0

myHero è una stringa giusta? Non dovrebbe essere '

{{ myHero }}
' invece di '
{{ myHero.name }}
'? – guilhebl

1

Sto semplicemente aggiungendo una precisione su come utilizzare la smart/muto approccio component nel caso in cui sia necessario utilizzare la pipe async e una sintassi di parentesi.

Che combinano un trucco trovato here.

< ui-gallery-image([image]="(imagesFB | async) ? (imagesFB | async)[0] : null") ></ui-gallery-image>

ho trascorrere ore da trovare. Spero che questo aiuto. Maggiori informazioni su questo blog post.

14

Questo è ora possibile utilizzare il 'come' la sintassi, disponibile in v4.0.0:

<span *ngIf="user$ | async as user; else loadingUserInfo"> 
{{user.firstName}} {{user.lastName}} 
</span> 
<ng-template #loadingUserInfo> 
    Loading user information... 
</ng-template> 

Maggiori dettagli disponibili nel RFC thread on github.

1

Il modo migliore per gestire un oggetto singolo osservabile all'interno di un modello angolare 2.3.xo Angolare 4.x consiste nell'utilizzare un tubo asincrono con una variabile modello.

Ecco un obiettivo comune per gli sviluppatori angolari. Prendi una serie di elementi da redux e cogli un singolo elemento corrispondente dalla collezione. Quindi renderizza quell'oggetto singolare in un modello.

COMPONENTE

@Component({ 
    selector: 'app-document-view', 
    templateUrl: './document-view.component.html', 
    styleUrls: ['./document-view.component.scss'] 
}) 
export class DocumentViewComponent implements OnInit { 

    @select(['documents', 'items']) readonly documenList$: Observable<DocumentDTO[]>; 
    public documentVO$: Observable<DocumentDTO>; 

    constructor(private _state: NgRedux<IAppState>, 
       private _route: ActivatedRoute, 
       private _documentActions: DocumentActions) { 

    _route.params.subscribe(params => { 
     let modelId: number = parseInt(params['modelId']); //1   
     let documentId: number = parseInt(params['documentId']); //50 
     this._documentActions.getDocument(modelId, documentId); 
    }); 
    } 

    ngOnInit() { 

    //documenList holds all of the documents in our application state 
    //but this view only wants a single element 

    this.documentVO$ = this.documenList$.map(documents => documents.find(doc => doc.documentId === 50)); 
    } 
} 

VISTA

<div class="row" *ngIf="documentVO$ | async as dto"> 
    <div id="about" class="col-12"> 
     <div id="title" class="paper meta"> 
      <p>{{ dto.title }}</p> 
     </div> 
    </div> 
</div> 
Problemi correlati