CodeYogi
CodeYogi

Reputation: 1422

Handling code duplication in typescript code

I am refactoring a poorly written Angular2 code which has service methods like:

  fooServiceName(body): Observable<any> {
    let headers = new Headers();
    this.loginService.writeAuthToHeaders(headers);
    return this.http.put(this.loginService.url() + '/url', body, { headers: headers })
    .map(response => response.json());
  }

  barResource(body): Observable<any> {
    let headers = new Headers();
    this.loginService.writeAuthToHeaders(headers);
    return this.http.post(this.loginService.url() + '/url', body, { headers: headers })
    .map(response => response.json());
  }

I see that following lines are used repetitively at many places:

let headers = new Headers();
this.loginService.writeAuthToHeaders(headers);

I thought to write a separate method which would call these lines but the issue is that someone new to the project has to remember to call that method, is there any better approach?

Update:

Adding missing method definition:

  /** function to write username and password to local storage of browser*/
  public writeAuthToHeaders(headers: Headers): void {
    headers.append('Accept', 'application/json');
    headers.append('Content-Type', 'application/json');
    headers.append('Authorization', 'Basic ' + btoa(getUsername() + ':' + this.getPassword()));
  }

Upvotes: 1

Views: 1614

Answers (2)

Arg0n
Arg0n

Reputation: 8423

You could write a complex type if the classes are almost identical, and pass differences to the constructor. I wrote the following as an example:

Generic.Service.ts

import { Http } from '@angular/http';
import { Observable } from 'rxjs/Rx';

export class GenericService<T> {
    protected http: Http;

    constructor(private TCreator: { new (properties: any): T }, private url: string) {}

    public get(id: number): Observable<T> {
        return this.requestSingle(`${id}`);
    }

    public getAll(): Observable<T[]> {
        return this.requestMultiple('/all.json');
    }

    private requestSingle(addedUrl?: string): Observable<T> {
        return this.request(addedUrl)
        .map((response: Response) => new this.TCreator(response.json()));
    }

    private requestMultiple(addedUrl?: string): Observable<T[]> {
        return this.request(addedUrl)
        .map((response: Response) => {
            const results: any = response.json();
            for (let i = 0; i < results.length; i++) {
                results[i] = new this.TCreator(results[i]);
            }
            return results;
        });
    }

    private request(addedUrl?: string): Observable<any> {
        return this.http.get(this.url + (addedUrl ? addedUrl : ''));
    }
}

Example usage:

Vegetable.Service.ts

import { Injectable } from '@angular/core';
import { Http } from '@angular/http';

import { GenericService } from './generic.service';
import { Vegetable } from '../app.component';

@Injectable()
export class VegetableService extends GenericService<Vegetable> {
    constructor(protected http: Http) {
        super(Vegetable, '/vegetables');
    }
}

Vegetable.ts

interface IVegetable {
  id: number;
  name: string;
  type: string;
}

export class Vegetable implements IVegetable {
  public id: number;
  public name: string;
  public type: string;

  constructor(properties: IVegetable) {
    this.id = properties.id;
    this.name = properties.name;
    this.type = properties.type;
  }
}

Some.Component.ts

import { Component, OnInit } from '@angular/core';

import { VegetableService } from './services/vegetable.service';
import { IVegetable } from '.components/vegetable.component';

@Component({
  selector: 'some-component',
  templateUrl: './some.component.html'
})
export class SomeComponent implements OnInit {
  public vegetables: IVegetable[] = [];

  constructor(private vegetableService: VegetableService) { ... }

  public ngOnInit(): void {
    ...
    this.vegetableService.getAll().subscribe((result) => this.vegetables = result);
    ...
  }
}

Upvotes: 2

Pardeep Jain
Pardeep Jain

Reputation: 86800

Better is to create one Gloabl service which shared all methods which are common, let's asume your problem

you can create Global methods for whole app to do same task like this

 getHeaders(){
    let headers = new Headers();
    this.loginService.writeAuthToHeaders(headers);
    return headers;
 }

 fooServiceName(body): Observable<any> {
    return this.http.put(this.loginService.url() + '/url', body, { headers: this.getHeaders() })
    .map(response => response.json());
  }

  barResource(body): Observable<any> {
    return this.http.post(this.loginService.url() + '/url', body, { headers: this.getHeaders() })
    .map(response => response.json());
  }

Also try to create some global methods for CRUD operations so that in future use try to use those instead of creating new everytime just need to pass variables as parameters like url, data etc.

Upvotes: 0

Related Questions