AngularJSの複数の特定のモデルプロパティによるフィルタリング(OR関係)


107

こちらの例をご覧ください:http : //docs.angularjs.org/api/ng.filter : filter

を使用して任意の電話のプロパティで<input ng-model="search">検索でき、を使用して名前だけで検索できます。<input ng-model="search.name">結果は名前で適切にフィルタリングされます(電話番号を入力しても期待どおりの結果は返されません)。

のは、どのように私はによってフィルタリングについては行くだろう、私は「名前」プロパティを持つモデル、「電話」プロパティ、および「秘密の」性質を持っているとしましょう、両方の「名前」と「電話」の特性とない「秘密」プロパティ?つまり、本質的にユーザーは名前または電話番号を入力でき、ng-repeatは正しくフィルタリングしますが、ユーザーが「秘密」の値の一部と等しい値を入力しても、何も返されません。

ありがとう。


"名前"オブジェクトを入力フィールドng-modelsearch.nameINPUTフィールドで指定)にアタッチするng-modelと、オブジェクトが繰り返され、そのnameプロパティによってフィルターされるのはなぜですか?Ieは直感的に私には、あなただけのことで、具体的フィルタすることができるはずですname、あなたに指定することによってng-repeatフィルタ:filter: friend.name代わりに``書き込み<入力NG-モデル=「search.name」>の、...
LazerSharks

回答:


171

これがプランカーです

よりクリーンなコードを備えた新しいプランカーで、クエリと検索リストの項目の両方で大文字と小文字が区別されません

主なアイデアは、この目的を達成するためのフィルター関数を作成することです。

公式ドキュメントから

function:述語関数を使用して、任意のフィルターを作成できます。関数は、配列の各要素に対して呼び出されます。最終結果は、述語がtrueを返した要素の配列です。

<input ng-model="query">

<tr ng-repeat="smartphone in smartphones | filter: search "> 

$scope.search = function(item) {
    if (!$scope.query || (item.brand.toLowerCase().indexOf($scope.query) != -1) || (item.model.toLowerCase().indexOf($scope.query.toLowerCase()) != -1) ){
        return true;
    }
    return false;
};

更新

一部の人々は、実際の世界のパフォーマンスに懸念を抱いているかもしれませんが、それは正しいです。

現実の世界では、おそらくこのようなフィルターをコントローラーから実行します。

これは、その方法を示す詳細な投稿です。

つまり、ng-change新しい検索の変更を監視するための入力に追加します

次に、フィルター機能をトリガーします。


1
こんにちは@maxisam、二重の縦線が何を意味するか説明してくれませんか?私は、この行を読んでどのように本当にわからない:item.brand.indexOf($scope.query)!=-1 || item.model.indexOf($scope.query)!=-1)
LazerSharks

15
|| ORを意味します。あなたはJavascript、良い部分を読みたいかもしれません。
maxisam 2013

1
||と言えば、これを試してみたところ機能しました:<tr ng-repeat = "スマートフォンのスマートフォン|フィルター:電話||名前">。最初のフィルターが優先されます。
Jazzy

2
@kate angular.lowercase(item.brand).indexOf ...基本的に、すべてを小文字にします
maxisam

1
@maxisam。大文字と小文字を区別しないようにするには、クエリ文字列も小文字にする必要があります。以下は、大文字小文字を区別せずにフォークをフォークしたものですplnkr.co/edit/auz02bvWm1Vw4eItSa5J?p=preview フィルターをありがとう。
Leopold Kristjansson 2015

78

APIリファレンスで説明されているように、オブジェクトをパラメーターとしてフィルター式に渡すことができます。このオブジェクトは、次のように、必要なプロパティを選択的に適用できます。

<input ng-model="search.name">
<input ng-model="search.phone">
<input ng-model="search.secret">
<tr ng-repeat="user in users | filter:{name: search.name, phone: search.phone}">

これがプランカーです

お見事です...この例はAngularJS 1.1.5でうまく機能しますが、1.0.7では常にうまくいくとは限りません。この例では、1.0.7はすべてを除外して初期化し、入力の使用を開始すると機能します。入力が空白で始まっていても、入力に一致しない値があるように動作します。安定したリリースを維持したい場合は、状況に応じて試してください。ただし、一部のシナリオでは、1.2.0がリリースされるまで@maxisamのソリューションを使用する場合があります。


26
検索ボックスが1つしかない場合に、プランカーを調べて、望ましい効果がどのように達成されるかを確認します。これが課題です... ORの部分。
silvster27 2014年

2
この答えは金です​​が、質問には答えません。
Cyril CHAPON、2015年

1
次の表の例のように、入力フィールドを1つだけにしてどうしますか。datatables.net
Flash

投稿されたPlunkerでフィルタリングされたデータの数をどのように取得しますか?
ムハンマドジーシャンタヒル

5

@maxisamの答えからインスピレーションを得て、独自のソート関数を作成しましたが、共有したいと思いました(うんざりしました)。

一連の車をフィルタリングしたい状況。フィルタリングするために選択したプロパティは、名前、年、価格、kmです。不動産価格とkmは数値です(したがっての使用.toString)。大文字を制御したい(したがって.toLowerCase)。また、フィルタークエリを別の単語に分割できるようにしたいとします(たとえば、フィルター2006 Acuraを指定すると、2006と年が一致し、Acuraが名前と一致します)。

フィルターに渡す関数

        var attrs = [car.name.toLowerCase(), car.year, car.price.toString(), car.km.toString()],
            filters = $scope.tableOpts.filter.toLowerCase().split(' '),
            isStringInArray = function (string, array){
                for (var j=0;j<array.length;j++){
                    if (array[j].indexOf(string)!==-1){return true;}
                }
                return false;
            };

        for (var i=0;i<filters.length;i++){
            if (!isStringInArray(filters[i], attrs)){return false;}
        }
        return true;
    };

1
ビュー側で、このフィルターをAngularでどのように呼び出すかを示していただけますか?
twknab 2017



2

ここには良い解決策がたくさんありますが、私はこれで別のルートに行くことをお勧めします。検索が最も重要であり、ビューで「シークレット」プロパティがまったく使用されていない場合。これに対する私のアプローチは、組み込みの角度フィルターをすべての利点とともに使用し、モデルを新しいオブジェクトの配列にマップすることです。

質問の例:

$scope.people = members.map(function(member) { 
                              return { 
                                name: member.name, 
                                phone: member.phone
                              }});

これで、htmlでは、通常のフィルターを使用して、これらの両方のプロパティを検索します。

<div ng-repeat="member in people | filter: searchString">

1
私は小さなオブジェクトを処理するためのこのソリューションが好きですが、ネストされたものがたくさんある大きなオブジェクトのセットがある場合、すべてをマッピングすると混乱を招く/エラーが発生しやすくなります。ただし、基本的なニーズに対する優れたソリューションとしては+1ですが、これはそれほど複雑ではなく、すべてではなくいくつかのプロパティのみをフィルタリングすることを望みます。:/ ...将来的には、Angularがこの種のフィルタの組み込み機能を追加する可能性があります...
twknab '27

2

angularJsでfilterByを使用するかなり単純なアプローチ

plnkrを機能させるには、このリンクをたどってください

http://plnkr.co/edit/US6xE4h0gD5CEYV0aMDf?p=preview

これは、すべてではなく、複数の列を検索するために1つのプロパティを特別に使用しています。

<!DOCTYPE html>
<html ng-app="myApp">

  <head>
    <script data-require="angular.js@1.4.1" data-semver="1.4.1" src="https://code.angularjs.org/1.4.1/angular.js"></script>
    <script data-require="angular-filter@0.5.2" data-semver="0.5.2" src="https://cdnjs.cloudflare.com/ajax/libs/angular-filter/0.5.2/angular-filter.js"></script>
    <link rel="stylesheet" href="style.css" />
    <script src="script.js"></script>
  </head>

  <body ng-controller="myCtrl as vm">
  <input type="text" placeholder="enter your search text" ng-model="vm.searchText" />
   <table>
     <tr ng-repeat="row in vm.tableData | filterBy: ['col1','col2']: vm.searchText">
       <td>{{row.col1}}</td>
       <td>{{row.col2}}</td>
       <td>{{row.col3}}</td>
     </tr>
   </table>
   <p>This will show filter from <b>two columns</b> only(col1 and col2) . Not from all. Whatever columns you add into filter array they
   will be searched. all columns will be used by default if you use <b>filter: vm.searchText</b></p>
  </body>
</html>

コントローラ

// Code goes here
(function(){

  var myApp = angular.module('myApp',['angular.filter']);

  myApp.controller('myCtrl', function($scope){
    var vm= this;
    vm.x = 20;

    vm.tableData = [
      {
        col1: 'Ashok',
        col2: 'Tewatia',
        col3: '12'
      },{
        col1: 'Babita',
        col2: 'Malik',
        col3: '34'
      },{
        col1: 'Dinesh',
        col2: 'Tewatia',
        col3: '56'
      },{
        col1: 'Sabita',
        col2: 'Malik',
        col3: '78'
      }
      ];
  })

})();

欠点は、サードパーティのプラグインが1つ追加されることです。呼び出すことが重要です。
mix3d 2018年

2

私はこれを簡単に解決しました:

<div ng-repeat="Object in List | filter: (FilterObj.FilterProperty1 ? {'ObjectProperty1': FilterObj.FilterProperty1} : '') | filter:(FilterObj.FilterProperty2 ? {'ObjectProperty2': FilterObj.FilterProperty2} : '')">

1

http://plnkr.co/edit/A2IG03FLYnEYMpZ5RxEm?p=preview

これも大文字と小文字を区別する検索で、検索を単語に分割して、各モデルでも検索します。スペースが見つかった場合にのみ、クエリを配列に分割し、各単語を検索します。

すべての単語が少なくともモデルの1つにある場合、trueを返します。

$scope.songSearch = function (row) {
    var query = angular.lowercase($scope.query);
    if (query.indexOf(" ") > 0) {
        query_array = query.split(" ");
        search_result = false;
        for (x in query_array) {
            query = query_array[x];
            if (angular.lowercase(row.model1).indexOf(query || '') !== -1 || angular.lowercase(row.model2).indexOf(query || '') !== -1 || angular.lowercase(row.model3).indexOf(query || '') !== -1){
                search_result = true;
            } else {
                search_result = false;
                break;
            }
        }
        return search_result;
    } else {
        return (angular.lowercase(row.model1).indexOf(query || '') !== -1 || angular.lowercase(row.model2).indexOf(query || '') !== -1 || angular.lowercase(row.model3).indexOf(query || '') !== -1);
    }
};

1

フィルターは、フィールドを持つJavaScriptオブジェクトにすることができ、次のような式を持つことができます。

ng-repeat= 'item in list | filter :{property:value}'

0

可能な限りシンプルにしておくのが好きです。インターナショナルでグループ化し、すべての列でフィルタリングし、各グループの数を表示し、アイテムが存在しない場合はグループを非表示にする必要がありました。

さらに、このような単純なもののためだけにカスタムフィルターを追加したくありませんでした。

        <tbody>
            <tr ng-show="fusa.length > 0"><td colspan="8"><h3>USA ({{fusa.length}})</h3></td></tr>
            <tr ng-repeat="t in fusa = (usa = (vm.assignmentLookups | filter: {isInternational: false}) | filter: vm.searchResultText)">
                <td>{{$index + 1}}</td>
                <td ng-bind-html="vm.highlight(t.title, vm.searchResultText)"></td>
                <td ng-bind-html="vm.highlight(t.genericName, vm.searchResultText)"></td>
                <td ng-bind-html="vm.highlight(t.mechanismsOfAction, vm.searchResultText)"></td>
                <td ng-bind-html="vm.highlight(t.diseaseStateIndication, vm.searchResultText)"></td>
                <td ng-bind-html="vm.highlight(t.assignedTo, vm.searchResultText)"></td>
                <td ng-bind-html="t.lastPublished | date:'medium'"></td>
            </tr>
        </tbody>
        <tbody>
            <tr ng-show="fint.length > 0"><td colspan="8"><h3>International ({{fint.length}})</h3></td></tr>
            <tr ng-repeat="t in fint = (int = (vm.assignmentLookups | filter: {isInternational: true}) | filter: vm.searchResultText)">
                <td>{{$index + 1}}</td>
                <td ng-bind-html="vm.highlight(t.title, vm.searchResultText)"></td>
                <td ng-bind-html="vm.highlight(t.genericName, vm.searchResultText)"></td>
                <td ng-bind-html="vm.highlight(t.mechanismsOfAction, vm.searchResultText)"></td>
                <td ng-bind-html="vm.highlight(t.diseaseStateIndication, vm.searchResultText)"></td>
                <td ng-bind-html="vm.highlight(t.assignedTo, vm.searchResultText)"></td>
                <td ng-bind-html="t.lastPublished | date:'medium'"></td>
            </tr>
        </tbody>

0

私は非常に遅いかもしれませんが、これは私がやったことです。とても一般的なフィルターを作りました。

angular.module('app.filters').filter('fieldFilter', function() {
        return function(input, clause, fields) {
            var out = [];
            if (clause && clause.query && clause.query.length > 0) {
                clause.query = String(clause.query).toLowerCase();
                angular.forEach(input, function(cp) {
                    for (var i = 0; i < fields.length; i++) {
                        var haystack = String(cp[fields[i]]).toLowerCase();
                        if (haystack.indexOf(clause.query) > -1) {
                            out.push(cp);
                            break;
                        }
                    }
                })
            } else {
                angular.forEach(input, function(cp) {
                    out.push(cp);
                })
            }
            return out;
        }

    })

次に、このように使用します

<tr ng-repeat-start="dvs in devices |  fieldFilter:search:['name','device_id']"></tr>

あなたの検索ボックスは

<input ng-model="search.query" class="form-control material-text-input" type="text">

ここで、nameとdevice_idはdvsのプロパティです


-1

オブジェクトに対するクイックフィルターを必要とするユーザーのための簡単なソリューションを次に示します。

<select>
  <option ng-repeat="card in deck.Cards | filter: {Type: 'Face'}">{{card.Name}}</option>
</select>

配列フィルターを使用すると、フィルターしようとしているオブジェクトを模倣できます。上記の場合、次のクラスは問題なく機能します。

var card = function(name, type) {
  var _name = name;
  var _type = type;

  return {
    Name: _name,
    Type: _type
  };
};

デッキは次のようになります。

var deck = function() {
  var _cards = [new card('Jack', 'Face'),
                new card('7', 'Numeral')];

  return {
    Cards: _cards
  };
};

また、オブジェクトの複数のプロパティをフィルタリングする場合は、フィールド名をカンマで区切ります。

<select>
  <option ng-repeat="card in deck.Cards | filter: {Type: 'Face', Name: 'Jack'}">{{card.Name}}</option>
</select>

編集:これは、単一および複数のプロパティフィルターの例を提供する作業中のplnkrです。

http://embed.plnkr.co/i0wCx6l1WPYljk57SXzV/


このタイプの検索をどのように実装しますか?この表の例では、単語の一部を入力し、スペースキーを押し、列に別の単語の一部を入力しても、それに応じてフィルタリングされます。datatables.net
Flash

質問に適切に対応しなかった場合を除き、投稿がダウングレードされた理由がわかりません。コードは、正しく適用すると機能します。
リック

返信ありがとうrick誰が反対票を投じたのかわかりませんが、私は先に進み、反対票を投じることができます。ただし、その例では、検索入力フィールドがあり、入力時にフィルターで除外される、私が提供したリンクにあるものとどのように類似していますか。彼女は私の元の投稿で、someouneも反対票を投じていました: stackoverflow.com/questions/42421941/angular-custom-search
Flash

1
テキストボックスフィルターがどのように機能するかを示すために、plnkrを更新しました。期待どおりに部分的なテキストをフィルターする方法に注意してください。これはあなたのリンクされた例に近いと思います。複数のフィルターが必要な場合(個別のデータ片に対して)、それは別の問題です。
リック

@Rick私は、この例に時間を費やして本当に感謝しています。私は現在、を介して繰り返されるオブジェクト内のすべてのプロパティではなく、2つのプロパティのみをフィルターに掛けようとしているためng-repeatです。しかし、あなたの例は少し複雑に見えます:それを煮詰める方法はありますか?質問は基本的に、選択したプロパティのみをフィルターできる単一の検索フィールドを探していることを知っています。あなたの例では、顔の値の名前または数値のいずれかをフィルタリングしていますが、両方はフィルタリングしていないようです。あなたの例を正しく理解していない場合は、私に知らせてください!
twknab 2017
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.