1

Following is a JSON data:

{
  "tagFrequency": [
    {
      "value": "At",
      "count": 1,
      "tagId": 249
    },
    {
      "value": "ipsum",
      "count": 1,
      "tagId": 251
    },
    {
      "value": "molestie",
      "count": 1,
      "tagId": 199
    }
  ]
}

I am populating this data on UI in a table having column names as word, frequency for above JSON object attributes value and count respectively. Third column tag-name is being extracted with GET API call using tagId attribute. Following is my HTML code:

<table>
  <thead>
    <tr>
      <th (click)="sort('value')">{{ 'word' | translate }}</th>
      <th (click)="sort('tagId')">{{ 'tag-name' | translate }}</th>
      <th (click)="sort('count')">{{ 'frequency' | translate }}</th>
      <th></th>
    </tr>
  </thead>
  <tbody>
    <tr *ngFor="let frequency of (frequencies | TagFrequencySorter: key: direction); let i = index;">
      <td>{{ frequency.value }}</td>
      <td>{{ processedTagNames[i] }}</td>
      <td>{{ frequency.count }}</td>
    </tr>
  </tbody>
</table>

I want to sort these columns value and count, which is working with "TagFrequencySorter" pipe. But I also want to sort tagNames array data using a same pipe in same for loop. I can make required changes in pipe, but all I want is to pass these both arrays somehow to this pipe.

Following is a sort function I write in component:

sort(value: string) {
    this.direction = this.direction * (-1);
    if(value === "tagId") {
      this.key = "";
    }
    else {
      this.key = value;
    }
  }

And here is pipe implementation:

export class TagFrequencySorter implements PipeTransform {
  transform(tagFrequencies: any, key: string, direction: number): any[] {
    if (key !== '' && tagFrequencies !== null) {
      console.log(key)
      tagFrequencies.sort(
        (a: any, b: any) => {
          let propertyA: number|string = this.getProperty(a, key);
          let propertyB: number|string = this.getProperty(b, key);

          if (propertyA < propertyB) {
            return -1 * direction;
          } else if (propertyA > propertyB) {
            return 1 * direction;
          } else {
            return 0;
          }
        }
      );
    }
    return tagFrequencies;
  }

  private getProperty(value: { [key: string]: any}, key: string): number|string {
    if (value === null || typeof value !== 'object') {
      return undefined;
    }
    let keys: string[] = key.split('.');
    let result: any = value[keys.shift()];
    for (let newkey of keys) {
      if (result === null) {
        return undefined;
      }
      result = result[newkey];
    }
    return result;
  }
}

Can someone help me to resolve this issue?

Nilakshi Naphade
  • 1,055
  • 4
  • 14
  • 30

1 Answers1

0

One way to achieve this is to pre-process your tagNames array by passing the custom pipe as a provider to your component

constructor(private _tagFrequencySorterPipe: TagFrequencySorter){ }

get processedTagNames(){
    return this._tagFrequencySorterPipe(this.tagNames, this.key, this.direction);    
}

Your HTML will then look like this:

<tr *ngFor="let frequency of (frequencies | TagFrequencySorter: key: direction); let i = index;">
    <td>{{ frequency.value }}</td>
    <td>{{ processedTagNames[i] }}</td>
    <td>{{ frequency.count }}</td>
</tr>

See this question for more information about Pipe dependency injection in Angular2


Another option could be to merge the two arrays together using a separate pipe, and then amend your existing sorting pipe to work on a merged array:

<tr *ngFor="let item of (frequencies | merge: tagNames |TagFrequencySorter: key: direction); let i = index;">
    <td>{{ item.frequency.value }}</td>
    <td>{{ item.tagName }}</td>
    <td>{{ item.frequency.count }}</td>
</tr>
Community
  • 1
  • 1
Christopher Moore
  • 3,071
  • 4
  • 30
  • 46
  • Thanks for the response. I used the first approach of preprocessing the tagNmaes. But how can I invoke this processedName method using onClick() on header name. I want to sort using onClick on respective header name, like how I am doing it for other two headers. Please see my updated HTML code above – Nilakshi Naphade Mar 19 '17 at 11:48
  • In this case, it sounds like going for the merging option will be the simplest option for you – Christopher Moore Mar 20 '17 at 10:00