2017-07-21 1 views
0

Ich versuche, Django Antwort auf Angulare User Array zu transformieren. Es gibt mehrere Gründe, z. B. verschiedene Variablennamen (first_name vs firstName) und einige Logik innerhalb Angular User Konstruktor.Wie JSON-Objekte in TS-Klasse umgewandelt werden

Einfach Django User => Angular User

Beispiel für Serverantwort:

[ 
    {"id":2,"email":"[email protected]","first_name":"Name 1","client":{"id":1}}}, 
    {"id":3,"email":"[email protected]","first_name":"Name 2","client":{"id":2}}} 
] 

Was ich will, ist in dieses Format zu transformieren:

export class User { 
    // contructor that transforms 
    id: number; 
    email: string; 
    firstName: string; 
    isClient: boolean = false; 
} 

Ich habe dies zur Zeit " gelöst ", aber ich frage mich, ob es dafür eine bessere Lösung gibt. Innen something.service.ts

public getClients(): Observable<User[]> { 
    return this.http.get(this.getClientsUrl) 
    .map(r => r.json() || []).map(x => x.map(y => new User(y))); 
} 

Wenn ich eine bessere Lösung sagen, während dies funktioniert, es sieht nicht sehr gut lesbar. Kein Problem, wenn Sie dies einmal tun, aber wenn Sie viele Anfragen haben, denken Sie über eine bessere Lösung nach (eine Methode, um damit umzugehen?). Was wäre ein besserer Weg? So etwas wie

return this.http.get(this.getClientsUrl) 
.map(transformResponse); 
+0

Gibt es einen Grund, dass Sie dies über eine Klasse anstelle einer Schnittstelle definieren möchten? –

Antwort

0

Eine Lösung, die ich fand (mit etwas Hilfe der Idee von Roman C) ist exten Service-Klasse. Diese Lösung funktioniert sowohl für Array- als auch für Objektantworten.

export class ServiceUtils { 
    protected transformResponse(response: Response, myClass: any) { 
     let body = response.json(); 

     if (body.constructor === Array) { 
      return body.map(element => new myClass(element)) || [] 
     } 

     return new myClass(body) || new myClass(); 
    } 
} 

Und mit wie folgt aus:

export class SomeService extends ServiceUtils { 

    constructor(private http: Http) { 
     super(); // Unfortunate side effect 
    } 

    public getClients(): Observable<User[]> { 
     return this.http.get(this.getClientsUrl) 
     .map(response => this.transformResponse(response, User)); 
    } 
} 

--- EDIT ---

Eine immer bessere Lösung (ohne Service-Verlängerung):

import { Response } from '@angular/http'; 


export class ServiceUtils { 
    public static transformResponse(response: Response, myClass: any) { 
     let body = response.json(); 

     if (body.constructor === Array) { 
      return body.map(element => new myClass(element)) || [] 
     } 

     return new myClass(body) || new myClass(); 
    } 
} 

Und es verwenden:

public getClients(): Observable<User[]> { 
    return this.http.get(this.getClientsUrl) 
    .map(r => ServiceUtils.transformResponse(r, User)); 
} 
0

mit sollte es so etwas wie

sein
return this.http.get(this.getClientsUrl) 
.map(r => this.transformResponse(r)); 
+0

So etwas, aber ich möchte transformResponse nur einmal implementiert haben, was bedeutet, dass es auch die Klasse als Parameter akzeptieren sollte. –

+0

Es sollte keine Klasse akzeptieren, aber es sollte ein Antwortobjekt akzeptieren. –

0

Eine TS-Schnittstelle sieht wie folgt aus:

interface SquareConfig { 
    color: string; 
    width?: number; 
    enabled: boolean; 
} 

Haben Sie ein bestimmtes Objekt in eine TS-Schnittstelle umwandeln möchten (wirklich) oder willst du das Antwortobjekt lesbarer machen? Das ist völlig anders.
Weil das "Was ich will" oben Beispiel keine TS-Schnittstelle ist.

+0

Ich habe den Titel ein wenig geändert –

+0

Ich denke, es kommt zu dem Anwendungsfall: eine Klasse kann mehr Funktionalität (Methoden) haben, wo eine Schnittstelle nur eine Reihe von Eigenschaften –

0

Wenn Sie Ihren Code anders formatiert haben und klarere Namen verwenden, wäre er z.

public getClients(): Observable<User[]> { 
    return this.http.get(this.getClientsUrl) 
     .map(response => response.json() || []) 
     .map(users => users.map(user => new User(user))); 
} 

Ich habe ein codepen example geschaffen, die die Server-Antwort korrekt formatiert abmeldet.

einem Ihrer Kommentare von anderen Antwort Lesen:

Something like this, but I would like to have transformResponse implemented only once, which means it should accept class as a parameter as well.

Ich denke, dass Sie TypeScript generics wollen, die wie folgt aussehen:

public getClients<T>(type: T): Observable<T[]> { 
    return this.http.get(this.getClientsUrl) 
     .map(response => response.json() || []) 
     .map(clients => clients.map(client => new type(user))); 
} 

Und wenn man wollte Roman C Ansatz kombinieren:

+0

Ich vereinfacht den größten Teil des Codes, um es einfacher zu machen Lesen Sie StackOverflow. Aber ich mag deine erste Lösung, im Gegensatz zu der Lösung, die ich entwickelt habe, hat sie keine Nachteile und ist einfach zu verstehen. –

+0

Ich werde es zuerst testen, obwohl es funktionieren sollte :) –

+0

Wenn Sie Ihre erste Lösung versuchen, bekomme ich 'Fehler: Fehler beim Versuch, diff '[Objekt Objekt]'. Nur Arrays und Iterables sind erlaubt. –

Verwandte Themen