0

I have a service where http request are created for subject and behaviorSubject. Then I get the data from the service to a page.ts (on the constructor) to display it in the template.

The code i did is working well, but the problem is the template "yelling" that the data from the subject are not arrived yet. So it give me error if I want to use it to initialize a FORM control or to display data from array.

PS: i tried with subject an behaviorSubject and i have the same problem. :( I'm sure I'm doing an conception error.

Someone have an idea about how to get data before the template is display ?

Thanks for your help

Service code with Subject and with behaviorSubject:

const INTI_DATA = [];

@Injectable({
  providedIn: 'root'
})
export class FormStorageService {
  dbSubject = new Subject<any[]>();
  dbBSubject = new BehaviorSubject(INTI_DATA);
  data$: Observable<any> = this.dbBSubject.asObservable();

  private _URL: any = '../assets/DB-Test/data.json';


  private dbData: any[] = [];

  constructor(private http: HttpClient) {}


  getDBDataBehavior() {
    this.http.get<any[]>(this._URL).subscribe((response: any[]) => {
      const value = response['DB_DATA'];
      this.dbBSubject.next(value);
    }, error => {
      console.log('Error : ', error);
      alert(error.message);
    });
  }

  getDBData() {
    this.http.get<any[]>(this._URL).subscribe((response: any[]) => {
      const value = response['DB_DATA'];
      this.dbSubject.next(value);
    }, error => {
      console.log('Error : ', error);
      alert(error.message);
    });
  }
}

Page.TS (Form2Page) with Subject call

export class Form2Page implements OnInit, OnDestroy {
  obsSubscription: Subscription;
  public dbData: DataModel[] = [];

  itemsForm: FormGroup;

  constructor(private storageService: FormStorageService) {
    // Get data from DB
    this.storageService.getDBData();
    this.obsSubscription = this.storageService.dbSubject.subscribe(
      (value: any[]) => {
        this.dbData = value;
        console.log('Value in FORM2 : ', value);
        console.log('DB Data in FORM2 in subscribe : ', this.dbData);
      },
      error => {
        console.log('erreur', error);
      }
    );
    console.log('DB Data DB Data in FORM2 : ', this.dbData);
  }

  ngOnInit() {
    console.log('DB Data in FORM2 in ngOnInit : ', this.dbData);
  }

  ngOnDestroy() {
    this.obsSubscription.unsubscribe();
  }
}

Result in the console. You can see the dbData get some data after a while

DB Data DB Data in FORM2 :  []
form2.page.ts:46 DB Data in FORM2 in ngOnInit :  []
form2.page.ts:29 Value in FORM2 :  {ITEMS: Array(1)}
form2.page.ts:30 DB Data in FORM2 in subscribe :  {ITEMS: Array(1)}

Page.TS (Form3Page) with BehaviorSubject call

export class Form3Page implements OnInit {
  obsBSubject$ = this.formStorage.data$;
  public dbData: any[] = [];

  constructor(private formStorage: FormStorageService) { 
    this.formStorage.getDBDataBehavior();
    this.obsBSubject$.subscribe(
      (value: any[]) => {
        this.dbData = value;
        console.log('Value in FORM3 : ', value);
        console.log('DB Data in FORM3 in subscribe : ', this.dbData);
      },
      error => {
        console.log('erreur', error);
      }
    );
    console.log('DB Data in FORM3 : ', this.dbData);
  }


  ngOnInit() {
    console.log('DB Data in FORM3 in ngOnInit : ', this.dbData);
  }

}

Result in the console. You can see the dbData get some data after a while

Value in FORM3 :  []
form3.page.ts:19 DB Data in FORM3 in subscribe :  []
form3.page.ts:25 DB Data in FORM3 :  []
form3.page.ts:30 DB Data in FORM3 in ngOnInit :  []

form3.page.ts:18 Value in FORM3 :  {ITEMS: Array(1)}
form3.page.ts:19 DB Data in FORM3 in subscribe :  {ITEMS: Array(1)}
JBD
  • 568
  • 8
  • 25

3 Answers3

1

You can use *ngIf to verify if the data already got the the frontend or not

*ngIf=="data"

Also you can check if the lenght is more than zero with another div with *ngIf to inform that the data already got here BUT with no records...

Ari Waisberg
  • 1,186
  • 1
  • 12
  • 23
1

first of all you must do get data from calling service method in ngOninit not in constructor look at this link [Difference between Constructor and ngOnInit

then before show all data into template you must ensure that data is already exists by using *ngIf

for work around solution if you don't care about performance use setTimeOut function but personally i don't prefer this sol...

Ahmed Shalash
  • 133
  • 1
  • 1
  • 12
0

There are a couple of issues I have noticed in your code and logic.

  1. ngOnInit is usually used for all the initialization/declaration. It is better to avoid placing logic in the constructor. The constructor should only be used to initialize class members but shouldn't do actual "work". So I'd suggest you move your logic from the constructor to your ngOnInit()

  2. You are not seeing the data in your console because the flow is async. So your logs are displayed in the console before this.dbdata actually receives the value.

  3. Due to the reason mentioned in point 2, if you try to create your form on the same line as your console, you will receive an error as there is no data. Instead, you should create the form once you receive the data in the subscribe method.

Page.TS (Form3Page) with BehaviorSubject call

export class Form3Page implements OnInit {
  obsBSubject$ = this.formStorage.data$;
  public dbData: any[] = [];

  constructor(
    private formStorage: FormStorageService
  ) { }

  ngOnInit() {
    this.formStorage.getDBDataBehavior();
    this.obsBSubject$.subscribe(
      (value: any[]) => {
        this.dbData = value;
        this.createForm();
        ...
      },
      error => {
        console.log('erreur', error);
      }
    );
  }

  createForm() {
    // Create form here
  }
}
nash11
  • 8,220
  • 3
  • 19
  • 55