Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Make your pipe null-safe by returning null when null is passed as value

Tags:

json

angular

While using a pipe I was getting "NgFor only supports binding to Iterables such as Arrays." I received help from Guenter as can be seen from the comments, and then I ran into the issue with the keys pipe with the error "TypeError: Cannot convert undefined or null to object". Guenter then suggested to make the pipe null-safe by returning null when null is passed as value.

Here is my code on Plunker.

I am trying to print out the names of batch jobs in JSON format located here.

Here is the app.ts on Plunker:

import {Component, NgModule} from '@angular/core'
import {BrowserModule} from '@angular/platform-browser'
import { FormsModule }    from '@angular/forms';
import { HttpModule, JsonpModule } from '@angular/http';

import { JobListComponent }      from './job-list.component';
import { KeysPipe }          from './keys.pipe';
import { JobService }          from './job.service';
import { Job }          from './job';
import { routing } from './app.routes';

@Component({
  selector: 'my-app',
    template: `
    <div>
      <header>
        <div>
          <!-- Title -->
          <span>Jobs::</span>        
                <div>
                  {{jobs | json}}
                  <ul>
                    <li *ngFor="let job of jobs | keys">
                      <a>{{job.name}}</a>
                   </li>
                 </ul> 
              </div>
        </div>
      </header>
  </div>
  `,
})
export class App {
  private json;

  jobs: Observable<Job[]>;

  constructor(private jobService: JobService) {}


    ngOnInit() {

        this.jobService.listJobs()
            .subscribe(
                jobs => {
                    this.jobs = jobs,
                        console.log(this.jobs)
                    console.log("AFTER")
                });

    }


}

@NgModule({
    imports: [
    BrowserModule,
    FormsModule,
    HttpModule
  ],
  declarations: [ App,KeysPipe ],
  providers: [JobService],
  bootstrap: [ App ]
})
export class AppModule {}

I am using a pipe and I am trying to print the job name. It is modified as per Guenter's suggestion:

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

@Pipe({name: 'keys'})
export class KeysPipe implements PipeTransform {
    transform(value: any, args?: any[]): any[] {
      if(value == null) {
        return;
      }
        let keys = Object.keys(value),
            data = [];

        keys.forEach(key => {
            data.push(value[key]);
        });

        return data;
    }
}

Here is the service:

import { Injectable }    from '@angular/core';
//import { Jsonp, URLSearchParams } from '@angular/http';
import {Http, Response} from '@angular/http';
import { Job } from './job'
import 'rxjs/add/operator/map';
import {Observable} from "rxjs";


// Decorator to tell Angular that this class can be injected as a service to   another class
@Injectable()
export class JobService {

  // Class constructor with Jsonp injected
  constructor(private http:Http) { }

  // Base URI for Spring Batch Admin
  private jobsUrl = 'https://api.myjson.com/bins/1n6lw';

  // Get the list of jobs
  listJobs() {
        // RESTful service, list of jobs:
        // http://localhost:8080/batch/jobs.json
        const endPoint = 'jobs.json'

       // Return response
      return this.http.get(this.jobsUrl)
          .map(res => <Job[]> res.json().jobs.registrations);

    }

  }

Here is the JSON I am trying to parse. I am trying to print the {{job.name}}:

{ "mecConsolidatorKickoutJob": { "name": "mecConsolidatorKickoutJob", "resource": "http://localhost:8080/batch/jobs/mecConsolidatorKickoutJob.json", "description": "No description", "executionCount": 460, "launchable": false, "incrementable": false }, 
  "meceinJob": { "name": "meceinJob", "resource": "http://localhost:8080/batch/jobs/meceinJob.json", "description": "No description", "executionCount": 125, "launchable": false, "incrementable": false }, 
  "mecmdwJob": { "name": "mecmdwJob", "resource": "http://localhost:8080/batch/jobs/mecmdwJob.json", "description": "No description", "executionCount": 701, "launchable": false, "incrementable": false }, 
  "mecmdwvalidatingJob": { "name": "mecmdwvalidatingJob", "resource": "http://localhost:8080/batch/jobs/mecmdwvalidatingJob.json", "description": "No description", "executionCount": 1998, "launchable": false, "incrementable": false }, 
  "mecssnJob": { "name": "mecssnJob", "resource": "http://localhost:8080/batch/jobs/mecssnJob.json", "description": "No description", "executionCount": 217, "launchable": false, "incrementable": false } }
like image 473
Tim Schumacher Avatar asked Jan 25 '26 10:01

Tim Schumacher


1 Answers

Before all bindings are resolved or when inputs are used that are received from async calls or because just a value is never assigned to a property, parameters passed to a pipe can be null.

A pipe should not throw when null is passed. Just check

transform(value) {
  if(!value) {
    return;
  }
  // process values that are != null here
  return result;
}

Plunker example

like image 169
Günter Zöchbauer Avatar answered Jan 28 '26 00:01

Günter Zöchbauer



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!