0

I am currently trying to set up a simple form in Angular 8 using Akita. Before going further I'll have to tell you that I am not a developer and I am quite new to the Angular world... Not even mentioning the state management concepts. Please keep that in mind when reading my code :)

Here is a quick description of what I am trying to achieve. A user enters the first characters of a registration number in an input. Below, in an autocomplete, are suggested the registration numbers known in the database. When the user selects one of these values, a service is triggered with the corresponding ID and gets the data for the selected vehicle (an aircraft in this case). And the returned data is displayed below the select box.

So far so good... My autocomplete box works well and the store is filled (apparently) as expected. I see the correct data in the store using Redux devtools.

enter image description here

My problem comes when I try to display the data... I am able to see the whole object in the store on my page with something like {{ store_aircraft$ | json }} which gives me something like:

    {
  "_isScalar": false,
  "source": {
    "_isScalar": false,
    "source": {
      "_isScalar": false,
      "source": {
        "_isScalar": false,
        "source": {
          "_isScalar": false,
          "observers": [],
          "closed": false,
          "isStopped": false,
          "hasError": false,
          "thrownError": null,
          "_value": {
            "entities": {},
            "ids": [],
            "loading": true,
            "error": null,
            "aircraft_id": 18737,
            "manufacturer_id": 1,
            "manufacturer_name": "Cessna Aircraft",
            "model_id": 60,
            "model_name": "172",
            "model_variant": "N",
            "model_subname": "Skyhawk",
            "model_designator": "C172",
            "serial_number": "17270821",
            "registration": "C-GVNH",
            "year_manufacture": 1978,
            "mtom_kg": 1043,
            "seats": null,
            "address_hex": "c07d76",
            "registration_status": "Registered"
          }
        }
      },
      "operator": {}
    },
    "operator": {}
  },
  "operator": {}
}

I just would like to know how to simply access the data in the store and to display it. Let's say for example the "manufacturer_name".

Here is my aircraft.store.ts:

import { Injectable } from '@angular/core';
import { EntityStore, StoreConfig } from '@datorama/akita';
import { AircraftModel, AircraftState } from './aircraft.model';

export function createInitialState(): AircraftState {
  return {
    aircraft_id: null,
    manufacturer_id: null,
    manufacturer_name: null,
    model_id: null,
    model_name: null,
    model_variant: null,
    model_subname: null,
    model_designator: null,
    serial_number: null,
    registration: null,
    year_manufacture: null,
    mtom_kg: null,
    seats: null,
    address_hex: null,
    registration_status: null
  };
}

export function createAircraft(aircraft: AircraftState) {
  return { ...aircraft };
}

@Injectable({ providedIn: 'root' })
@StoreConfig({ name: 'aircraft', idKey: 'aircraft_id' })
export class AircraftStore extends EntityStore<AircraftState, AircraftModel> {
  constructor() {
    super(createInitialState());
  }

  set(data) {
    //console.log('set function triggered');
    const aircraft = createAircraft(data.body[0]);
    this.update(aircraft);
  }
}

Here is the aircraft.service.ts:

import { HttpClient, HttpResponse } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { ID } from '@datorama/akita';
import { Configuration } from '../../_constants/app.constants';
import { AircraftDataService } from './aircraft-data.service';
import { AircraftState } from './aircraft.model';
import { AircraftStore } from './aircraft.store';

@Injectable({ providedIn: 'root' })
export class AircraftService {
  entities: AircraftState;
  private actionUrl: string;

  constructor(
    private aircraftStore: AircraftStore,
    private http: HttpClient,
    private configuration: Configuration,
    private aircrafDataService: AircraftDataService
  ) {
    this.actionUrl = configuration.apiUrl;
  }

  get(aircraftId: ID) {
    return this.aircrafDataService
      .getAircraft(aircraftId)
      .subscribe((response: HttpResponse<any>) => this.aircraftStore.set(response));
  }

}

Here is the aircraft.query.ts:

import { Injectable } from '@angular/core';
import { QueryEntity } from '@datorama/akita';
import { AircraftModel, AircraftState } from './aircraft.model';
import { AircraftStore } from './aircraft.store';

@Injectable({ providedIn: 'root' })
export class AircraftQuery extends QueryEntity<AircraftState, AircraftModel> {
    constructor(protected store: AircraftStore) {
    super(store);
  }
}

So my question is: How to display any value from the store?

Thanks a million in advance for your help.

Pierre H.
  • 107
  • 2
  • 12

1 Answers1

0

Solution

Since you are dealing with an observable, you will need to use the Async Pipe. So in your example, you would use:

{{ (store_aircraft$ | async)?.manufacturer_name }}

To read about why we use ?. see safe navigation operator

Side Note

In your aircraft.service.ts, in get, you subscribe to getAircraft. You should avoid subscribing in services and should subscribe where the call gets made, which in most cases will be in the component.

To accomplish this,

this.aircrafDataService
  .getAircraft(aircraftId)
  .pipe(
      tap(response => this.aircraftStore.set(response))
  );

Then in the component simply do:

this.aircrafDataService.getAircraft().subscribe();

Another thing that needs to be considered is unsubscribing, but I'll leave that for you to read about.

  • Hi, Thank you for your answer. Unfortunately, it doesn't work. The value on the page does not appear at all and there's no error at all in the console. I tried many options before posting my question. This should be as straightforward as rendering an observable value. What puzzles me is that the store is filled as expected. – Pierre H. Jan 16 '20 at 06:25