AngularJS निर्देश में चेकबॉक्स पर क्लिक का जवाब कैसे दें?


79

मेरे पास एक AngularJS निर्देश है जो निम्नलिखित टेम्पलेट में संस्थाओं के संग्रह को प्रस्तुत करता है:

<table class="table">
  <thead>
    <tr>
      <th><input type="checkbox" ng-click="selectAll()"></th>
      <th>Title</th>
    </tr>
  </thead>
  <tbody>
    <tr ng-repeat="e in entities">
      <td><input type="checkbox" name="selected" ng-click="updateSelection($event, e.id)"></td>
      <td>{{e.title}}</td>
    </tr>
  </tbody>
</table>

जैसा कि आप देख सकते हैं, यह वह जगह है <table>जहाँ प्रत्येक पंक्ति को अपने स्वयं के चेकबॉक्स के साथ व्यक्तिगत रूप से चुना जा सकता है, या सभी पंक्तियों को एक बार में स्थित मास्टर चेकबॉक्स के साथ चुना जा सकता है <thead>। बहुत बढ़िया यूआई।

सबसे अच्छा तरीका क्या है:

  • एक पंक्ति का चयन करें (यानी जब चेकबॉक्स की जाँच की जाती है, तो चयनित इकाई की आईडी को आंतरिक सरणी में जोड़ें, और <tr>अपने चयनित राज्य को प्रतिबिंबित करने के लिए इकाई वाले CSS वर्ग को जोड़ें )?
  • एक बार में सभी पंक्तियों का चयन करें? (यानी सभी पंक्तियों के लिए पहले से वर्णित क्रियाएँ करें <table>)

मेरा वर्तमान कार्यान्वयन मेरे निर्देशन में एक कस्टम नियंत्रक जोड़ना है:

controller: function($scope) {

    // Array of currently selected IDs.
    var selected = $scope.selected = [];

    // Update the selection when a checkbox is clicked.
    $scope.updateSelection = function($event, id) {

        var checkbox = $event.target;
        var action = (checkbox.checked ? 'add' : 'remove');
        if (action == 'add' & selected.indexOf(id) == -1) selected.push(id);
        if (action == 'remove' && selected.indexOf(id) != -1) selected.splice(selected.indexOf(id), 1);

        // Highlight selected row. HOW??
        // $(checkbox).parents('tr').addClass('selected_row', checkbox.checked);
    };

    // Check (or uncheck) all checkboxes.
    $scope.selectAll = function() {
        // Iterate on all checkboxes and call updateSelection() on them??
    };
}

विशेष रूप से, मुझे आश्चर्य है:

  • क्या ऊपर दिया गया कोड किसी कंट्रोलर का है या इसे किसी linkफंक्शन में जाना चाहिए ?
  • यह देखते हुए कि jQuery आवश्यक रूप से मौजूद नहीं है (AngularJS को इसकी आवश्यकता नहीं है), DOM ट्रैवर्सल करने का सबसे अच्छा तरीका क्या है? JQuery के बिना, मुझे <tr>एक दिए गए चेकबॉक्स के माता-पिता का चयन करने, या टेम्पलेट में सभी चेकबॉक्स का चयन करने में मुश्किल समय आ रहा है ।
  • पासिंग $eventके लिए updateSelection()बहुत ही सुंदर प्रतीत नहीं होता। क्या केवल क्लिक किए गए तत्व के राज्य (चेक / अनियंत्रित) को पुनः प्राप्त करने का एक बेहतर तरीका नहीं है?

धन्यवाद।

जवाबों:


122

इस तरह से मैं इस तरह का सामान कर रहा हूं। कोणीय एक अनिवार्य एक के बजाय डोम की घोषणात्मक हेरफेर के पक्ष में है (कम से कम इस तरह से मैं इसके साथ खेल रहा हूं)।

मार्कअप

<table class="table">
  <thead>
    <tr>
      <th>
        <input type="checkbox" 
          ng-click="selectAll($event)"
          ng-checked="isSelectedAll()">
      </th>
      <th>Title</th>
    </tr>
  </thead>
  <tbody>
    <tr ng-repeat="e in entities" ng-class="getSelectedClass(e)">
      <td>
        <input type="checkbox" name="selected"
          ng-checked="isSelected(e.id)"
          ng-click="updateSelection($event, e.id)">
      </td>
      <td>{{e.title}}</td>
    </tr>
  </tbody>
</table>

और कंट्रोलर में

var updateSelected = function(action, id) {
  if (action === 'add' && $scope.selected.indexOf(id) === -1) {
    $scope.selected.push(id);
  }
  if (action === 'remove' && $scope.selected.indexOf(id) !== -1) {
    $scope.selected.splice($scope.selected.indexOf(id), 1);
  }
};

$scope.updateSelection = function($event, id) {
  var checkbox = $event.target;
  var action = (checkbox.checked ? 'add' : 'remove');
  updateSelected(action, id);
};

$scope.selectAll = function($event) {
  var checkbox = $event.target;
  var action = (checkbox.checked ? 'add' : 'remove');
  for ( var i = 0; i < $scope.entities.length; i++) {
    var entity = $scope.entities[i];
    updateSelected(action, entity.id);
  }
};

$scope.getSelectedClass = function(entity) {
  return $scope.isSelected(entity.id) ? 'selected' : '';
};

$scope.isSelected = function(id) {
  return $scope.selected.indexOf(id) >= 0;
};

//something extra I couldn't resist adding :)
$scope.isSelectedAll = function() {
  return $scope.selected.length === $scope.entities.length;
};

EDIT : getSelectedClass()पूरी इकाई की अपेक्षा करता है लेकिन इसे केवल इकाई की आईडी के साथ बुलाया जा रहा था, जिसे अब सुधारा गया है


धन्यवाद, Liviu! वह काम करता है और इससे मदद मिली। और आपके लिए धन्यवाद, मैंने ngCheckedनिर्देश के बारे में सीखा है । (मेरा एकमात्र खेद यह है कि हम इस कोड को थोड़ा कम नहीं कर सकते हैं।)
AngularChef

1
इसे क्रिया के रूप में मत समझो, इसे चिंताओं के पृथक्करण के संदर्भ में सोचो। आपके डेटा मॉडल को उसके प्रस्तुत करने के तरीके के बारे में नहीं पता होना चाहिए। कंट्रोलर में याद रखें कि tr या td's का कोई उल्लेख नहीं है। अधिकांश में यह चेकबॉक्स होता है, लेकिन इसे भी फैक्टर आउट किया जा सकता है। आप हमेशा अपने नियंत्रक को ले सकते हैं और इसे दूसरे टेम्पलेट पर लागू कर सकते हैं;)
लिविउ टी।

इस सवाल और जवाब के लिए धन्यवाद। मैं इस दृष्टिकोण के दक्षता संबंधी निहितार्थों को जानने के लिए उत्सुक था इसलिए मैंने यह प्लंकर बनाया: plnkr.co/edit/T5aZO3s5DzSnbrLELveG मैंने देखा कि हर बार जब मैं किसी एक आइटम का चयन करता हूं, तो iselected को 6 बार (प्रत्येक पुनरावर्तक आइटम के लिए दो बार) कहा जाता है। किसी भी विचार क्यों यह प्रत्येक के लिए दो बार हो रहा है? किसी को भी पृष्ठ पर 100+ पुनरावर्तक आइटम फेंकने और मोबाइल पर चलाने के बारे में चिंतित हैं? शायद एक समस्या नहीं है ...
एरोनियस

@ एरोनियस यदि आप आइसोलेटेड फ़ंक्शन में एक ब्रेकप्वाइंट जोड़ते हैं और ताज़ा करते हैं तो आप देखेंगे कि निर्देश की सामग्री को पार्स और निष्पादित करने से पहले इसे कॉल किया जाता है। मुझे लगता है कि चूंकि यह एक निर्देश है जो सभी बाध्य कार्यों को प्रतिस्थापित करता है, इसलिए दो बार कहा जाता है
Liviu T.

क्या केवल चयनित चेकबॉक्स को जानने के लिए कोई विधि है?
सना जोसेफ

35

मैं चेकबॉक्स के साथ काम करते समय ngModel और ngChange निर्देशों का उपयोग करना पसंद करता हूं । ngModel आपको चेकबॉक्स के चेक / अनियंत्रित अवस्था को इकाई पर एक संपत्ति में बाँधने की अनुमति देता है:

<input type="checkbox" ng-model="entity.isChecked">

जब भी उपयोगकर्ता चेकबॉक्स को चेक या अनचेक करता है तो entity.isCheckedमान भी बदल जाएगा।

अगर यह सब आप की जरूरत है तो आप भी जरूरत नहीं है ngClick या ngChange निर्देश। चूंकि आपके पास "चेक ऑल" चेकबॉक्स है, इसलिए आपको स्पष्ट रूप से संपत्ति के मूल्य को निर्धारित करने की तुलना में अधिक करने की आवश्यकता है जब कोई चेकबॉक्स चेक करता है।

एक चेकबॉक्स के साथ ngModel का उपयोग करते समय, चेक किए गए और अनियंत्रित घटनाओं से निपटने के लिए ngClick के बजाय ngChange का उपयोग करना सबसे अच्छा है। ngChange सिर्फ इस तरह के परिदृश्य के लिए बनाया गया है। यह डेटा-बाइंडिंग के लिए ngModelController का उपयोग करता है (यह ngModelController के $viewChangeListenersसरणी के लिए एक श्रोता जोड़ता है । इस सरणी में श्रोता मॉडल मान सेट होने के बाद कॉल करते हैं, इस समस्या से बचते हुए )।

<input type="checkbox" ng-model="entity.isChecked" ng-change="selectEntity()">

... और नियंत्रक में ...

var model = {};
$scope.model = model;

// This property is bound to the checkbox in the table header
model.allItemsSelected = false;

// Fired when an entity in the table is checked
$scope.selectEntity = function () {
    // If any entity is not checked, then uncheck the "allItemsSelected" checkbox
    for (var i = 0; i < model.entities.length; i++) {
        if (!model.entities[i].isChecked) {
            model.allItemsSelected = false;
            return;
        }
    }

    // ... otherwise ensure that the "allItemsSelected" checkbox is checked
    model.allItemsSelected = true;
};

इसी तरह, हेडर में "चेक ऑल" चेकबॉक्स:

<th>
    <input type="checkbox" ng-model="model.allItemsSelected" ng-change="selectAll()">
</th>

... तथा ...

// Fired when the checkbox in the table header is checked
$scope.selectAll = function () {
    // Loop through all the entities and set their isChecked property
    for (var i = 0; i < model.entities.length; i++) {
        model.entities[i].isChecked = model.allItemsSelected;
    }
};

सीएसएस

सबसे अच्छा तरीका क्या है ... <tr>अपने चयनित राज्य को प्रतिबिंबित करने के लिए इकाई वाले सीएसएस वर्ग को जोड़ें ?

यदि आप डेटा-बाइंडिंग के लिए ngModel दृष्टिकोण का उपयोग करते हैं, तो आपको केवल इकाई गुण में परिवर्तन करने पर क्लास में गतिशील रूप से जोड़ने या निकालने के लिए ngClass निर्देश जोड़ने की आवश्यकता है।<tr>

<tr ng-repeat="entity in model.entities" ng-class="{selected: entity.isChecked}">

पूरा प्लंकर यहां देखें ।


allItemsSelected ध्वज शुरुआत में झूठा करने के लिए सेट किया गया है, तो यह कैसे सही पर सेट किया जाता है जब चयन करें सभी चेक बॉक्स पर क्लिक करें। क्या आप समझा सकते हैं?
user2514925

11

मेरे लिए लिवियू का जवाब बेहद मददगार था। आशा है कि यह खराब रूप नहीं है, लेकिन मैंने एक ऐसी बेला बनाई है जो भविष्य में किसी और की मदद कर सकती है।

आवश्यक दो महत्वपूर्ण टुकड़े हैं:

    $scope.entities = [{
    "title": "foo",
    "id": 1
}, {
    "title": "bar",
    "id": 2
}, {
    "title": "baz",
    "id": 3
}];
$scope.selected = [];

1
कोणीय डॉक्स चेक के सभी भाग के लिए एक सरल उत्तर है। docs.angularjs.org/api/ng.directive:ngChecked । जो कुछ भी चेक किया गया है उसे इकट्ठा करना मैं यह जानने की कोशिश कर रहा हूं।
हेडन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.