Angular2 applying Pipe after data is received

老子叫甜甜 提交于 2020-01-24 05:39:18

问题


I have an Object that is used to manage the data received from the back end. It is initiated with all the fields as display: false, and if I receive that specific field from the server, I will eventually change it to true.

filterGroups (initial):

export let filterGroups: any = {
    genericFilters: {
        iboId: {
            'display': false,
            'template': ''
        },
        iboCode: {
            'display': false,
            'template': 'text/iboCode'
        },
        iboName: {
            'display': false,
            'template': 'text_input_iboName'
        },
        iboSurname: {
            'display': false,
            'template': 'text_input_iboSurname'
        },
        iboRank: {
            'display': false,
            'template': 'select/multi_iboRank',
        },
        iboEmail: {
            'display': false,
            'template': 'text_input_iboEmail'
        },
        iboNewsletter: {
            'display': false,
            'template': 'select/simple_iboNewsletter',
        },
    },
    orderFilters: {
        iboTotalOrders: {
            'display': false,
            'template': 'compound/iboTotalOrders',
        }
    },
    peFilters: {
        iboTotalPE: {
            'display': false,
            'template': 'checkbox/iboTotalPE',
        }
    },
};

In my template, I want to have as many div as filter groups. In this case we have 3 filter groups: genericFilters, orderFilters and peFilters.

This Object will be modified as soon as I receive data from the server (which I call in my constructor).

And so, my filterGroups will look like this after I have received the data from my async call.

filterGroups (after async call):

export let filterGroups: any = {
    genericFilters: {
        iboId: {
            'display': true,
            'template': ''
        },
        iboCode: {
            'display': true,
            'template': 'text/iboCode'
        },
        iboName: {
            'display': true,
            'template': 'text_input_iboName'
        },
        iboSurname: {
            'display': true,
            'template': 'text_input_iboSurname'
        },
        iboRank: {
            'display': false,
            'template': 'select/multi_iboRank',
        },
        iboEmail: {
            'display': true,
            'template': 'text_input_iboEmail'
        },
        iboNewsletter: {
            'display': false,
            'template': 'select/simple_iboNewsletter',
        },
    },
    orderFilters: {
        iboTotalOrders: {
            'display': true,
            'template': 'compound/iboTotalOrders',
        }
    },
    peFilters: {
        iboTotalPE: {
            'display': false,
            'template': 'checkbox/iboTotalPE',
        }
    },
};

Now, in my template I have this:

Template (HTML):

<div *ngFor="let group of filterGroups | keysCheckDisplay">
    <div>
        <h4>{{group.key}}</h4>
    </div>
</div>

And, obviusly, here is my @Pipe.

@Pipe:

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

@Pipe({name: 'keysCheckDisplay'})
export class KeysCheckDisplayPipe implements PipeTransform {
    transform(value, args: string[]): any {
        let keys = [];
        for (let key in value) {
            if (!isNullOrUndefined(value[key])) {
                let display = false;
                for (let keyChild in value[key]) {
                    if (!isNullOrUndefined(value[key][keyChild]) && value[key][keyChild]['display'] === true) {
                        display = true;
                        break;
                    }
                }
                if (display === true) {
                    keys.push({key: key, value: value[key]});
                }
            }
        }
        return keys;
    }
}

In this @Pipe as you can see I do several things:

  • Loop through the filterGroups object
  • Check for each group within the object if exists a child with display: true.

The functionality:

I want this @Pipe to loop through my Objectand return me the 'filter groups' that have at least 1 element with display: true.

The Issue:

The @Pipe is getting the first version of the filterGroups object, and is ignoring the fact that the object changes as soon as I receive the data from the server.

The @Pipe works fine if I modify the initial values of the filterGroups object.

What I have tried:

  • Research, research, research
  • I changed the @Pipe to inpure, but I hate this solution because of awful performance and also it entered an infinite loop.
  • I have also tried this approach: *ngFor="let group of filterGroups | async | keysCheckDisplay". But it throwed the following error:

Error: InvalidPipeArgument: '[object Object]' for pipe 'AsyncPipe'

Possible solutions?

  • Modify the @Pipe?

  • Modify the initial object?

  • Create a second @Pipe to loop through the first Pipe's result?

I hope it was detailed and clear, if not, please don't esitate to comment asking for more details and I will gladly update the post.

Thank you beforehand!


回答1:


A pure pipe is only called when the data changes. This means when "data" is a new object instance. If only the content of the object is modified, then Angular change detection won't recognize it as change and won't call the pipe.

Possible approaches

  • make the pipe impure: usually quite a burden for performance
  • copy the object like:
var tmp = this.data; this.data = {}; Object.assign(this.data, tmp);
  • add an additional parameter to the pipe and update the parameter value
*ngFor="let item of data | myPipe:counter"
// updated `data`
// this.counter++;


来源:https://stackoverflow.com/questions/43181283/angular2-applying-pipe-after-data-is-received

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!