简体   繁体   中英

Displaying a single object from ngrx store in the angular html template

I need help with displaying an object. The code is as follows:

office.action.ts:

export const getOfficeRequest = createAction('[Office] Get Office Request', props<{key: string}>());
export const getOfficeDone = createAction('[Office] Get Office Request Done', props<{office: Office}>());

office.reducer.ts:

@Effect()
  getOffice$ = this.action$.pipe(
    ofType(getOfficeRequest),
    switchMap((action) => this.OFMService.getOffice(action.key)
    .pipe(
      map((office: Office) =>  getOfficeDone({ office })))
    )
  );

component.module.ts:

import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { faEllipsisV, faPhoneAlt, faUserFriends } from '@fortawesome/free-solid-svg-icons';
import { OfficeComponent } from './office-list/office/office.component';
import { NgModule } from '@angular/core';
import { StoreDevtoolsModule } from '@ngrx/store-devtools';

import { CommonModule } from '@angular/common';

import {EffectsModule} from '@ngrx/effects';
import { officesReducer } from './../shared';

import { ComponentsRoutingModule } from './components-routing.module';
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { library } from '@fortawesome/fontawesome-svg-core';
import { RouterModule } from '@angular/router';
import { OfficeListComponent } from './office-list/office-list.component';
import {OfficeDetailsComponent} from './office-list/office-details/office-details.component';
import {OfficeEffects} from './../shared/store/effects/office.effects';


import {  ReactiveFormsModule } from '@angular/forms';
import { LoadingComponent, ModalModule } from '../shared';
import { StaffComponent } from './staff/staff.component';
import { StoreModule } from '@ngrx/store';



@NgModule({
  declarations: [OfficeComponent, OfficeListComponent, OfficeDetailsComponent, StaffComponent, LoadingComponent],
  imports: [
    CommonModule,
    ComponentsRoutingModule,
    FontAwesomeModule,
    RouterModule,
    ReactiveFormsModule,
    StoreModule.forRoot({ offices: officesReducer }),
    StoreDevtoolsModule.instrument(),
    EffectsModule.forRoot([ OfficeEffects ]),
    NgbModule,
    ModalModule],
})
export class ComponentsModule {
  constructor() {
    library.add(faPhoneAlt, faEllipsisV, faUserFriends);
  }
}

office-details.component.ts:

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { Store, select } from '@ngrx/store';
import { getOfficeRequest } from 'src/app/shared';

import { Office } from 'src/app/shared/models/office.model';
import { OfficemanService } from '../../../shared/services/officeman.service';

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

  office$ = this.store.pipe(select(theState => theState.office));
  // office: Office;
  id: string;
  constructor(
    private officeMan: OfficemanService,
    private route: ActivatedRoute,
    private router: Router,
    private store: Store<{office: Office}>) {
    this.id = route.snapshot.params.id;
  }

  ngOnInit(): void {
    const key = this.id;
    this.store.dispatch(getOfficeRequest({key}));
  }

}

office-details.component.html


<div class="office-details text-center text-white" *ngIf="(office$ | async); let office;">
    <div class="office-details__office-card bg-primary shadow mx-2 mb-3">
        <div class="office-details__header text-white text-left px-4 pt-4 h3" [routerLink]="'/'"><i class="fas fa-arrow-left pr-4"></i>{{office?.officeName }}</div>
        <div class="office-details_contact-details text-left p-4 pt-2">
            <div class="office-details__address">Address: {{office | json}}</div>
            <div class="office-details__email">Email: {{office?.email }}</div>
            <div class="office-details__office-tel">Office Tel: {{office?.officeTel }}</div>
            <div class="office-details__max-capacity">Max Capacity: {{office?.maxOccupants }}</div>
        </div>
    </div>
    <app-staff [office]="office$" ></app-staff>
</div>

<app-loading *ngIf="!office$"></app-loading>

The redux tools show that the object is being retrieved from the store but I can't display it on the html template. I have read many of the other entries on here but they don't work on my case.

在此处输入图像描述

It's not showing any error messages on the console. But when I try console.log the this.office it show that there is an observable and the values are present. I don't know how to diplay them though. YOu help will be much appreciated. I'm using Angular11.

There are a couple of things going on here. Observables have to be subscribed to in order to listen to values produced. In the template, use the AsyncPipe to subscribe to the observable and get its values.

The other part is variable reassigment. You've subscribed to the "office$" observable using the async pipe, and reassigned it to "office", so you can just use the "office" value for the rest.

Anything outside the div with the *ngIf will need to use the async pipe again.

<div class="office-details text-center text-white" *ngIf="(office$ | async); let office;">
    <div class="office-details__office-card bg-primary shadow mx-2 mb-3">
        <div class="office-details__header text-white text-left px-4 pt-4 h3" [routerLink]="'/'"><i class="fas fa-arrow-left pr-4"></i>{{office?.officeName }}</div>
        <div class="office-details_contact-details text-left p-4 pt-2">
            <div class="office-details__address">Address: {{office | json}}</div>
            <div class="office-details__email">Email: {{office?.email }}</div>
            <div class="office-details__office-tel">Office Tel: {{office?.officeTel }}</div>
            <div class="office-details__max-capacity">Max Capacity: {{office?.maxOccupants }}</div>
        </div>
    </div>
    <app-staff [office]="office" ></app-staff> <! -- here -->
</div>

<app-loading *ngIf="!(office$ | async)"></app-loading> <!-- here -->

In the office.reducer.ts:

const office = new Office();

export const officeReducer = createReducer<Office>(office,
    on(getOfficeDone, (_, action) => action.office));

I added a selector which I will use to send the intercepted/copied data to the store.

Then I modified the component.module.ts:

 StoreModule.forRoot({ offices: officesReducer, office: officeReducer }),

This all I had left out in my solution. The Object is now populating the template as planned.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM