angulartypescriptactionngrx

Actions is initialized as undefined in the class constructor


The functionality "this.actions$.pipe" does not work due to the undefined value of actions$.

TypeError: Cannot read properties of undefined (reading 'pipe') at note.effects.ts:17:19 at createEffect (ngrx-effects.mjs:85:47) at <instance_members_initializer> (note.effects.ts:16:16) at new _NoteEffects (note.effects.ts:11:3) at Object.NoteEffects_Factory [as factory] (note.effects.ts:61:6) at core.mjs:3132:35 at runInInjectorProfilerContext (core.mjs:866:5) at R3Injector.hydrate (core.mjs:3131:11) at R3Injector.get (core.mjs:3005:23) at injectInjectorOnly (core.mjs:1095:36)

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { environment } from '../../environments/environment.development';
import { NoteDetail } from './note-detail.model';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root',
})
export class NoteDetailService {
  readonly url: string = environment.apiBaseUrl + '/notes';
  list: NoteDetail[] = [];
  formData: NoteDetail = new NoteDetail();
  formSubmitted: boolean = false;
  constructor(private http: HttpClient) {}

  refreshList(): Observable<NoteDetail[]> {
    return this.http.get<NoteDetail[]>(this.url);
  }
}
import { Injectable } from '@angular/core';
import { of } from 'rxjs';
import { catchError, map, mergeMap } from 'rxjs/operators';
import { NoteDetailService } from '../../note-detail.service';
import * as NoteActions from './note.actions';
import { NoteDetail } from '../../note-detail.model';
import { Actions, createEffect, ofType } from '@ngrx/effects';

@Injectable()
export class NoteEffects {
  constructor(
    public actions$: Actions, // actions$ undefined value
    public noteService: NoteDetailService // noteService undefined value
  ) {}

  loadNotes$ = createEffect(() =>
    this.actions$.pipe(
      ofType(NoteActions.loadNotes),
      mergeMap(() =>
        this.noteService.refreshList().pipe(
          map((notes: NoteDetail[]) => NoteActions.loadNotesSuccess({ notes })),
          catchError((error) => of(NoteActions.loadNotesFailure({ error })))
        )
      )
    )
  );    

main.ts

import { bootstrapApplication } from '@angular/platform-browser';
import { provideHttpClient } from '@angular/common/http';
import { AppComponent } from './app/app.component';
import { provideRouter } from '@angular/router';
import { routes } from './app/app.routes';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { ToastrModule } from 'ngx-toastr';
import { importProvidersFrom, isDevMode } from '@angular/core';
import { CommonModule } from '@angular/common';
import { provideStore } from '@ngrx/store';
import { provideEffects } from '@ngrx/effects';
import { provideStoreDevtools } from '@ngrx/store-devtools';
import { noteReducer } from './app/store/note.reducer';
import { NoteEffects } from './app/store/note.effects';

bootstrapApplication(AppComponent, {
  providers: [
    provideRouter(routes),
    provideHttpClient(),
    importProvidersFrom(CommonModule),
    importProvidersFrom(BrowserAnimationsModule),
    importProvidersFrom(ToastrModule.forRoot()),
    provideStore({ notes: noteReducer }),
    provideEffects([NoteEffects]),
    provideStoreDevtools({ maxAge: 25, logOnly: !isDevMode() }),
  ],
}).catch((err) => console.error(err));
    import { Component, Input, Output, EventEmitter } from '@angular/core';
    import { Store } from '@ngrx/store';
    import { FormsModule } from '@angular/forms';
    import { NgForm } from '@angular/forms';
    import { ToastrService } from 'ngx-toastr';
    import { CommonModule } from '@angular/common';
    import { addNote, updateNote } from '../../store/note.actions';
    
    @Component({
      selector: 'app-note-details-form',
      standalone: true,
      imports: [FormsModule, CommonModule],
      templateUrl: './note-details-form.component.html',
      styleUrl: './note-details-form.component.scss',
    })
    export class NoteDetailsFormComponent {
      @Input() formData = { id: 0, noteText: '' };
      @Output() submit = new EventEmitter<any>();
      formSubmitted: boolean = false;
    
      constructor(private store: Store, private toastr: ToastrService) {}
    
      onSubmit(form: NgForm) {
        this.formSubmitted = true;
        if (form.valid) {
          if (this.formData.id === 0) this.insertRecord(form);
          else this.updateRecord(form);
        }
      }
    
      insertRecord(form: NgForm) {
        this.store.dispatch(addNote({ note: this.formData }));
        this.resetForm(form);
        this.toastr.success('Inserted successfully', 'Note Detail Register');
      }
    
      updateRecord(form: NgForm) {
        this.store.dispatch(updateNote({ note: this.formData }));
        this.resetForm(form);
        this.toastr.info('Updated successfully', 'Note Detail Register');
      }
    
      resetForm(form: NgForm) {
        form.resetForm();
        this.formData = { id: 0, noteText: '' };
      }
    }
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { environment } from '../../environments/environment.development';
import { NoteDetail } from './note-detail.model';
import { NgForm } from '@angular/forms';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root',
})
export class NoteDetailService {
  private url: string = environment.apiBaseUrl + '/notes';
  list: NoteDetail[] = [];
  formData: NoteDetail = new NoteDetail();
  formSubmitted: boolean = false;

  constructor(private http: HttpClient) {}

  refreshList(): Observable<NoteDetail[]> {
    console.log(this.http.get<NoteDetail[]>(this.url));
    return this.http.get<NoteDetail[]>(this.url);
  }

  postNoteDetail(note: NoteDetail): Observable<any> {
    return this.http.post(this.url, note);
  }

  putNoteDetail(note: NoteDetail): Observable<any> {
    return this.http.put(this.url + '/' + note.id, note);
  }

  deleteNoteDetail(id: number): Observable<any> {
    return this.http.delete(this.url + '/' + id);
  }

  resetForm(form: NgForm) {
    form.form.reset();
    this.formData = new NoteDetail();
    this.formSubmitted = false;
  }
}
import { Component, OnInit } from '@angular/core';
import { CommonModule } from '@angular/common';
import { NoteDetailsFormComponent } from './note-details-form/note-details-form.component';
import { Store } from '@ngrx/store';
import { NoteState } from '../store/note.state';
import { loadNotes, deleteNote, updateNote } from '../store/note.actions';
import { ToastrService } from 'ngx-toastr';
import { Observable } from 'rxjs';
import { NoteDetail } from '../shared/note-detail.model';

@Component({
  selector: 'app-note-details',
  standalone: true,
  imports: [CommonModule, NoteDetailsFormComponent],
  templateUrl: './note-details.component.html',
  styleUrls: ['./note-details.component.scss'],
})
export class NoteDetailsComponent implements OnInit {
  notes$: Observable<NoteDetail[]>;
  formData: NoteDetail = new NoteDetail();

  constructor(private store: Store<NoteState>, private toastr: ToastrService) {
    this.notes$ = this.store.select((state) => state.notes);
  }

  ngOnInit(): void {
    this.store.dispatch(loadNotes());
  }

  populateForm(selectedRecord: NoteDetail) {
    this.formData = { ...selectedRecord };
  }

  onDelete(id: number) {
    if (confirm('Are you sure to delete this record?'))
      this.store.dispatch(deleteNote({ id }));
  }
}

I checked through DevTools what exactly is causing the problem: two values ​​from the constructor take on undefined values, which is why the program does not work any more. Help solve this problem.


Solution

  • Are you sure about your constructor?

    export class NoteEffects {
      constructor( public actions$: Actions, public noteService: NoteDetailService) {}
     ...
    }
    

    or they are simple variables?

    export class NoteEffects {
      public actions$: Actions, 
      public noteService: NoteDetailService
      constructor() {}
      ...
    }
    

    NOTE: as they are public variables you always can, after inject the service give values to the variable

    //in another component
    constructor(private noteEfect:NoteEfect){
       this.noteEfects.actions$=...
       this.noteEfect.noteService=...
    }