6

I have below JSON, from this I want to extract Skills where it is true.

[  
   {  
      "_id":"5de9f351baca28556c6a4b71",
      "Name":"Harsha",
      "Age":20,
      "Gender":"M",
      "Skills":{  
         "Java":"",
         "Mule":true,
         "Angular":""
      }
   },
   {  
      "_id":"5de9f358baca28556c6a4b72",
      "Name":"Anji",
      "Age":21,
      "Gender":"M",
      "Skills":{  
         "Java":"",
         "Mule":true,
         "Angular":true
      }
   },
   {  
      "_id":"5dea110297c2b65298b136e4",
      "Name":"Abhi",
      "Age":25,
      "Gender":"M",
      "Skills":{  
         "Java":"",
         "Mule":true,
         "Angular":""
      }
   }
]

I am able to print rest of the data using below code

<table *ngIf="formTemplate">
        <tr>
            <th *ngFor="let header of questionTitleArray" >{{header}}</th>
        </tr>

        <tr *ngFor="let data of surveyDataFromDB">
                <ng-container *ngFor="let head of questionTitleArray">
                <td>{{data[head]}}</td>         
        </ng-container>
        </tr>
    </table>

(Here JSON is "surveyDataFromDB")

Below is the output I am getting

Name    Age Gender  Skills
Harsha  20  M   [object Object]
Anji    21  M   [object Object]
Abhi    25  M   [object Object]

I want Skills which are true in place of [object Object]. Please help.

Abhi
  • 614
  • 2
  • 12
  • 26
  • You need sth like [this](https://stackoverflow.com/questions/35534959/access-key-and-value-of-object-using-ngfor) another ng for printing skills – Eldar Dec 06 '19 at 09:31
  • Try this one `Object.keys(skills).filter((skill) => {return skills[skill] == true;});` – hrdkisback Dec 06 '19 at 09:44

7 Answers7

4

You can first map your object to only have the truthy ones. You can use lodash pickBy.

mappedSurveyDataFromDB = this.surveyDataFromDB.map(
    entry => ({...entry, Skills: _pickBy(entry.Skills, Boolean)}),
  );

After change the template like this:

<table>
  <tr>
    <th *ngFor="let header of questionTitleArray">{{ header }}</th>
  </tr>

  <tr *ngFor="let data of mappedSurveyDataFromDB">
    <ng-container *ngFor="let head of questionTitleArray">
      <td *ngIf="head !== 'Skills'">{{ data[head] }}</td>
      <td *ngIf="head === 'Skills'">
        <ng-container *ngFor="let entry of (data[head] | keyvalue); let last = last">
          {{ entry.key }}
          <ng-container *ngIf="!last">, </ng-container>
        </ng-container>
      </td>       
    </ng-container>
  </tr>
</table>

Stackblitz: https://stackblitz.com/edit/angular-ga7lqg

MoxxiManagarm
  • 8,735
  • 3
  • 14
  • 43
  • It gave me exactly what I need. Thanks a lot. :) – Abhi Dec 06 '19 at 10:04
  • It is working perfectly if we have "Skills" in JSON. But what if we want to make your approach dynamic. There can be other name for the object which is currently referred as "Skills". Please help. – Abhi Dec 06 '19 at 10:17
  • I guess you need to do a mix of my answer and the one from 'Yash Rami'. (typeof) – MoxxiManagarm Dec 06 '19 at 12:48
2

you can try like this

<table *ngIf="formTemplate">
        <tr>
            <th *ngFor="let header of questionTitleArray" >{{header}}</th>
        </tr>

        <tr *ngFor="let data of surveyDataFromDB">
                <ng-container *ngFor="let head of questionTitleArray">
// here we are iterating a loop with keyvalue pipe bcs "Skills" is object
                 <span *ngIf="typeOf(data[head]) === 'object' else elsePart">
                    <td *ngFor="let j of data[head] | keyvalue">
                          {{j.key}} {{j.value}}
                    <td>
                 </span>
                 <ng-template #elsePart>
                     {{data[head]}}
                 <ng-template>    
               </ng-container>
             </tr>
</table>

Yash Rami
  • 2,276
  • 1
  • 10
  • 16
2
<table>
            <tr>
              <th *ngFor="let header of questionTitleArray">{{ header }} </th>
            </tr>
            <tr *ngFor="let data of surveyDataFromDB">
                    <ng-container *ngFor="let head of questionTitleArray">
                     <span *ngIf="checkType(data[head]) else elsePart">
                        <span *ngFor="let j of data[head] | keyvalue">
                           <td *ngIf="j.value==true">
                                {{j.key}} 
                           </td>
                        </span>
                     </span>
                     <ng-template #elsePart>
                         <td>{{data[head]}}</td> 
                     </ng-template>    
                   </ng-container>
                 </tr>
          </table>

in ts:

checkType(Ob:any)
 {
  if(typeof (Ob) === 'object')
  return true;
  else
  return false;
 }
Abhi
  • 614
  • 2
  • 12
  • 26
1

You can process before render on ui, and create a comma seprated string of skill key on the basics of its value

let list=[{"_id":"5de9f351baca28556c6a4b71","Name":"Harsha","Age":20,"Gender":"M","Skills":{"Java":"","Mule":true,"Angular":""}},{"_id":"5de9f358baca28556c6a4b72","Name":"Anji","Age":21,"Gender":"M","Skills":{"Java":"","Mule":true,"Angular":true}},{"_id":"5dea110297c2b65298b136e4","Name":"Abhi","Age":25,"Gender":"M","Skills":{"Java":"","Mule":true,"Angular":""}}];


let result = list.map((o) => { return {...o, 'Skills': Object.entries(o.Skills).reduce((acc, i) => acc+= i[1] ? `${i[0]},`: '' , '').slice(0, -1) } });

console.log(result)

Or You can checkout this demo may this helps you

In template you can use KeyValuePipe to iterate on object i.e skills and show skill key only when its value is not falsy

 <ng-container *ngFor="let entry of (data[head] | keyvalue); let last = last">
          {{  entry.value ? entry.key: '' }}
          <ng-container *ngIf="!last && entry.value">,</ng-container>
        </ng-container>
Saurabh Yadav
  • 3,303
  • 1
  • 10
  • 20
  • But what if we want to make your approach dynamic. There can be other name for the object which is currently referred as "Skills" or there can be multiple objects like "Skills" in the json. – Abhi Dec 06 '19 at 11:05
0

Okey so you want to extract all the skills that are true and place them in a new object. From what I know there is not built in function to do this, however I wrote some code to to exactly this


var skills = {
    Java: "",
    Mule: true,
    Angular: "",
    Cpp: true,
    Maja: false,
    NodeJs: true
}

let keys = Object.keys(skills);
let trueSkills = {};
keys.forEach(keyValue => {
    if (skills[keyValue] == true)
        trueSkills[keyValue] = true;
});

console.log(trueSkills); // These are all the true skills

I hope this helps

Hampfh
  • 54
  • 1
  • 7
0

Dealing with object keys based on their values can be complex in an Angular template. You could try to transform "Skills" into an array of strings. For example you could do it like this:

get formattedData() {
  // this.data would be your json object
  return this.data.map(i => ({...i, Skills: Object.keys(i.Skills).filter(j => i.Skills[j] === true)}))
}

This loops through every entry and transforms the skills object into an array with the skills.

This would return:

[
   {
      "_id":"5de9f351baca28556c6a4b71",
      "Name":"Harsha",
      "Age":20,
      "Gender":"M",
      "Skills":[
         "Mule"
      ]
   },
   {
      "_id":"5de9f358baca28556c6a4b72",
      "Name":"Anji",
      "Age":21,
      "Gender":"M",
      "Skills":[
         "Mule",
         "Angular"
      ]
   },
   {
      "_id":"5dea110297c2b65298b136e4",
      "Name":"Abhi",
      "Age":25,
      "Gender":"M",
      "Skills":[
         "Mule"
      ]
   }
]

A minimal working example: Stackblitz

I would strongly advise against this method though, if you have a lot of entries as it would take a long time.

Janis Jansen
  • 996
  • 1
  • 16
  • 36
0

Skills attribute in your data is an Object. ngFor can only be used with Iteratable. Therefore first you should convert Skills to an Array. It can be done as below.

  dataForView: any[];

  prepareDataForView() {

    this.dataForView = [...this.surveyDataFromDB];
    this.dataForView.map(item => {
      item.Skills = Object.keys(item.Skills).map(key => {
        if (item.Skills[key]) {
          return key;
        }
      });
    });
  }

And then you bind new array to View.

Find working Stackblitz Demo.

Sudarshana Dayananda
  • 5,165
  • 2
  • 23
  • 45
  • Instead of hard-coding the "item.Skills" can we have any dynamic approach for this? – Abhi Dec 06 '19 at 11:07