0

I have declared a class which has two arrays of objects. The arrays get filled by information from backend. I am using Observable and Http to get information from backend. The global class is declared in provider array of module.ts file, so it is declared at the highest point. In one of the top component I am subscribing to the service to fill the arrays in ngOnInit method. The data array service class in injected in the component's constructor. I see the arrays are getting populated with the right information in this class. But when I inject the same service class in child component, all arrays are null. Why? is there any way to retain the updated values? Please help.

Here is my code:

Global class AdminProductDisplayInfo (this class is added into the provider array in app.module.ts file

// admin-product-display-info.ts

import { ComponentGroupDisplayInfo } from './component-group-display';
import { ServiceCatDisplayInfo } from './service-cat-display-info';

export class AdminProudctDisplayInfo {
      public cgc_info_list: ComponentGroupDisplayInfo[] = [];
      public service_cat_info_list: ServiceCatDisplayInfo[] = []
}

// Service to get data from backend

import { AdminProudctDisplayInfo } from '../models/admin-product-display-info';

@Injectable()
export class BagProductService {

private backendURL = 'http://localhost:8080/BAG';

    constructor (private http: Http) {}

    /* This method gets the data necessary to display from backend */
    getAdminProductDisplayInfo(): Observable<AdminProudctDisplayInfo> {

        let adminURL = this.backendURL.concat('/admin/getAdminProudctDisplayInfo');
        let body = JSON.stringify("");
        let headers = new Headers({'Content-type': 'application/json'});
        let options = new RequestOptions({headers: headers});

        return this.http.post(adminURL, body, options)
                        .map(this.extractData)
                        .catch(this.handleError);
    }

}

// Component from which BagProductService and AdminProductDisplayInfo will be used to subscribe and get the data

import { BagProductService } from '../services/adminBagProduct.service';
import { ServiceCatDisplayInfo } from '../models/service-cat-display-info';

@Component({
  selector: 'admin-add-bag-Product',
  templateUrl: './admin-add-bag-product.html'
})
export class AdminAddBagProduct implements OnInit {

    constructor(private router: Router,
              private bagProdService: BagProductService,
              private adminProdDispInfo: AdminProudctDisplayInfo) {}

    ngOnInit() {
            this.bagProdService.getAdminProductDisplayInfo().subscribe(
                data => {this.adminProdDispInfo = data; console.log("data received: ", data)},
                error => {this.errorMessage = <any>error, console.log("Error Message: ", this.errorMessage)});
    }

//Here I see data being populated from backend and everything looks good.

}

// Child component of the above component where data will be used to display but everything is null here.

import { BagProductService } from '../services/adminBagProduct.service';

@Component({
  selector: 'admin-add-bag-component',
  templateUrl: './admin-add-bag-component.html'
})
export class AdminAddBagComponent {

    constructor(private router: Router, private bagProdService: BagProductService, private adminProdDispInfo: AdminProudctDisplayInfo) {

        console.log("in Component display: ", this.adminProdDispInfo.cgc_info_list);

    // Here this.adminProdDispInfo.cgc_info_list and other array is null.
  }

}
AT82
  • 71,416
  • 24
  • 140
  • 167
Jpatel
  • 45
  • 9

1 Answers1

2

You have gotten this a little backwards. AdminProudctDisplayInfo doesn't hold any data, you have just declared it as a model for your data that you are receiving (similar to interface). To actually store any data in that class you would have to have constructor and functions. BUT, I strongly suggest you skip that option and do it the Angular way instead.

If you actually want to share the data between components, you can use @Input if the parent has the the child tag in the template. Then you would subscribe to the http-request in parent, assign data in a variable e.g here an Array of Objects called data and pass that to the child like so:

<admin-add-bag-component [data]="data"></admin-add-bag-component>

and in child you use @Input, have the data in data, which you then can use in the template:

In TS:

@Input() data: Object[];

View:

<div *ngFor="let d of data">{{d.name}}</div>

Here's a closer look at the above option: Pass data from parent to child with input binding.

If your child is displayed using router-outlet, a shared service would be the way to go using Observables (usually). In your case the parent would emit the data, and the child would subscribe to the data. Depending on your case, you would want to use some type of Subject.

Hope this helps, and take a close look at Input and shared service, there are very good examples explained, much closer than I have explained here ;)

AT82
  • 71,416
  • 24
  • 140
  • 167
  • Thanks for your response. I am aware of property binding way, but since the information in AdminProductDisplay class will be shared among many components, I thought of going service way. What I realize is that if I use Observer, it creates a local copy of AdminProductDisplay object and thus the main object is not getting updated. I want to know if there is way to create a global AdminProductDispaly object and some component(s) can update it and the changed components can be used by other components. – Jpatel Apr 12 '17 at 19:40
  • Maybe this then? http://stackoverflow.com/a/41451504/6294072 This would store the data in the service, and since each component would have the binding to one and the data then, if that is what you would want? :) – AT82 Apr 12 '17 at 19:44
  • In my case, AdminAddBagProduct is subscribing to the Observable, but data is being stored into the local copy of AdminProductDisplay and not in the global copy. if i want a data into other component, I will have to re-subscribe to the Observable and in that case service will make another call to backend to receive the data, which is not good performance wise. I am wondering is there a way to retrieve data from backend once and use it through out life cycle of an application. – Jpatel Apr 12 '17 at 19:45
  • Check my comment above. This would create one global copy that you can assign `this.node = this.sharedService.sharedNode;` and then assign `this.sharedService.sharedNode = this.node;` after changes. All components would have a reference to one and same data. – AT82 Apr 12 '17 at 19:49
  • Thanks let me try that. – Jpatel Apr 12 '17 at 19:50