Reputation: 89
I have a service in Angular 7 that calls an API and I want to use some data gathered by a component in the API call. Here is the relevant portion of the component:
import { Component, OnInit } from "@angular/core";
import { IPrompt } from './prompt';
import { PromptService } from './prompt.service';
import { DropdownService } from '../dropdown.service'
import { FormGroup, FormControl, ReactiveFormsModule } from '@angular/forms';
import { IQuery } from './prompt'
import { NgxSpinnerService } from 'ngx-spinner';
import { Query } from '../dropdown.service';
@Component({
selector: 'pm-prompts',
templateUrl: './prompt-list.component.html',
styleUrls: ['./prompt-list.component.css']
})
export class PromptListComponent implements OnInit
{
public get searchArray(): string[]
{
return [ this.searchForm.controls['searchQuery'].value, this.searchForm.controls['region'].value,
this.searchForm.controls['status'].value, this.searchForm.controls['language'].value,
this.searchForm.controls['inputMode'].value ];
}
public get QueryString(): string
{
var query = new Query(this.searchForm.controls['searchQuery'].value, this.searchForm.controls['region'].value,
this.searchForm.controls['status'].value, this.searchForm.controls['language'].value,
this.searchForm.controls['inputMode'].value, this.searchArray);
return query.getQuery;
}
}
I removed all the unnecessary fields from the above sample. Basically, I want to access the get QueryString()
method that is in this component from my service called PromptService. I can include the code for the service as well if needed. I've researched this but all of the questions I see has asked how to use data from a service in a component, not the other way around.
I tried importing the component to the service then using:
queryString = PromptListComponent.QueryString()
But I get an error saying that "Property 'QueryString' does not exist on type 'typeof PromptListComponent'". I feel that there is a simple fix for this but I have had no luck finding it or figuring it out.
Upvotes: 2
Views: 4005
Reputation: 874
Assuming that you are not listening from an event from the UI, but executing an action in the service that need to get the component property.
I am leveraging the Visitor pattern for this solution.
There are a couple of things that you appear to be missing, based on provided sample code.
Ok, now that we have some context to work from, lets see a potential way to achieve what you are looking for:
public interface IPropertyReader {
readProperty<T>(prop: string): T
}
@Component({
selector: 'pm-prompts',
templateUrl: './prompt-list.component.html',
styleUrls: ['./prompt-list.component.css']
})
export class PromptListComponent implements OnInit, IPropertyReader
{
constructor(private promptService: PromptService) {
promptService.registerComponent(this)
}
public readProperty<T>(prop: string):T {
if (!this.hasOwnProperty(prop)) {
throw Error(`Property "${prop}" does not exists`);
}
return this[prop];
}
}
@Injectable({ providedIn: 'root' })
export class PromptService {
component: IPropertyReader
public registerComponent(comp: IPropertyReader) {
this.component = comp;
console.log(this.component.readProperty<string>("QueryString"));
}
}
Upvotes: 2
Reputation: 29355
The reason everything you see is about accessing data from a service in a component is because you've inverted control. Your logic should be that the component is PUSHING this data to the service, not that the service is PULLING this data from your component.
your theoretical service should have a sort of setQueryString(queryString: string)
method that accepts the query string as an argument, and your component, whenever the query string changes, calls that services method. since your already using reactive forms, this is quite simple!
this.searchForm.valueChanges.subscribe(value => this.myService.setQueryString(this.QueryString));
there are MANY alternative ways to do this, but the principle should be the same, data is always being pushed, never pulled.
Upvotes: 3
Reputation: 2987
You can import the component to the service and define it in your constructor, it generate an instance of that component, then you can access methods and properties from that component's instance:
In your service file:
import { PromptListComponent } from './path-to-your-component';
import { Injectable } from '@angular/core';
@Injectable({providedIn:'root'}) //Or import to providers
export class PromptService {
//Define it in your service constructor
constructor( private promptListComponent: PromptListComponent){}
//You now have generated an instance of that component
getQueryFromPromtListComponent() {
console.log(this.promptListComponent.QueryString())
}
}
Upvotes: 4