2016-04-22 3 views
17

Может ли кто-нибудь помочь увидеть, есть ли синтаксическая ошибка здесь, в моем шаблоне? Он не дает ошибок, но не заполняет данные в шаблоне.angular2 async pipe не заполняет данные объекта в шаблон

<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> 

Компонентный код

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) 
     ) 
    } 

В console.log (данные) печатает объект {_id: 11, имя: "Г-н Nice"} , который мне, что данные корректно получены.

Также отображается блок <div>, что означает * ngIf видит объект как не пустой.

<h2>{{hero}}</h2> показывает [объект объекта].

Но почему {{hero.name}} не отображается?

+0

У вас есть несколько вещей, перепутали. 'hero' - это свойство ввода, но тогда вы назначаете ему значение в ngOnInit() - это нечетно. Назначенное значение - Observable, которое не имеет свойства 'name', что объясняет, почему' {{hero.name}} 'не будет работать. Этот ответ должен помочь вам: http://stackoverflow.com/a/34561532/215945 –

+0

Я обновил сообщение и удалил @input. Но все тот же. Асинхронная труба должна превращать наблюдаемый в объект героя? – Shawn

ответ

48

Объекты немного сложны с асинхронной трубой. С Observable, который содержит массив, мы можем использовать NgFor и создать локальную переменную шаблона (hero ниже), которая получает каждый элемент массива после того, как асинхронный канал извлекает массив из Observable. Затем мы можем использовать эту переменную в другом месте в шаблоне:

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

Но наблюдаемом, который содержит один объект, я не знаю ни одного способа, чтобы создать локальную переменную шаблона, который будет ссылаться на этот объект. Вместо этого мы должны сделать что-то более сложное:

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

И мы должны были бы повторить, что для каждого свойства объекта, который мы хотим отобразить. (В строке выше предполагается, что компонент свойство hero является Наблюдаемым.)

Это, вероятно, легче назначить объект (то есть внутри Наблюдаемый, hero$ ниже) к свойству компонента, используя логику компоненты:

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

, а затем использовать NgIf или Elvis/safe navigation operator для отображения данных в виде:

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

{{(hero | async) ?. name}} не будет работать. Я сделал второй способ: подписаться на получение данных в свойстве компонента и ссылаться на него в шаблоне. Спасибо, что нашли время. Я ценю это. – Shawn

+3

{{(hero | async)?.name}}
- это просто отлично. Сэкономил мне много времени ... –

+0

Удивительный, второй путь был проще и прямо :) –

19

Другим вариантом было бы использовать @Input и использовать смарт/подход немой компонент. В вашем интеллектуальном компоненте вы можете передать объект async для немого компонента, а затем в немой компоненте вы можете использовать его как обычный объект.

Идея заключается в том, что ваш интеллектуальный компонент имеет дело с логикой и данными, а также с представлением о немых компонентах.

Смарт компонент:

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

Тупой класс компонента:

@Input() myHero: Hero; 

Тупой шаблона компонента:

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

Это правильный подход, на мой взгляд, – Amit

+0

Сохранял мне много времени и намного лучше, чем принято. ИМХО. – mdziob

+0

myHero - строка справа? Не должно быть «

{{ myHero }}
» вместо «
{{ myHero.name }}
»? – guilhebl

1

Я просто добавляя точность о том, как использовать смарт/немой компонентный подход в случае, если вам нужно использовать асинхронный канал и синтаксис скобки.

Этот комбинированный трюк найден here.

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

Я часами, чтобы найти. Надеюсь, эта помощь. Подробнее об этом blog post.

14

Теперь это возможно с помощью 'как' синтаксис, доступный в V4.0.0:

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

Подробнее доступны в RFC thread on github.

1

Лучший способ обработки Одиночный наблюдаемый объект внутри шаблона Angular 2.3.x или Angular 4.x предназначен для использования async-канала с переменной шаблона.

Вот общая цель для угловых разработчиков. Возьмите массив элементов из redux и вырвите из коллекции один элемент соответствия. Затем визуализируйте этот особый объект в шаблоне.

КОМПОНЕНТ

@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)); 
    } 
} 

VIEW

<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> 
Смежные вопросы