Filtering a json array obtained from a web service

2020-03-31 23:56发布

I am creating a project which uses a HTTP get from a web service and returns an array of projects, with ID, name, description etc.

There is many projects within this web service but I am only concerned with 9 of them the rest are irrelevant.

I have a desired set of 9 projects with unique ID's declared in the project.service.http.ts class that I want to only be showing.

I am trying to filter the HTTP get request to only include the 9 specific Ids, which I store in a projectIds array of type string.

EDIT2: With logging the response: enter image description here

EDIT SOLVED: I changed the constructor in the project.viewer.component from :

 constructor(private service: ProjectService) {
        this.service.fetchProjects().subscribe(response => {
          this.projects = response.filter(elements => {
            // BaseComponent was my class. Use yours.
            return ProjectViewerComponent.projectIds.includes(elements.id);
          });
        })
      }

to :

 constructor(private service: ProjectService) {
        this.service.fetchProjects().subscribe(response => {
          this.projects = response['project'].filter(elements => {
            // BaseComponent was my class. Use yours.
            return ProjectViewerComponent.projectIds.includes(elements.id);
          });
        })
      }

The Key was the ['project'] after the this.projects = response

project.service.http.ts:

@Injectable()
export class ProjectServiceHttp extends ProjectService {

    //variables
    baseUrl = "http://...";

        static projectIds: string[] = ["..."
                                ,"...", "..","..."];

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

    //methods
    fetchProjects(): Observable<any>{
        let headers = new Headers({'Content-Type': 'application/json'});
        let options = new RequestOptions({headers: headers});
        return this.http.get(this.baseUrl, options)
          .map((response: Response) => response.json())
          .catch(this.handleError);
      }

        private handleError(error: any) {
            // In a real world app, we might use a remote logging infrastructure
            // We'd also dig deeper into the error to get a better message
            let errMsg = (error.message) ? error.message :
                error.status ? `${error.status} - ${error.statusText}` : 'Server error';
            console.log(errMsg); // log to console instead
            return Observable.throw(errMsg);
        }
}

project.viewer.component.ts:

@Component({
    selector: 'project-viewer',
    templateUrl: './project-viewer.html',  
    styleUrls: ['./project-viewer.css']
})


export class ProjectViewerComponent  {
    name = 'ProjectViewerComponent';
    projects: Project[] = [];

    static testIds: string[] = ['qqq', 'aaa'];

    static projectIds: string[] = ["...","..."
    ,"..","..","...","..."
    ,"..", "...","..."];

    errorMessage = "";
    stateValid = true;

      constructor(private service: ProjectService) {
        this.service.fetchProjects().subscribe(response => {
          this.projects = response.filter(elements => {
            return ProjectViewerComponent.projectIds.includes(elements.id);
          });
        })
      }

    private raiseError(text: string): void {
        this.stateValid = false;
        this.errorMessage = text;
    }
}

project-viewer.html:

<h3>Projects </h3>
<div >
    <ul class= "grid grid-pad">
        <a *ngFor="let project of projects" class="col-1-4">
            <li class ="module project" >
                <h4 tabindex ="0">{{project.name}}</h4>
            </li>
        </a>
    </ul>
</div>

2条回答
爱情/是我丢掉的垃圾
2楼-- · 2020-04-01 00:02

you could use a pipe to filter those projects based on your condition (that passes only for those 'unique ids') and apply them on your *ngFor in the template like this,

<a *ngFor="let project of projects | uniqueOnes" class="col-1-4">

Define the pipe like this,

@Pipe({
  name: 'uniqueOnes'
})
export class UniqueOnesPipe implements PipeTransform {
  uniqueIds = [ 'id1', 'id2', 'id5'];

  transform(value: any): any {
    return value
            ? value.filter(project => { return <condition to pass only the unique projects (For ex: this.uniqueIds.indexOf(project.id) !== -1)>  })
            : value;
  }

}

More on pipes here.

查看更多
趁早两清
3楼-- · 2020-04-01 00:04

The method fetchProjects() from your service could be re-used in another component. So you might want it to return all the projects, since it's the aim of this method. To fetch all the projects.

First method (recommended) :

The best thing would be to filter the data you get from the return of your HTTP Call.

In that way, you need to filter the data you get from the service to display only what you want in that component.

project.viewer.component.ts :

.subscribe(response =>{
  this.projects = response.project.
    .filter(elements => someCondition);
  console.log(response);
  console.log(this.projects);
},

Second method (not recommended) :

The only time you will want to use the .map() method to change the data you get from your service call is when you are sure you won't ever need to have all the projects, but only these ones. Of course, you could do another function that would call the same URL and not filter that data, but then you will have to maintain two methods doing basically the same call. That's why it's better to filter your data in your component and not in your service.

Nonetheless, you would need to change this part in your service :

project.service.http.ts : (should be called project.service.ts btw)

.map((response: Response) => {
  const results = response.json();
  return = results.filter(elements => someCondition);
})

EDIT : Here is the working solution with your class object and my own mock data :

project.service.http.ts : Initial one, don't use .filter().

fetchProjects(): Observable<any>{
  const headers = new Headers({'Content-Type': 'application/json'});
  const options = new RequestOptions({headers: headers});
  return this.http.get(this.baseUrl, options)
    .map((response: Response) => response.json())
    .catch(this.handleError);
}

project.viewer.component.ts :

You will need to adapt a bit since I took some of your code to do a fast example (my projects IDs are 'qqq' and 'aaa').

  static projectIds: string[] = ['yourIds', 'YourIds2', ...];

  projects: Project[] = [];

  constructor(private service: ProjectService) {
    this.service.fetchProjects().subscribe(response => {
      this.projects = response.filter(element => BaseComponent.projectIds.includes(element.id)); // BaseComponent was my class. Use yours.
    })
  }

project-viewer.html : Unchanged.

In my example, my service sends me 4 projects, and I filter 2 of them to only display 2. Works great, tell me if you have any problem adapting to your code.

As you can see, this is the application of the first method I mentionned first. Do not apply this to the service as well for the reasons stated in the second method.

查看更多
登录 后发表回答