AngularJS - 按任何属性过滤

时间:2017-05-25 15:34:24

标签: angularjs search angular-filters object-comparison or-condition

我有一个应用程序,我用AngularJS显示项目列表。我正在尝试在此列表上轻松搜索,但它会搜索该项目中的所有内容。项目的一个例子:

{
    id: 283727893,
    name: 'Item A',
    parent: {
        id: 239495838,
        name: 'Item B'
    },
    user: 'User C'
}

在列表中我只写了根项的名称,因此parent.name没有出现。

问题

但是,如果我使用'Item B'的AngularJS过滤器进行搜索,它仍会出现,因为内部属性具有此字符串。

我尝试了什么

我已经放置了一个对象引用,如下所示(其中val是输入的文本):

vm.searchObj = {
    name: val,
    user: val
};

然后,在我的DOM上:

<li data-ng-repeat="[...] | filter: Ctrl.searchObj | orderBy: Ctrl.orderBy">
...
</li>

但是,这适用于条件AND,因此它仅显示nameuser两者都有val

我需要什么

我想获取一个输入文本并进行搜索以在给定的对象属性上复制此列表(复数形式)。

所以,在这个例子中,如果我写'Item A'或'User C'(或只是'A'或只是'C'等等),这个项目应该出现,但是如果我写'B'则不会出现,因为nameuser都没有这封信。

我需要它来获取引用对象,在本例中为Ctrl.searchObj,并检查对象的任何给定属性是否包含val到过滤对象的相同结构中。 / p>

当然,这应该适用于对象的更深层次,因此我可以按如下方式定义searchObj,如果过滤后的对象内部具有该结构,仍然可以获取:

vm.searchObj = {
    parent: {
        name: 'Item'
    }
};

在这种情况下,它应该显示其parent.name属性包含单词'Item'的项目。

如果您需要更多信息,请告诉我们!

谢谢!

3 个答案:

答案 0 :(得分:1)

如果我理解正确,搜索的对象(我们称之为target)是匹配的:

  • searchObjtarget在同一级别共享至少一个属性名称

  • target属性的值等于或包含searchObj属性的值

以下代码(包括您的修改)应该可以满足您的需求。我将留给您填写任何边缘案例(检查hasOwnProperty,比较不同类型等)。我认为这样的过滤应该只在必要时发生,比如当用户输入时。创建一个Angular过滤器可能过于昂贵,因为它在每个摘要周期运行:

function objectContains(searchObj, target) {
    for (var property in searchObj) {
        var searchVal = searchObj[property];
        var targetVal = target[property];

        if (isObject(searchVal) && isObject(targetVal)) {
            if(objectContains(searchVal, targetVal)){
                return true;
            }
        }

        if (
            !isObject(searchVal) && !isObject(targetVal) && 
            !isUndefinedOrNull(targetVal) && 
            !isUndefinedOrNull(searchVal) &&
            targetVal.toString().indexOf(searchVal.toString()) !== -1
        ) {
            return true;
        }
    }

    return false;
}

function isUndefinedOrNull(x) {
    return typeof x === "undefined" || x === null;
}

function isObject(x) {
    return typeof x === "object";
}

var filtered = list.filter(function(item) {
    return objectContains(searchObj, item);
});

答案 1 :(得分:0)

试试这种方式。在过滤器上使用<li data-ng-repeat="[...] | filter: Ctrl.searchObj:true | orderBy: Ctrl.orderBy"> ... </li> 属性可以获得您搜索的内容!

(project) ➜  project git:(feature/62-api-custom-image-categories) ✗ docker-compose up postgres
Starting project_postgres_1 ... 
Starting project_postgres_1 ... done
Attaching to project_postgres_1
postgres_1        | FATAL:  database files are incompatible with server
postgres_1        | DETAIL:  The data directory was initialized by PostgreSQL version 9.5, which is not compatible with this version 9.6.3.
project_postgres_1 exited with code 1

答案 2 :(得分:0)

所以,以Frank Modica的代码作为基础(谢谢),我在其compare函数中提出了一些版本,不仅要查找第一个属性,还要查看不是匹配,继续搜索。这是修改后的代码:

function objectContains(searchObj, target) {
    for (var property in searchObj) {
        var searchVal = searchObj[property];
        var targetVal = target[property];

        if (isObject(searchVal) && isObject(targetVal)) {
            if(objectContains(searchVal, targetVal)){
                return true;
            }
        }

        if (
            !isObject(searchVal) && !isObject(targetVal) && 
            !isUndefinedOrNull(targetVal) && 
            !isUndefinedOrNull(searchVal) &&
            targetVal.toString().indexOf(searchVal.toString()) !== -1
        ) {
            return true;
        }
    }

    return false;
}

如果它匹配,它返回true,因为它只需要一个匹配就可以找到它们。如果它不匹配,它会继续运行。

我们检查第二个条件不是这两个值的对象,因为当我们应用[object OBJECT]时它们转向toString(),因此它总是返回true。这样,如果它是一个对象,它将忽略它(不需要进行进一步的检查,因为我们已经在第一个if中完成了这个。)

谢谢Frank,因为我无法想出这个!

现在,它完美无缺!