मैं एक कोणीय फिल्टर के साथ डेटा समूह कैसे कर सकता हूं?


136

मेरे पास खिलाड़ियों की एक सूची है जो प्रत्येक समूह से संबंधित है। मैं प्रति समूह उपयोगकर्ताओं को सूचीबद्ध करने के लिए एक फिल्टर का उपयोग कैसे कर सकता हूं?

[{name: 'Gene', team: 'team alpha'},
 {name: 'George', team: 'team beta'},
 {name: 'Steve', team: 'team gamma'},
 {name: 'Paula', team: 'team beta'},
 {name: 'Scruath of the 5th sector', team: 'team gamma'}];

मैं इस परिणाम की तलाश में हूँ:

  • टीम अल्फा
    • जीन
  • टीम बीटा
    • जॉर्ज
    • पाउला
  • टीम गामा
    • स्टीव
    • 5 वें क्षेत्र के स्क्रूथ

जवाबों:


182

आप कोणीय.फिल्टर मॉड्यूल के ग्रुपबी का उपयोग कर सकते हैं ।
तो आप ऐसा कुछ कर सकते हैं:

जे एस:

$scope.players = [
  {name: 'Gene', team: 'alpha'},
  {name: 'George', team: 'beta'},
  {name: 'Steve', team: 'gamma'},
  {name: 'Paula', team: 'beta'},
  {name: 'Scruath', team: 'gamma'}
];

HTML:

<ul ng-repeat="(key, value) in players | groupBy: 'team'">
  Group name: {{ key }}
  <li ng-repeat="player in value">
    player: {{ player.name }} 
  </li>
</ul>

परिणाम:
समूह का नाम: अल्फा
* खिलाड़ी: जीन
समूह का नाम: बीटा
* खिलाड़ी: जॉर्ज
* खिलाड़ी: पाउला
समूह का नाम: गामा
* खिलाड़ी: स्टीव
* खिलाड़ी: स्क्रूथ

अद्यतन: jsbin का उपयोग करने के लिए बुनियादी आवश्यकताओं को याद रखें angular.filter, विशेष रूप से ध्यान दें कि आपको इसे अपने मॉड्यूल की निर्भरता में जोड़ना होगा:

(1) आप 4 विभिन्न तरीकों का उपयोग करके कोणीय-फ़िल्टर स्थापित कर सकते हैं:

  1. क्लोन और इस भंडार का निर्माण
  2. Bower के माध्यम से: $ bower चलाकर अपने टर्मिनल से कोणीय-फ़िल्टर स्थापित करें
  3. npm के माध्यम से: $ npm चलाकर अपने टर्मिनल से कोणीय-फ़िल्टर स्थापित करें
  4. cdnjs http://www.cdnjs.com/lbooks/angular-filter के माध्यम से

(2) कोणीय में ही शामिल करने के बाद, अपने index.html में कोणीय-फ़िल्टर.जेएस (या कोणीय-फ़िल्टर.मिन.जेएस) शामिल करें।

(3) अपने मुख्य मॉड्यूल की निर्भरता सूची में 'कोणीय.फिल्टर' जोड़ें।


महान उदाहरण है। हालाँकि, कुंजी समूह नाम लौटाती है न कि वास्तविक कुंजी ... हम इसे कैसे हल कर सकते हैं?
JohnAndrews

7
angular.filterमॉड्यूल को शामिल करना न भूलें ।
puce

1
आप ग्रुप-बाय @erfling, PTAL के साथ आदेश का उपयोग कर सकते हैं: github.com/a8m/angular-filter/wiki/…
a8m

1
ओह वाह। धन्यवाद। मैं नेस्टेड लूप को उस तरह से बाहरी को प्रभावित करने के लिए आदेश देने की उम्मीद नहीं करता था। यह वास्तव में उपयोगी है। +1
16

1
@ मैं भी मैं keyवस्तु के रूप में करना चाहते हैं के लिए देख रहा हूँ । आपकी ओर से कोई भी भाग्य
सुपर कूल

25

ऊपर दिए गए स्वीकृत उत्तरों के अलावा मैंने अंडरस्कोर.जेएस लाइब्रेरी का उपयोग करके एक सामान्य 'ग्रुपबाय' फिल्टर बनाया।

JSFiddle (अद्यतन): http://jsfiddle.net/TD7t3/

फ़िल्टर

app.filter('groupBy', function() {
    return _.memoize(function(items, field) {
            return _.groupBy(items, field);
        }
    );
});

'मेमोइज़' कॉल को नोट करें। यह अंडरस्कोर विधि फ़ंक्शन के परिणाम को कैश करती है और हर बार फिल्टर अभिव्यक्ति का मूल्यांकन करने से कोणीय को रोकती है, इस प्रकार कोणीय को पाचन पुनरावृत्तियों की सीमा तक पहुंचने से रोकती है।

एचटीएमएल

<ul>
    <li ng-repeat="(team, players) in teamPlayers | groupBy:'team'">
        {{team}}
        <ul>
            <li ng-repeat="player in players">
                {{player.name}}
            </li>
        </ul>
    </li>
</ul>

हम अपने 'GroupBy' फ़िल्टर को TeamPlayers स्कोप वैरिएबल पर, 'टीम' प्रॉपर्टी पर लागू करते हैं। हमारा एनजी-रिपीट (कुंजी, मान []) का एक संयोजन प्राप्त करता है जिसे हम अपने निम्नलिखित पुनरावृत्तियों में उपयोग कर सकते हैं।

11 जून 2014 को अपडेट करें मैंने कुंजी के रूप में अभिव्यक्तियों के उपयोग के लिए फ़िल्टर द्वारा समूह का विस्तार किया (जैसे नेस्टेड चर)। कोणीय पार्स सेवा इसके लिए काफी उपयोगी है:

फ़िल्टर (अभिव्यक्ति समर्थन के साथ)

app.filter('groupBy', function($parse) {
    return _.memoize(function(items, field) {
        var getter = $parse(field);
        return _.groupBy(items, function(item) {
            return getter(item);
        });
    });
});

नियंत्रक (नेस्टेड ऑब्जेक्ट्स के साथ)

app.controller('homeCtrl', function($scope) {
    var teamAlpha = {name: 'team alpha'};
    var teamBeta = {name: 'team beta'};
    var teamGamma = {name: 'team gamma'};

    $scope.teamPlayers = [{name: 'Gene', team: teamAlpha},
                      {name: 'George', team: teamBeta},
                      {name: 'Steve', team: teamGamma},
                      {name: 'Paula', team: teamBeta},
                      {name: 'Scruath of the 5th sector', team: teamGamma}];
});

HTML (क्रमबद्ध अभिव्यक्ति के साथ)

<li ng-repeat="(team, players) in teamPlayers | groupBy:'team.name'">
    {{team}}
    <ul>
        <li ng-repeat="player in players">
            {{player.name}}
        </li>
    </ul>
</li>

JSFiddle: http://jsfiddle.net/k7fgB/2/


आप सही हैं, फिडल लिंक को अपडेट कर दिया गया है। मुझे सूचित करने के लिए धन्यवाद।
क्रिस जू

3
यह वास्तव में बहुत साफ है! कोड की कम से कम राशि।
बेनी बोटेमा

3
इस पर ध्यान देने वाली एक बात - डिफ़ॉल्ट रूप से संस्मरण पहले परम (अर्थात 'आइटम') को कैश कुंजी के रूप में उपयोग करता है - इसलिए यदि आप इसे एक अलग 'फ़ील्ड' के साथ समान 'आइटम' पास करते हैं तो यह एक ही कैश्ड मान लौटाएगा। समाधान का स्वागत है।
टॉम कार्वर

मुझे लगता है कि आप इसे प्राप्त करने के लिए $ आईडी मूल्य का उपयोग कर सकते हैं: $ id (आइटम) द्वारा आइटम ट्रैक में आइटम
Caspar Harmer

2
कौन से "उत्तर स्वीकार किए जाते हैं"? स्टैक ओवरफ्लो पर, केवल एक ही स्वीकृत उत्तर हो सकता है।
सेबस्टियन मच

19

पहले एक फिल्टर का उपयोग करके एक लूप करें जो केवल अद्वितीय टीमों को लौटाएगा, और फिर एक नेस्टेड लूप जो वर्तमान टीम के सभी खिलाड़ियों को लौटाता है:

http://jsfiddle.net/plantface/L6cQN/

एचटीएमएल:

<div ng-app ng-controller="Main">
    <div ng-repeat="playerPerTeam in playersToFilter() | filter:filterTeams">
        <b>{{playerPerTeam.team}}</b>
        <li ng-repeat="player in players | filter:{team: playerPerTeam.team}">{{player.name}}</li>        
    </div>
</div>

स्क्रिप्ट:

function Main($scope) {
    $scope.players = [{name: 'Gene', team: 'team alpha'},
                    {name: 'George', team: 'team beta'},
                    {name: 'Steve', team: 'team gamma'},
                    {name: 'Paula', team: 'team beta'},
                    {name: 'Scruath of the 5th sector', team: 'team gamma'}];

    var indexedTeams = [];

    // this will reset the list of indexed teams each time the list is rendered again
    $scope.playersToFilter = function() {
        indexedTeams = [];
        return $scope.players;
    }

    $scope.filterTeams = function(player) {
        var teamIsNew = indexedTeams.indexOf(player.team) == -1;
        if (teamIsNew) {
            indexedTeams.push(player.team);
        }
        return teamIsNew;
    }
}

बहुत आसन। एक अच्छा @Plantface।
जेफ येट्स

बस शानदार। लेकिन क्या होगा अगर मैं क्लिक पर $ स्कोप के लिए एक नई वस्तु को धक्का देना चाहता हूं। के रूप में यू एक समारोह के माध्यम से पाशन कर रहे हैं यह जोड़ा जाएगा?
सुपर कूल

16

मैंने मूल रूप से प्लांटफेस के उत्तर का उपयोग किया था, लेकिन मुझे यह पसंद नहीं आया कि मेरे विचार में वाक्यविन्यास कैसे दिखाई देता है।

मैंने डेटा को पोस्ट-प्रोसेस करने और अद्वितीय टीमों पर एक सूची वापस करने के लिए $ q.defer का उपयोग करने के लिए इसे फिर से काम किया , जो बाद में फ़िल्टर के रूप में उपयोग करता है।

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

राय

<ul>
  <li ng-repeat="team in teams">{{team}}
    <ul>
      <li ng-repeat="player in players | filter: {team: team}">{{player.name}}</li> 
    </ul>
  </li>
</ul>

नियंत्रक

app.controller('MainCtrl', function($scope, $q) {

  $scope.players = []; // omitted from SO for brevity

  // create a deferred object to be resolved later
  var teamsDeferred = $q.defer();

  // return a promise. The promise says, "I promise that I'll give you your
  // data as soon as I have it (which is when I am resolved)".
  $scope.teams = teamsDeferred.promise;

  // create a list of unique teams. unique() definition omitted from SO for brevity
  var uniqueTeams = unique($scope.players, 'team');

  // resolve the deferred object with the unique teams
  // this will trigger an update on the view
  teamsDeferred.resolve(uniqueTeams);

});

1
यह जवाब AngularJS> 1.1 के साथ काम नहीं कर रहा है क्योंकि प्रोमिस किए गए सरणियों के लिए अब और तैयार नहीं किए गए हैं। आव्रजन नोट
बेनी बोटेमा

6
इस समाधान में वादे की कोई आवश्यकता नहीं है, क्योंकि आप कुछ भी अतुल्यकालिक नहीं कर रहे हैं। इस स्थिति में, आप बस उस चरण ( jsFiddle ) को छोड़ सकते हैं ।
बजे बेनी बोटेमा

11

दोनों उत्तर अच्छे थे इसलिए मैंने उन्हें एक निर्देश में स्थानांतरित कर दिया ताकि यह पुन: प्रयोज्य हो और एक दूसरे दायरे के चर को परिभाषित नहीं करना पड़े।

यदि आप इसे लागू देखना चाहते हैं तो यहाँ फ़ाइडल है

नीचे निर्देश है:

var uniqueItems = function (data, key) {
    var result = [];
    for (var i = 0; i < data.length; i++) {
        var value = data[i][key];
        if (result.indexOf(value) == -1) {
            result.push(value);
        }
    }
    return result;
};

myApp.filter('groupBy',
            function () {
                return function (collection, key) {
                    if (collection === null) return;
                    return uniqueItems(collection, key);
        };
    });

फिर इसका उपयोग निम्नानुसार किया जा सकता है:

<div ng-repeat="team in players|groupBy:'team'">
    <b>{{team}}</b>
    <li ng-repeat="player in players | filter: {team: team}">{{player.name}}</li>        
</div>

11

अपडेट करें

मैंने शुरू में यह जवाब लिखा था क्योंकि एरियल एम द्वारा सुझाए गए समाधान के पुराने संस्करण को जब अन्य $filterएस के साथ संयुक्त किया गया था, तो " इन्फाइट $ डाइजेस्ट लूप एरर " ( infdig) । सौभाग्य से इस मुद्दे को कोणीय.फिल्टर के नवीनतम संस्करण में हल किया गया है ।

मैंने निम्नलिखित कार्यान्वयन का सुझाव दिया था , उस मुद्दे पर नहीं था :

angular.module("sbrpr.filters", [])
.filter('groupBy', function () {
  var results={};
    return function (data, key) {
        if (!(data && key)) return;
        var result;
        if(!this.$id){
            result={};
        }else{
            var scopeId = this.$id;
            if(!results[scopeId]){
                results[scopeId]={};
                this.$on("$destroy", function() {
                    delete results[scopeId];
                });
            }
            result = results[scopeId];
        }

        for(var groupKey in result)
          result[groupKey].splice(0,result[groupKey].length);

        for (var i=0; i<data.length; i++) {
            if (!result[data[i][key]])
                result[data[i][key]]=[];
            result[data[i][key]].push(data[i]);
        }

        var keys = Object.keys(result);
        for(var k=0; k<keys.length; k++){
          if(result[keys[k]].length===0)
            delete result[keys[k]];
        }
        return result;
    };
});

हालांकि, यह कार्यान्वयन केवल कोणीय 1.3 से पहले के संस्करणों के साथ काम करेगा। (मैं सभी समाधानों के साथ काम करने वाले समाधान प्रदान करते हुए जल्द ही इस उत्तर को अपडेट करूंगा।)

मैंने वास्तव में उन चरणों के बारे में एक पोस्ट लिखी है जो मैंने इसे विकसित करने के लिए उठाए हैं $filter, जो समस्याएं आईं और जो चीजें मैंने इससे सीखीं


हाय @Josep, नए angular-filterसंस्करण - 0.5.0 पर एक नज़र डालें , कोई और अपवाद नहीं है। groupByकिसी भी फिल्टर के साथ श्रृंखला हो सकती है। इसके अलावा, आप महान परीक्षण मामलों को सफलतापूर्वक समाप्त कर रहे हैं - यहाँ एक प्लंकर धन्यवाद है।
a8m

1
@Josep में अंक 1.3 1.3
amcdnl

2

यदि आप कई कॉलमों के अनुसार समूह बनाना चाहते हैं, तो स्वीकृत उत्तर के अलावा आप इसका उपयोग कर सकते हैं :

<ul ng-repeat="(key, value) in players | groupBy: '[team,name]'">

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.