2

I have tried looking on many sites and browsed through many posts here, but still can't find what I am looking for, or at least could not implement it work. I have an API response where depending on the request parameters it either returns an object with an array of objects (which I am able to deal with), or an object with several objects that contain arrays within them. I was able to get the data from the simple form, but the multi-object containing object is kicking my butt. I am also doing this in Angular 4, just in case that makes a difference. The response is from the holiday api.

Below is the full response with no filtering params, minus a few objects, to not beat a dead horse.

{ "status": 200, "holidays": {
   "2016-01-01": [
  {
    "name": "Durin's Day",
    "date": "2016-01-01",
    "observed": "2016-01-01",
    "public": true
  }
],
"2016-02-23": [
  {
    "name": "Founder's Day",
    "date": "2016-02-23",
    "observed": "2016-02-23",
    "public": true
  }
],
"2016-02-29": [
  {
    "name": "Leap Day",
    "date": "2016-02-29",
    "observed": "2016-02-29",
    "public": false
  }
],
"2016-03-20": [
  {
    "name": "Weasel Stomping Day",
    "date": "2016-03-20",
    "observed": "2016-03-20",
    "public": false
  }
],
"2016-04-05": [
  {
    "name": "First Contact Day",
    "date": "2016-04-05",
    "observed": "2016-04-05",
    "public": false
  }
],
"2016-04-06": [
  {
    "name": "Second Contact Day",
    "date": "2016-04-06",
    "observed": "2016-04-06",
    "public": false
  }
],
"2016-05-10": [
  {
    "name": "Whacking Day",
    "date": "2016-05-10",
    "observed": "2016-05-10",
    "public": false
  }
],
"2016-10-31": [
  {
    "name": "Harry Potter Day",
    "date": "2016-10-31",
    "observed": "2016-10-31",
    "public": false
  }
],
"2016-11-24": [
  {
    "name": "Hogswatch",
    "date": "2016-11-24",
    "observed": "2016-11-24",
    "public": false
  }
],
"2016-12-23": [
  {
    "name": "Festivus",
    "date": "2016-12-23",
    "observed": "2016-12-23",
    "public": true
  }
],
"2016-12-25": [
  {
    "name": "Decemberween",
    "date": "2016-12-25",
    "observed": "2016-12-25",
    "public": false
  },
  {
    "name": "Winter Veil",
    "date": "2016-12-25",
    "observed": "2016-12-26",
    "public": true
  }
] 
} }

Here is the code used:

import { Component, OnInit, Input } from '@angular/core';
import { HolidayService } from '../holiday.service';
@Component({
  selector: 'app-holiday',
  templateUrl: './holiday.component.html',
  styleUrls: ['./holiday.component.css']
})
export class HolidayComponent implements OnInit {
  constructor(private _holiday: HolidayService) {     
  }
  holidaysObj: any;
  holidayArr: Array<{key: string, value: string}>;
  ngOnInit() {
  }
  holidayParams(country,month){    
  this._holiday.getHolidays(country.value,month.value)
  .subscribe(responseDa
  ta => {
      this.holidaysObj = responseData;
      console.log(responseData);
    }); 
    this.convertObj(this.holidaysObj);
  }
  convertObj(obj : any){
    for(const prop in obj){
      if(obj.hasOwnProperty(prop)){
        this.holidayArr.push(obj[prop]);
      }
    }
  }
}

It works just fine when the response is called with filtering params, like 'month' and returns something like this:

{
  "status": 200,
  "holidays": [
    {
      "name": "Festivus",
      "date": "2016-12-23",
      "observed": "2016-12-23",
      "public": true
    },
    {
      "name": "Decemberween",
      "date": "2016-12-25",
      "observed": "2016-12-25",
      "public": false
    },
    {
      "name": "Winter Veil",
      "date": "2016-12-25",
      "observed": "2016-12-26",
      "public": true
    }
  ]
}
1
  • Could you post the code you are currently using to read this file? Commented May 4, 2017 at 14:52

1 Answer 1

1

You can use a custom pipe to iterate your Objects, you could also extract the data from holidays from your response like:

.map(res => res.json().holidays)

but here I won't do it.

So let's create the custom pipe:

@Pipe({
  name: 'keys'
})
export class KeysPipe implements PipeTransform {
     transform(value: any, args?: any[]): any[] {
        // check there is value to iterate
        if(value) {
        // create instance vars to store keys and final output
        let keyArr: any[] = Object.keys(value),
            dataArr = [];

        // loop through the object,
        // pushing values to the return array
        keyArr.forEach((key: any) => {
            dataArr.push(value[key]);
        });
        // return the resulting array
        return dataArr;
        }
    }
}

and then you can use it in the template like:

<div *ngFor="let d of data?.holidays | keys">
  <div *ngFor="let a of d">
    {{a.name}}
    {{a.date}}
    <!-- rest of the properties -->
  </div>
</div>

Here's a

Demo


UPDATE:

Alternatively, if you want to make your data to the same format as the other data you are receiving, you can manipulate the response. Like you mentioned, you need an if else statement first to check in which format the data is. In case the data is in the format like presented in question, you can do the following to reach the desired result:

.subscribe(data => {
   // add statuscode   
   this.data = {status:data.status,holidays:[]}      
   let keyArr: any[] = Object.keys(data.holidays);

   keyArr.forEach((key: any) => {
     // push values of each holiday
     this.data.holidays.push(data.holidays[key][0]);
   });
})

Demo

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

7 Comments

This works perfectly when the json is not given filtering parameters, like asking for a specific month. Greatly appreciate the assistance. The code fails when you provide the param and get only a single object with an array. I might have to pass it through an if-else statement to convert it prior to the rendering of it.
Yeah, you need to do that. As of now, you really cannot use the same template then, since the build of the data is different. I guess you just have to do the if else and display one template if the data is one type and display another if the type is another. OR manipulate this data so that it matches the same build as the other to be able to use the same template... I think that are your options in this case...
Updated answer with the other option to manipulate the data to the format like the other data :)
Thanks AJT_82 for your help, I am still very new to Angular. I have yet to get your updated version (the second one) to work for me, i keep getting an error when trying to use the "this.data.holidays.push" it says that ".holidays is not a property or part of Object" or something along those lines. I have tried several ways, but, my knowledge of programming is not as vast as my knowledge of aircraft maintenance...gotta love a mid career transition! :D
Aircraft maintenance, wow, very cool! :) Back to your issue though... Could you perhaps fork my plunker and add your code that could showcase the issue. Seems there is some type of typing issue, meaning that the models and declarations do not match...
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.