Return an empty Observable from an Angular2 Servic

2020-07-10 07:57发布

问题:

I'm building an Angular 2 application, which uses a service to gather data. The service does contain the following logic:

/* ========== CORE COMPONENTS ========== */
import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/Rx';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';

/* ========== MODELS ========== */
import { IApplicationViewModel } from './models/application.model';

/* ========== CONSTANTS ========== */
import { LogzillaServerConfiguration } from '../../app.configuration';

@Injectable()
export class ApplicationService {
    private getAllEndpoint = LogzillaServerConfiguration.host + '/api/administration/application/getAll';

    // Initializes a new instance of the 'ApplicationService'.
    constructor(private http: Http) { }

    // Get all the 'logzilla' applications.
    getApplications(): Observable<IApplicationViewModel[]> {
        return this.http.get(this.getAllEndpoint)
            .map((response: Response) => <IApplicationViewModel[]>response.json().model)
            .catch(this.handleError);
    }

    // Handle an error that occured while retrieving the data.
    // This method will throw an error to the calling code.
    private handleError(error: Response) {
        return Observable.empty();
    }
}

What this service does is retrieving data from an endpoint, and map it to a model, when an error does occur, I'm returning an empty Observable.

I also have a resolver, which is used to load the data from the service, before the active route is changed. This resolver does contain the following logic:

/* ========== CORE COMPONENTS ========== */
import { Injectable } from '@angular/core';
import { Resolve, ActivatedRouteSnapshot } from '@angular/router';

/* ========== APPLICATION SERVICES ========== */
import { ApplicationService } from './application.service';

/* ========== MODELS ========== */
import { IApplicationViewModel } from './models/application.model';
import { IApplicationLogLevel } from './models/applicationLevel.model';

// Defines the 'resolver' which is used to resolve the applications.
@Injectable()
export class ApplicationResolver implements Resolve<IApplicationViewModel[]> {

    // Initializes a new instance of the 'ApplicationResolver'.
constructor(private applicationService: ApplicationService) { }

// Get all the registered applications.
resolve(route: ActivatedRouteSnapshot) {
    return this.applicationService.getApplications();
}
}

The definition of my route is:

{ path: 'applications', component: ApplicationComponent, pathMatch: 'full', resolve: {
            application: ApplicationResolver
        }},

However, when I browse to /applications, I'm greeted with an error Uncaught (in promise): Error: no elements in sequence..

Edit: Added component

@Component({
    selector: 'logzilla-applications',
    templateUrl: './src/app/pages/applications/application.template.html'
})
@Injectable()
export class ApplicationComponent implements OnInit {
    hasApplications: boolean;
    applications: IApplicationViewModel[];
    errorMessage: string;

    // Initializes a new instance of the 'ApplicationComponent'.
    constructor (private route: ActivatedRoute) { 
        console.log('I am here.');
    }

    // This method is executed when the component is loaded.
    ngOnInit() { 

    }

The constructor of my component is not event called. How can this be resolved.

Kind regards,

回答1:

Replace Observable.empty() with Observable.of([]). The perference of of over empty is what the official Angular Tour of Heroes tutorial uses to return an empty observable, and is what I have been using in all my apps.

The difference between them seems to be whether nothing is returned, or an empty array.

From the official rxjs docs:

Observable.empty()

Creates an Observable that emits no items to the Observer and immediately emits a complete notification.

Observable.of()

Creates an Observable that emits some values you specify as arguments, immediately one after the other, and then emits a complete notification.



回答2:

The resolver tries to subscribe to the given Observable and pass the first result of the Observable sequence to the component (actually the ActivatedRoute object).

But because your Observable fires the completed event before an result is emitted the resolver does not get a result. So that's where your error comes from.

You have to return either Observable.of(null) or Observable.of([]) or something similar. Then you can handle the empty input in your component.

This page contains more information about the Observable.empty()function.



标签: angular