Reputation: 754
I am having an issue with the amount of code duplication in both my component as well as my service class. I would like to reduce this where possible while retaining strong typing. Is there a way to reduce the amount of similar code by passing in the interface or something similar?
Lets say we have 5 types:
I have defined all of my types where each type is different except for the Primary Key(id):
interface House {
address: string;
squareFt: number;
id: string;
...
}
interface Person {
name: string;
age: number;
id: string
...
}
I have my component: app.component.ts
export class AppComponent implements OnInit {
house: House;
person: Person;
animal: Animal;
plant: Plant;
car: Car;
constructor(public dataService: DataService){ }
ngOnInit() {
// House
this.dataService.getHouseData().subscribe(
(house: House) => {
this.house = house;
...
},
(error) => console.error(error),
() => console.log('Finished House Data')
);
// Person
this.dataService.getPersonData().subscribe(
(person: Person) => {
this.person = person;
...
},
(error) => console.error(error),
() => console.log('Finished Person Data')
);
...
}
I have this service: dataService.ts
export class DataService {
constructor(public http: HttpClient) {}
handleError(error: Response) {
// handlesErrors
}
retryWithBackOff(delay, maxRetry) {
// retry http call with exponential backoff
}
// Get House Data
public getHouseData(): Observable<House> {
return this.http.get<House>(myURL).pipe(
this.retryWithBackoff(1000, 3),
catchError(this.handleError)
)
}
// Get Person Data
public getPersonData(): Observable<Person> {
return this.http.get<Person>(myURL).pipe(
this.retryWithBackoff(1000, 3),
catchError(this.handleError)
)
}
...
}
What I would like to do is something like this to reduce my code: app.component.ts
export class AppComponent implements OnInit {
house: House;
person: Person;
animal: Animal;
plant: Plant;
car: Car;
constructor(public dataService: DataService){ }
ngOnInit() {
const obj = [
{
url: 'house'
type: House
}, {
url: 'person'
type: Person
},
...
];
_.map(obj, (val) => {
this.dataService.getData<val.type>().subscribe(
(data: val.type) => {
if(val.url === 'house') this.house = data;
if(val.url === 'person') this.person = data;
...
},
(error) => console.error(error),
() => console.log('Finished retrieving data')
);
}
}
Then: dataService.ts
export class DataService {
constructor(public http: HttpClient) {}
handleError(error: Response) {
// handlesErrors
}
retryWithBackOff(delay, maxRetry) {
// retry http call with exponential backoff
}
// Get Data
public getData<T>(): Observable<t> {
return this.http.get<T>(myURL).pipe(
this.retryWithBackoff(1000, 3),
catchError(this.handleError)
)
}
}
Is something like this possible?
Upvotes: 1
Views: 159
Reputation: 29335
So, this is just a different approach, combining your streams helps to clean up the code.
ngOnInit() {
forkJoin(
this.dataService.getHouseData(),
this.dataService.getPersonData()
).subscribe(
([house: House, person: Person]) => {
this.house = house;
this.person = person;
},
(error) => console.error(error),
() => console.log('Finished Data')
);
}
but even better, is not subscribing at all and using the async pipe:
ngOnInit() {
this.house$ = this.dataService.getHouseData()
this.person$ = this.dataService.getPersonData()
}
and in templates you'd use these like so:
<div *ngIf="house$ | async as house">{{house | json}}</div>
<div *ngIf="person$ | async as person">{{person | json}}</div>
or even combine the methods if you like:
ngOnInit() {
this.data$ = forkJoin({
house: this.dataService.getHouseData(),
person: this.dataService.getPersonData()
})
}
<div *ngIf="data$ | async as data">
{{data.house | json}}
{{data.person | json}}
</div>
Upvotes: 1