2

I am trying to figure out how to make a re-usable component in Angular. I am stuck in one particular aspect though. The component depends on a service (which has been made injectable). The service retrieves a list of items from a server. The URL to retrieve the items from however depends on the context of instantiation of the re-usable component using the service.

I have cobbled together an absolute minimal plunkr demonstrating this.

https://plnkr.co/edit/HcnGjEOFiDAq2HsNOYPY

The re-usable component here is in yygggg-list.component.*

The injectable service is in yygggg.service.ts. I have commented out the HTTP retrieve for the sake of the plunker and replaced with returning a fixed array but the URL in the HTTP retrieve is the aspect needing variability. More specifically this.realm:

return this.http.get("http://localhost/" + this.realm + ".php")
    .toPromise()
    .then(response => response.json() as string[])
    .catch(this.handleError);

There are now two contexts (I call them realms in the app) within which I wish to use the yygggg-list component: from METAR and SYNOP components. Barring the names, they are duplicates from one-another in the plunkr for simplicity (not in the real-life though). Here the SYNOPs (plural) component depends on the re-usable yygggg-list and a SYNOP (singular) component. The idea is to select an entry from the drop-down yygggg-list which washes through to selecting a specific SYNOP. Currently I pass the realm as a parameter to yygggg-list in the SYNOPs HTML.

<yygggg-list realm="synop" [(yygggg)]="selyygggg"></yygggg-list><br/>
<synop-capture [yygggg]="selyygggg"></synop-capture>

My current hack is to then pass this realm onto the service in the re-usable component's ngOnInit:

ngOnInit() : void
{
    this.yyggggsvc.realm = this.realm;
    ...
}

For this to work though the service's default value for realm needs to coincide with the default selected realm of the app on startup which is why i call it a hack as in yygggg.service.ts:

public realm: string = "synop";

I was hoping there is someone here understanding Angular well enough to assist me in getting rid of the hack and making this clean. The abstraction of a yygggg-list is really shareable between them, its just the URL that needs to vary so I can retrieve the list from the correct database table.

1 Answer 1

1

In the component where you provide the service you can also provide a configuration

@Component({
  ...,
  providers: [{provide: 'url', useValue: 'http:/...'}],
  template: '<yy-gggg-list></yy-gggg-list>',
)
export class ParentComponent {}

the service can then inject the config

constructor(private http: Http, @Inject('url') private url:String) {}    

Instead of just a string token you can also use an InjectionToken

Sign up to request clarification or add additional context in comments.

3 Comments

The problem I see is that I need to apply your suggestion in yygggg-list.component.ts which is the re-usable component and the URL is not known there to provide it. It is only known when instantiating the component from synops.component.html or metars.component.html
You can provide the url also at a parent component or at module level. This way you can share an url among several yygggg-list.component s. Only if you want to use several list instances within the same parent component with different urls it's becoming a bit more complicated. You can use a directive at the list elements tag that only provides the URL, but this would require a different directive for each url.
Aaah, that is the mental block I had. Thanks

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.