8

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,

5
  • 1
    Can We see ApplicationComponent Commented Mar 7, 2017 at 10:05
  • What happens if you replace Observable.empty() with Observable.of([]) Commented Mar 7, 2017 at 10:08
  • I've added the component as an edit, but it's almost empty, so I don't see why you need it :)à Commented Mar 7, 2017 at 10:09
  • @ChristopherMoore Changing it to Observable.of([]) does work. However, can you explain why I'm having this behavious? Commented Mar 7, 2017 at 10:09
  • @Complexity - let me add an answer with further details Commented Mar 7, 2017 at 10:13

3 Answers 3

12

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.

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks for the clarification. Is there any way how my component would now it the retrieval failed, or if no data was returned. Because I might want to show some error message when the retrieval failed.
If I implement this, again, error start popping up, indicating an exception in the resolver.
of([]).ifEmpty() returns false when subscribed to. I think you meant of(), which of().ifEmpty returns true. Oddly .from([]) is considered empty, while from() is not allowed.
3

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.

1 Comment

Observable.of(null) is the answer here if you have defined a type parameter of your observable (e.g. Observable<User>)
0

You can return empty observable by using this -

return new Observable<HttpEvent<any>>();

And also you can use the type to get rid of type script error.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.