1

I want to be able to call a function from my filterComponent(component) inside of my engagementService(service)

The function in my filterComponent accesses an array which is within the engagementService - it uses this array's data to add into a radio button in it's html template.

It successfully accesses the array as i include the engagementService within the filterComponents constructor (I tested it via a click function but functionally this does not work as I need the radio button to have the names after loading).

This array's data is populated after my main page is loaded as the data is retrieved from an endpoint which is within the engagementService so I wish to call this function only after the graph is loaded (asynchronously), the graph function is within the engagementService, as well as other code which is where I could effectively call this function from my filterComponent after the array is populated with data and hence it would work.

I have probably done this in not the best way as I have the array within the engagementService which is populated with data from the endpoint and then I want to call the function from filterComponent within the engagementService which uses the array.

So data is going one way but not the other. I have a second component where I could also call the function as I call the graph function within there but I also had the same problem.

If i add the component class in the constructor i get 'Can't resolve all parameters for EngagementService: ([object Object], ?).'

If I just include the class as a variable it doesnt work either.

My filterComponent: I can successfully call my service within the constructor(engagementService, and I access the array from there - this.engagementService.orgSubSidNames.

  @Injectable()
  export class EngagementFilterComponent implements OnInit {
  public subsidiaryForm: FormGroup;
  public subsidiaryOptions: Array<RadioButtonGroupOptions>;
   public orgSubSidNames = [];

  @Output() updateSubSids = new EventEmitter;

  constructor(private builder: FormBuilder, public engagementService: EngagementService) { }

  ngOnInit(): void {

    this.subsidiaryForm = this.builder.group({ subsidiary: new FormControl() });
    this.subsidiaryForm.valueChanges.subscribe(data => this.updateSub(data.subsidiary, resolve));

  namesAsOrgs({ includeOpportunities, orgSubSidNames }) {
    return orgSubSidNames.map((name, i) => {
      return {
        label: name,
        value: `${i}`,
        selected: this.includeOpportunities
      }
    })
  }

  subSidNamesToRadioButton() {
    console.log('we are calling here within the subsidnamesto radio button ')
    const subSids = this.namesAsOrgs({
      includeOpportunities: true,
      orgSubSidNames: this.engagementService.orgSubSidNames
    })

    this.subsidiaryOptions = subSids;
  }

My service: (if I include the engagementFilter in the constructor or even just call the class inside of the class the system just doesnt load, and in the constructor it gives an error saying 'unable to resolve object parameters within the engagementService constructor'.

Getordsubsiaries create the array of names which is then saved in the orgSubSidNames which is called in the components function.. this works! but of course I need to call that function asynchronously as the names are retrieved by an endpoint.

    @Injectable()
   export class EngagementService {
  public orgSubSidIds = [];
  public graphParams: IGraphParams = {

  }

  constructor(private http: WefHttp) {
    this.baseURL = `${environment.ews_api_host}/${ENDPOINTS.api}`;
    this.organization = this.focus = new EngagementRoot();
  }


  getOrgSubsidiaries(id) {
    return this.organizationSubsidiaries(id)
  .subscribe(data => {
    console.log('subsidiaries data' + JSON.stringify(data));

    let subsidiaryNames = []
    data.forEach(sub => {
      subsidiaryNames.push(sub.SubsidiaryName)
    })
    subsidiaryNames = subsidiaryNames.filter(this.onlyUnique);

    this.orgSubSidNames = subsidiaryNames;

  });
 }

This getOrgSubsidiaries is called when the system is first loaded.

Sparlarva
  • 790
  • 1
  • 8
  • 30
  • If I understand your question correctly, you are trying to add the `EngagementFilterComponent` component into your `EngagementService` service. And this is not working, am I right? – dRoyson Oct 19 '18 at 08:19
  • Yes! Im sorry if it was ambiguous – Sparlarva Oct 19 '18 at 09:30
  • In that case, your implementation is causing a **cyclic dependency** in the 2 classes and hence you are getting an error. Your requirements aren't clear to me to post an answer for this. Do you mind elaborating or editing the question to help it understand. – dRoyson Oct 19 '18 at 09:45
  • Sure, I think you are right. I was stressed and not articulating myself accurately. I will change the text to better describe my intentions. – Sparlarva Oct 19 '18 at 09:47
  • Okay ive made edits – Sparlarva Oct 19 '18 at 09:56

1 Answers1

2

What you are currently doing is not possible. You cannot inject the component inside a service constructor or any other component's constructor. That is not the way to take control of the component.

If you really want to call a method of component from service, then you could make use of Subject or BehaviorSubject and then subscribe to it from the component.

service.ts

private _source = new BehaviorSubject<boolean>();
public source$ = this._source.asObservable();   // observable to be subscribed from the component

getOrgSubsidiaries(id) {
    return this.organizationSubsidiaries(id)
        .subscribe(data => {
            console.log('subsidiaries data' + JSON.stringify(data));

            ...........................
            this.orgSubSidNames = subsidiaryNames;

            //emit event
            this._source.next(true);
        });
}

component.ts

constructor(private builder: FormBuilder, public engagementService: EngagementService) { }

ngOnInit(){
   // subscribe to emitter(BehaviourSubject) of service
   this.engagementService.source$.subscribe(
   (data)=>{
       if(data){
           // call component method here every time when event is emitted
       }
   })
}
Amit Chigadani
  • 28,482
  • 13
  • 80
  • 98
  • This is more like what I need really, so basically only after the data is received, THEN call my function - actually calling it from my component file though, as I would prefer! – Sparlarva Oct 19 '18 at 10:35
  • 1
    Yes, this is a work around that needs to be followed. Indirectly calling the method of `component` from component itself but only when service informs to do so via `BehaviorSubject` – Amit Chigadani Oct 19 '18 at 10:37
  • I'm just going to try it out now, I hadn't yet heard about this! I'd heard of observables but I dont think they were applicable in this situation. – Sparlarva Oct 19 '18 at 10:38
  • 1
    https://stackoverflow.com/questions/47537934/what-is-the-difference-between-a-observable-and-a-subject-in-rxjs – Amit Chigadani Oct 19 '18 at 10:40