在Angular App中处理过滤值的更优雅的方法 [英] A More Elegant Way to Handle Filtering Values in Angular App

查看:98
本文介绍了在Angular App中处理过滤值的更优雅的方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Angular 2应用程序中多次重新加载表格显示中的数据时,我遇到了一些问题.我正在考虑的主要问题与以下事实有关:在初始加载组件时,我正在作为网络请求发送一系列过滤器的数据.

I am running into some issues with data in a tabular display reloading several times in my Angular 2 app. I'm thinking the main issue with that is related to the fact that, upon initial component loading, I am sending data for a series of filters along as network requests.

基本上,我们使用的是Mongo/Mongoose功能,该功能使我们可以在发布请求的对象主体中传递键/值对,然后该键/值对将根据传入的值返回经过过滤的数据集.这段代码如下:

Basically we're making use of a Mongo/Mongoose feature that lets us pass key/value pairs in the object body of a post request, which then returns a filtered dataset based on those passed-in values. This code looks like this:

private processType(name: string, value: any, body)
{
    if (this.body[name] && !value) {
            delete this.body[name];
        } else {
            this.body[name] = { $in: value };
        }
} 

所有操作均按预期进行.但是,在我当前的实现中感觉不太理想的是,在初始组件加载时,我正在传递每个滤波器的所有可能值的数组.用户可以从那里通过UI过滤器列表更改传递和过滤的内容.我要在初始组件加载时传递每个过滤器的可能值的整个数组,因为如果我传递一个空数组,则NOTHING将匹配.但是,似乎应该有更好的方法来处理我的初始请求.

All that's working as expected. However, what feels less than ideal in my current implementation is that on initial component load I am passing an array of all possible values for each of those filters. And from there a user can change what's passed and filtered-on via a UI filter list. I am passing the entire array of possible values for each filter on initial component load, because if I pass in an empty array NOTHING will match. However, it seems like there should be a better way to handle my initial request.

理想情况下,我希望我的初始请求实际上是不对任何内容进行初始过滤",而不是像我现在所做的那样对所有内容进行初始过滤".我现在已经用这种方式完成了,因为处理初始加载时的条件以及在用户删除过滤器或所有过滤器的情况下都很难处理.现在,在任何一种情况下,我都将再次传递所有可能值的数组.我所拥有的作品奏效了,但似乎并不尽如人意.既然所有这些都作为对象传递到了post请求的主体中,那么有没有办法我可以删除该对象而不是传递具有所有值的数组的对象?

I'd ideally like my initial request to be, effectively, "don't initially filter on anything", rather than "filter initially on everything", as I'm doing now. I've done it this way for now, because it's a little tricky to handle both the condition on initial load, AND in a situation where a user removes a filter, or all filters. Right now, in either of those scenarios, I'm just passing in the array of all possible values again. What I have works, but it doesn't seem as elegant as it could be. Since this is all being passed as an object in the body of the post request, is there a way I could just delete the object rather than passing an object with arrays of all values?

这是我其余相关代码的样子:

This is what the rest of my relevant code looks like:

public initLanguageFilterOptions(): void
{
    this.languageFilterOptions = new FilterOptions([
        { value: 'English', toString: () => 'English' },
        { value: 'Spanish', toString: () => 'Spanish' },
        { value: 'Mandarin', toString: () => 'Mandarin' }
    ]);

    let arr = [];

    // Update array when filter selection is made
    arr.push(this.languageFilterOptions.addEventListener(FilterOptions.CHANGE_EVENT, () => this.sendLangSelections(true)));

    // Update array when filter options are loaded from URL parameters
    arr.push(this.languageFilterOptions.addEventListener(FilterOptions.URL_LOAD_EVENT, () => this.sendLangSelections(true)));

    // Clean up after component is no longer used
    this.addEventListener('ngOnDestroy', function ()
    {
        arr.forEach(s => s()); // Remove all listeners
        return true;
    }.bind(this));

}

/**
* Handles the emitting of the selected values to the API
*/
private sendLangSelections(languageFilterOptions) {
    const origLangArray = ['English', 'Spanish', 'Mandarin'];
    if (languageFilterOptions)
        {
            let selectionsArray = this.languageFilterOptions.selection;
            let values = selectionsArray.map((a) => { return a.value; });
            if (values && values.length > 0)
                {
                    this.sendLanguage.emit(values);
                }
            else if (values && values.length < 1)
                {
                    this.sendLanguage.emit(origLangArray);
                }
        }
}

这是我对我们的Mongo/Mongoose/Node后端的API调用,如下所示:

This is what my API call to our Mongo/Mongoose/Node backend looks like:

// A POST request to work with observables
public obsPost(strReq, page, pagesize, body, sort?) {
    const headers = new Headers({ 'Content-Type': 'application/json' });
    const options = new RequestOptions({ headers: this.headers });
    return this.http.post
    (`${API.URL}/${API.VER}${strReq}?apikey=${API.KEY}&page=${page}&pagesize=${pagesize}`,
    body, options)
        .map((res: Response) => res.json())
        .catch(this.filterErrorHandler);
}
    filterErrorHandler(error: Response) {
    console.error(error);
    return Observable.throw(error.json().error || 'Server error');
}

推荐答案

要实现此目的,需要在通过{ $in: value }传递值时添加更多条件逻辑.由于弹出的错误是由于{ $in: value }的格式问题引起的,所以关键是确保仅在有要传递的值时才触发此错误.

To make this work, it's a matter of adding some more conditional logic to when a value gets passed via { $in: value }. Since the errors that were popping up were because of formatting issues with { $in: value }, the key was to make sure this is triggered only when there is a value to be passed.

因此,最后,要使它起作用-不必传递所有可能的值的数组,这既不是一种优雅的方法,也不是高性能的解决方案-我改变了这一点:

So, in the end, to get this to work - without having to pass in an array of all possible values, which was not an elegant nor performant solution - I changed this:

private processType(name: string, value: any, body)
{
    if (this.body[name] && !value) {
            delete this.body[name];
        } else {
            this.body[name] = { $in: value };
        }
}

...对此:

private processType(name: string, value: any, body)
{
    if (this.body[name] && !value || this.body[name] && value.length < 1) {
            delete this.body[name];
        } else if (value) {
            this.body[name] = { $in: value };
        }
}

这基本上是确保在触发{$ in:value}时,至少有一个值的数组可用.

What this does is basically ensure that an array of at least one value is available when the { $in: value } is triggered.

唯一需要进行的其他更改是涉及当用户取消选择所有值时发出的更改.我是这样处理的:

The only other change necessary was the one involving what gets emitted when a user has de-selected all values. I handled that, this way:

private sendLangSelections(languageFilterOptions) {
    const origLangArray = ['English', 'Spanish', 'Mandarin'];
    if (languageFilterOptions)
        {
            let selectionsArray = this.languageFilterOptions.selection;
            let values = selectionsArray.map((a) => { return a.value; });
            if (values && values.length > 0)
                {
                    this.sendLanguage.emit(values);
                }
            else if (values && values.length < 1)
                {
                    this.sendLanguage.emit(this.obj = undefined);
                }
        }
}

这篇关于在Angular App中处理过滤值的更优雅的方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆