Shah Rukh
Shah Rukh

Reputation: 300

Ngxs @Select decorator returns undefined even after subscription

I am trying to read the labels that are saved in the state.

Below is my state file

export class LabelStateModel {
  labels: LabelConfig = {};
}

@State<LabelStateModel>({
  name: 'labels',
  defaults: {
    labels: {},
  },
})
@Injectable()
export class LabelState {
  constructor(
    private realLabelService: LabelService,
    private fakeLabelService: FakeLabelService,
    @Inject('environment') private environment: any
  ) {}

  get labelService(): LabelService | FakeLabelService {
    return this.environment.isMockEnabled
      ? this.fakeLabelService
      : this.realLabelService;
  }

  @Selector()
  static getLabels(state: LabelStateModel) {
    return state.labels;
  }

  @Action(GetLabels)
  getLabels({ getState, setState }: StateContext<LabelStateModel>) {
    return this.labelService.getLabels().pipe(
      tap((labelConfig) => {
        try {
          labelConfigSchema.parse(labelConfig);
        } catch (error) {
          throw new Error(`Data validation error: ${error}`);
        }
        const state = getState();
        setState({
          ...state,
          labels: labelConfig,
        });
      })
    );
  }
}

My action file:

export class GetLabels {
  static readonly type = '[Label] Get';
}

This is my test Service, where the error occurs

ERROR TypeError: Cannot read properties of undefined (reading 'subscribe')
@Injectable({
  providedIn: 'root',
})
export class TextService {
  @Select(LabelState.getLabels) labels$!: Observable<LabelConfig>;

  convert(data: GeneralText[]): Observable<LabelConfig> {
    // The error is
    // ERROR TypeError: Cannot read properties of undefined (reading 'subscribe')
    this.labels$.subscribe((labels) => {
      console.log('labels', labels);
    });

    return of({ labelId: 'L_REF_ID' });
  }
}

It should get the value of the state I have also added a screenshot of devtools enter image description here

Solution

I made it work like this

@Injectable({
  providedIn: 'root',
})
export class TextService {
  constructor(private store: Store) {}

  // @Select(LabelState.getLabels) labels$!: Observable<LabelConfig>;

  convert(data: GeneralText[]): Observable<LabelConfig> {
    const labels$ = this.store.select(
      (state) => state.labels.labels
    ) as Observable<LabelConfig>;

    labels$.subscribe((labels) => {
      console.log('labels', labels);
    });

    return of({ labelId: 'L_REF_ID' });
  }
}

But still why isnt @Select working?

@Select(LabelState.getLabels) labels$!: Observable<LabelConfig>;

Upvotes: 1

Views: 386

Answers (1)

user10123947
user10123947

Reputation:

It's not literally possible to determine why your code is not working based solely on the screenshot you've provided.

The @Select decorator is explicit in its behavior, as it reads the Store instance from the global service locator and defines the property on the class using a getter that returns store.select(...arguments).

The last solution is correct since we're deprecating the @Select decorator. You need to replace all instances of the @Select decorator in your code with Store injection and store.select.

Upvotes: 3

Related Questions