2016-02-20 37 views
25

Ho un componente che riceve i dati da un servizio via http, il problema è che non voglio colpire il backend API ogni volta che mostro questo componente. Voglio che il mio servizio verifichi se i dati sono in memoria, se lo è, restituisce un osservabile con l'array in memoria e, in caso contrario, effettua la richiesta http.Angular2: converte array in Observable

mio componente

import {Component, OnInit } from 'angular2/core'; 
import {Router} from 'angular2/router'; 

import {Contact} from './contact'; 
import {ContactService} from './contact.service'; 

@Component({ 
    selector: 'contacts', 
    templateUrl: 'app/contacts/contacts.component.html' 
}) 
export class ContactsComponent implements OnInit { 

    contacts: Contact[]; 
    errorMessage: string; 

    constructor(
    private router: Router, 
    private contactService: ContactService) { } 

    ngOnInit() { 
    this.getContacts(); 
    } 

    getContacts() { 
    this.contactService.getContacts() 
         .subscribe(
         contacts => this.contacts = contacts, 
         error => this.errorMessage = <any>error 
         ); 
    } 
} 

Il mio servizio

import {Injectable} from 'angular2/core'; 
import {Http, Response, Headers, RequestOptions} from 'angular2/http'; 
import {Contact} from './contact'; 
import {Observable} from 'rxjs/Observable'; 

@Injectable() 
export class ContactService { 

    private contacts: Array<Contact> = null; 

    constructor (private http: Http) { 

    } 

    getContacts() { 
    // Check first if contacts == null 
    // if not, return Observable(this.contacts)? <-- How to? 

    return this.http.get(url) 
        .map(res => <Contact[]> res.json()) 
        .do(contacts => { 
         this.contacts = contacts; 
         console.log(contacts); 
        }) // eyeball results in the console 
        .catch(this.handleError); 
    } 


    private handleError (error: Response) { 
    // in a real world app, we may send the server to some remote logging infrastructure 
    // instead of just logging it to the console 
    console.error(error); 
    return Observable.throw(error.json().error || 'Server error'); 
    } 
} 

risposta

44

Hai ragione lì. Se si dispone già di dati in memoria, è possibile utilizzare l'osservabile of (equivalente a return/just in RxJS 4).

getContacts() { 

    if(this.contacts != null) 
    { 
     return Observable.of(this.contacts); 
    } 
    else 
    { 
     return this.http.get(url) 
      .map(res => <Contact[]> res.json()) 
      .do(contacts => this.contacts = contacts) 
      .catch(this.handleError); 
    } 
} 
+0

Ha funzionato come un fascino! Grazie mille! – Mathius17

+0

Questa è probabilmente una domanda stupida, ma non potresti semplicemente memorizzare nella cache l'osservabile stesso e chiamare .next() invece di memorizzare lo stato e ricreare l'osservabile su ogni chiamata? –

+0

Buon punto, ci proverò. Anche se non è il migliore per quando voglio iterare la matrice per restituire un singolo contatto con una chiave specifica – Mathius17

0

Questo potrebbe essere estremamente tarda ad arrivare, ma ho usato sessionStorage piuttosto pesantemente per gestire alcuni dei miei lavori. Se perdi lo stato perché le persone rimbalzano, hai ancora i tuoi dati.

getSubjects(): Observable<Subject[]> { 
 
    
 
    let SubjectsString = sessionStorage.getItem("Subjects") 
 

 
    if (SubjectsString) { 
 
     let subjects: Subject[] = JSON.parse(SubjectsString); 
 
     console.log("GETTING DATA FROM SESSION STORAGE") 
 
     return Observable.of(subjects); 
 
     
 
    } else { 
 
     let url = `${this.apiHost}/api/subject`; 
 
     return this.http.get(url) 
 
     .map(res =>{   
 
    
 
      sessionStorage.setItem("Subjects",JSON.stringify(res.json()));   
 
      return res.json(); 
 
     }) 
 
     
 
     
 
    } 
 

 
     
 
    }

In questo esempio, ho una classe per soggetto e una definizione per apiHost, ma il resto è abbastanza semplice. Chiami il servizio per un osservabile. Il tuo componente non ha idea di dove siano i dati e non gli interessa. Il servizio controlla la memoria locale e, se ce l'ha, la converte in un osservabile e la restituisce, se così non fosse, va a prenderla, quindi la salva nella memoria locale e poi la restituisce.

Nel mio caso, ho alcune applicazioni enormi con centinaia di pagine. Gli utenti potrebbero rimbalzare da una nuova pagina Angular4, passare a un'era ASP classica e viceversa. Avere tutti gli elementi del menu e anche i risultati di ricerca in sessionstorage è stato un vero toccasana.

0

Soluzione rapida qui:

getSomething():Observable<Object[]>{ 
     return new Observable(observable => { 
      this.http.get('example.com').subscribe(results => { 
       observable.next(results.json()); 
       observable.complete(); 
      }); 
     }); 
    } 
0

Alcune persone, come me vogliono in modo diverso, che è da string[] in Observable<string>.

Questo è un esempio che coinvolge la conversione:

import { from } from 'rxjs/observable/from'; 
import 'rxjs/add/operator/map'; 
import 'rxjs/add/operator/toArray'; 

const ids = ['x12', 'y81']; 
let userUrls: string[]; 

from(ids) // Converting string[] into Observable<string> 
    .map(id => 'http://localhost:8080/users/' + id) 
    .toArray() 
    .subscribe(urls => userUrls = urls); 

Speriamo che aiuterà alcuni altri.

Problemi correlati