การกรองตามคุณสมบัติของโมเดลเฉพาะหลายรายการใน AngularJS (ในความสัมพันธ์หรือ)


107

ดูตัวอย่างได้ที่นี่: http://docs.angularjs.org/api/ng.filter:filter

คุณสามารถค้นหาโดยใช้คุณสมบัติโทรศัพท์ใดก็ได้โดยใช้<input ng-model="search">และคุณสามารถค้นหาด้วยชื่อโดยใช้<input ng-model="search.name">และผลลัพธ์จะถูกกรองตามชื่ออย่างเหมาะสม (การพิมพ์หมายเลขโทรศัพท์ไม่ได้ผลลัพธ์ใด ๆ ตามที่คาดไว้)

สมมติว่าฉันมีโมเดลที่มีคุณสมบัติ "ชื่อ" คุณสมบัติ "โทรศัพท์" และคุณสมบัติ "ความลับ" ฉันจะกรองคุณสมบัติทั้ง "ชื่อ" และ "โทรศัพท์" ได้อย่างไรไม่ใช่คุณสมบัติ"ความลับ" เหรอ? ดังนั้นโดยพื้นฐานแล้วผู้ใช้สามารถพิมพ์ชื่อหรือหมายเลขโทรศัพท์และng-repeatตัวกรองจะถูกต้อง แต่แม้ว่าผู้ใช้จะพิมพ์ค่าที่เท่ากับส่วนหนึ่งของค่า "ความลับ" แต่ก็จะไม่ส่งคืนอะไรเลย

ขอบคุณ.


ฉันสับสนจริงๆว่าทำไมการแนบ "ชื่อ" วัตถุในช่องอินพุตng-model(การระบุsearch.nameในช่อง INPUT ng-model) จะส่งผลให้วัตถุที่ทำซ้ำถูกกรองโดยnameคุณสมบัติของพวกเขา? สำหรับฉันโดยสัญชาตญาณคุณควรจะกรองโดยเฉพาะได้nameโดยการระบุในng-repeatตัวกรองของคุณ: filter: friend.nameแทนที่จะเขียน `<input ng-model =" search.name "> ...
LazerSharks

คำตอบ:


171

นี่คือผู้พลัดถิ่น

เครื่องมือใหม่ที่มีรหัสที่สะอาดกว่าและโดยที่ทั้งข้อความค้นหาและรายการค้นหาไม่คำนึงถึงตัวพิมพ์เล็กและใหญ่

แนวคิดหลักคือสร้างฟังก์ชันตัวกรองเพื่อให้บรรลุวัตถุประสงค์นี้

จากเอกสารอย่างเป็นทางการ

ฟังก์ชัน: สามารถใช้ฟังก์ชันเพรดิเคตเพื่อเขียนตัวกรองโดยพลการ ฟังก์ชันนี้ถูกเรียกใช้สำหรับแต่ละองค์ประกอบของอาร์เรย์ ผลลัพธ์สุดท้ายคืออาร์เรย์ขององค์ประกอบเหล่านั้นที่เพรดิเคตส่งคืนเป็นจริง

<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
|| หมายถึงหรือ. คุณอาจต้องการอ่าน Javascript ซึ่งเป็นส่วนที่ดี
maxisam

1
พูดถึง || ลองแค่นี้ก็ใช้ได้: <tr ng-repeat = "สมาร์ทโฟนในสมาร์ทโฟน | ตัวกรอง: โทรศัพท์ || name"> ตัวกรองแรกมีความสำคัญเหนือกว่า
Jazzy

2
@kate angular.lowercase (item.brand) .indexOf ... โดยพื้นฐานแล้วทุกอย่างเป็นตัวพิมพ์เล็ก
maxisam

1
@maxisam. สตริงการสืบค้นต้องเป็นตัวพิมพ์เล็กเช่นกันเพื่อให้กรณีไม่ไวต่อการทำงานอย่างถูกต้อง นี่คือFork of you plunker ที่ไม่ไวต่อกรณีการทำงาน plnkr.co/edit/auz02bvWm1Vw4eItSa5J?p=preview ขอบคุณสำหรับตัวกรอง
Leopold Kristjansson

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}">

นี่คือPlunker

โปรดทราบ ... ตัวอย่างนี้ใช้งานได้ดีกับ AngularJS 1.1.5 แต่ก็ไม่เสมอไปใน 1.0.7 ในตัวอย่างนี้ 1.0.7 จะเริ่มต้นด้วยทุกสิ่งที่ถูกกรองออกจากนั้นจะทำงานเมื่อคุณเริ่มใช้อินพุต มันจะทำงานเหมือนว่าอินพุตมีค่าที่ไม่ตรงกันแม้ว่าจะเริ่มว่างเปล่าก็ตาม หากคุณต้องการใช้งานรุ่นที่เสถียรต่อไปให้ลองใช้กับสถานการณ์ของคุณ แต่บางสถานการณ์อาจต้องการใช้โซลูชันของ @ maxisam จนกว่าจะมีการเผยแพร่ 1.2.0


26
การดูผู้รวบรวมของคุณว่าจะได้เอฟเฟกต์ที่ต้องการอย่างไรหากคุณมีช่องค้นหาเพียงช่องเดียว นี่คือความท้าทาย ... ส่วนหรือ
silvster27

2
คำตอบนี้คือทองคำ แต่ไม่ตอบคำถาม
Cyril CHAPON

1
คุณจะทำอย่างไรกับช่องป้อนข้อมูลเดียวดังตัวอย่างในตารางนี้: datatables.net
Flash

คุณจะได้รับจำนวนข้อมูลที่กรองใน Plunker ที่โพสต์อย่างไร
Muhammad Zeeshan Tahir

5

ฉันได้แรงบันดาลใจจากคำตอบของ @ maxisam และสร้างฟังก์ชันการเรียงลำดับของฉันเองและฉันก็จะแบ่งปันมัน (เพราะฉันเบื่อ)

สถานการณ์ ฉันต้องการกรองรถหลายคัน คุณสมบัติที่เลือกเพื่อกรอง ได้แก่ ชื่อปีราคาและกม. ราคาทรัพย์สินและกม. เป็นตัวเลข (ดังนั้นการใช้งาน.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



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

2

แนวทางตรงไปตรงมาโดยใช้ filterBy ใน angularJs

สำหรับการทำงาน plnkr ตามลิงค์นี้

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

สิ่งนี้ใช้คุณสมบัติเดียวเป็นพิเศษเพื่อค้นหาหลายคอลัมน์ แต่ไม่ใช่ทั้งหมด

<!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'
      }
      ];
  })

})();

ข้อเสียคือเพิ่มปลั๊กอินของบุคคลที่สามอีกหนึ่งตัว สิ่งสำคัญในการโทรออก
mix3d

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

นี่คือการค้นหาที่คำนึงถึงตัวพิมพ์เล็กและใหญ่ซึ่งแยกการค้นหาของคุณออกเป็นคำที่ต้องการค้นหาในแต่ละรุ่นด้วยเช่นกัน เฉพาะเมื่อพบช่องว่างเท่านั้นที่จะพยายามแยกคำค้นหาออกเป็นอาร์เรย์แล้วค้นหาแต่ละคำ

จะคืนค่าจริงหากทุกคำเป็นอย่างน้อยในหนึ่งในโมเดล

$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

ขอบคุณสำหรับการตอบกลับของคุณ rick ฉันไม่รู้ว่าใครโหวตให้ แต่ฉันสามารถลงคะแนนสำรองได้ อย่างไรก็ตามในตัวอย่างนั้นจะคล้ายกับลิงค์ที่ฉันให้ไว้อย่างไรซึ่งมีช่องป้อนข้อมูลการค้นหาและเมื่อพิมพ์จะกรองออก เธอเป็นผู้โพสต์ต้นกำเนิดของฉันที่ใครบางคนโหวตลงเช่นกัน: stackoverflow.com/questions/42421941/angular-custom-search
Flash

1
ฉันได้อัปเดต plnkr เพื่อแสดงว่าตัวกรองกล่องข้อความทำงานอย่างไร สังเกตว่ามันกรองข้อความบางส่วนตามที่คาดไว้อย่างไร ฉันเชื่อว่านี่ใกล้เคียงกับตัวอย่างที่เชื่อมโยงของคุณมากกว่า หากคุณต้องการตัวกรองหลายตัว (สำหรับชิ้นข้อมูลที่แยกจากกัน) นั่นเป็นคำถามที่แตกต่างกัน
Rick

@Rick ผมขอขอบคุณที่คุณใส่ลงไปในเวลาเช่นนี้ในขณะที่ฉันกำลังพยายามที่จะคิดออกเองกับตัวกรองเพียง 2 ng-repeatคุณสมบัติมากกว่าคุณสมบัติทั้งหมดที่อยู่ภายในวัตถุถูกทำซ้ำผ่าน อย่างไรก็ตามตัวอย่างของคุณดูซับซ้อนเล็กน้อย: มีวิธีใดบ้างที่คุณสามารถต้มมันลงได้? ฉันรู้ว่าคำถามคือการค้นหาช่องค้นหาเดียวที่สามารถกรองคุณสมบัติที่เลือกเท่านั้น ในตัวอย่างของคุณดูเหมือนว่าเรากำลังกรองชื่อตามมูลค่าหรือตัวเลข แต่ไม่ใช่ทั้งสองอย่าง หากฉันเข้าใจตัวอย่างของคุณไม่ถูกต้องโปรดแจ้งให้เราทราบ!
twknab
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.