【问题标题】:Angular checkboxes not independent角度复选框不独立
【发布时间】:2017-10-19 22:30:32
【问题描述】:

我遇到了一些angular checkboxes 的特殊问题

我在单独的 divs 中创建它们,每个 checkbox 具有不同的 id,它们将根据来自数据库的一组数据被选中或取消选中。

我觉得这个最好用代码来理解:

html:

 <div class="form-group row">
     <label for="field_publication" class="col-md-2 form-control-label">Drug/s:</label>
       <div class="btn btn-sm btn-primary">
        <input type="checkbox" id="check1" ng-checked="drugTypeIds.indexOf(1)!==-1" ng-click="updateSelection(1, publication, 'antimalarials')"> Antimalarial
         </div>
         <div class="btn btn-sm btn-primary">
         <input type="checkbox" id="check2" ng-checked="drugTypeIds.indexOf(2)!==-1" ng-click="updateSelection(2, publication, 'antibiotics')"> Antibiotic
        </div>
       <div class="btn btn-sm btn-primary">
      <input type="checkbox" id="check3" ng-checked="drugTypeIds.indexOf(3)!==-1" ng-click="updateSelection(3, publication, 'antiretrovirals')"> Antiretroviral
      </div>
       <div class="btn btn-sm btn-primary">
       <input type="checkbox" id="check4" ng-checked="drugTypeIds.indexOf(4)!==-1" ng-click="updateSelection(4, publication, 'antidiabetics')"> Antidiabetic
       </div>
       <div class="btn btn-sm btn-primary">
       <input type="checkbox" id="check5" ng-checked="drugTypeIds.indexOf(6)!==-1" ng-click="updateSelection(6, publication, 'antituberculosis')"> Antituberculosis
       </div>
       <div class="btn btn-sm btn-primary">
       <input type="checkbox" id="check6" ng-checked="drugTypeIds.indexOf(5)!==-1" ng-click="updateSelection(5, publication, 'maternal and reproductive')"> Maternal Health
       </div>
</div>

所以,ng-checked 告诉代码在数据上传到表单后在我创建的数组中查找对象的 id,这发生在控制器中,用这个方法:

$scope.drugTypeIds = null;
    $scope.checkboxes = function (publicationDrugTypes) {
                    $scope.drugTypeIds = [];
                    publicationDrugTypes.forEach(function (typeDrug) {
                        $scope.drugTypeIds.push(typeDrug.id);
                    });
                };

所以,这里drugTypeIds 被初始化为一个空值,直到数据被加载,一旦数据被加载,它将转到publication 对象的变量publicationDrugTypes 并将其作为参数传递给复选框功能:

 $scope.checkboxes(formDTO.publication.publicationDrugTypes);

现在为 null 的数组 (drugTypeIds) 将获取 publicationDrugTypes 变量中的 id 值,HTML 代码将选中正确的框。到这里它工作得很好

现在,如果用户想从publication 中添加/删除drugTypes,HTML 将使用控制器中的updateSelection() 代码:

$scope.updateSelection = function (drugTypeId, publication, type){
                if ($scope.drugTypeIds.indexOf(drugTypeId)!==-1){
                    publication.publicationDrugTypes.splice(publication.publicationDrugTypes.indexOf($scope.publicationDrugTypes[drugTypeId-1]),1);
                    $scope.drugTypeIds.splice($scope.drugTypeIds.indexOf(drugTypeId));
                }
                else {
                publication.publicationDrugTypes.push({id:$scope.publicationDrugTypes[drugTypeId-1].id,name:$scope.publicationDrugTypes[drugTypeId-1].name}); $scope.drugTypeIds.push(drugTypeId);
            };

此代码需要新的drugType 的 id,我们将要添加它的publication 和类型(此变量当前未使用)

所以,现在它检查 id 是否在之前的列表中,如果是,则删除它,如果不是,则添加它。

添加在前端和数据库中都可以正常工作,在拼接时我得到几个 checkboxes 同时取消选中自己,我不知道为什么因为它们都有不同的 id、不同的条件和没有附加特定型号。

我已经修改了jsfiddle 中的代码,该错误只有在您第一次运行时才能重现(与我的应用程序中每次都会发生的情况不同),您需要先单击按钮,以便从第一种方法将运行。尝试取消选中Antidiabetic checkbox时会出现错误

【问题讨论】:

  • 这段代码不仅第一次出现问题。如果您多次选中复选框,然后取消选中它们,您会看到一个非常奇怪的行为
  • 我刚刚分叉了小提琴,如果您使用帖子上的链接,代码现在会出现错误,正如我在解释中所预期的那样,但我无法重现任何其他奇怪的行为
  • 仍然困扰着我很多。你能解释一下你的用例是什么吗?我明天会为您更改此示例,以使其正常工作并对其进行清理

标签: javascript angularjs html checkbox


【解决方案1】:

您在管理插入/删除和元素检查时遇到了一些问题。我简化了一点逻辑。 这里你的例子应该做你正在寻找的:

var app = angular.module('CountApp',[]);

app.controller('CountCtrl',function($scope){
  $scope.drugTypeIds = [];
  $scope.publicationDrugTypes = [
  	{ id:1, name:'Antimalarial' },
    { id:4, name:'Antidiabetic' },
    { id:3, name:'Antiretroviral' }
  ];
  $scope.publication = {id:1, publicationDrugTypes:$scope.publicationDrugTypes};
	
  $scope.isPublicationChecked = function (id) {
  	return findElementInPublication(id) > -1;
  };

  $scope.updateSelection = function (drugTypeId, type){
    var elementIndex = findElementInPublication(drugTypeId);
    if (elementIndex === -1) {
    	$scope.publicationDrugTypes.push({ id: drugTypeId, name: type });
    }
    else {
    	$scope.publicationDrugTypes.splice(elementIndex, 1);
    }
  	console.log($scope.publication);
  };
  
  function findElementInPublication(id) {
  	return $scope.publicationDrugTypes.findIndex(function(el) { return el.id === id; });
  }
  
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div data-ng-app="CountApp" data-ng-controller="CountCtrl">
  <div class="btn btn-sm btn-primary">
    <input type="checkbox" id="check1" ng-checked="isPublicationChecked(1)" ng-click="updateSelection(1, 'antimalarials')"> Antimalarial
  </div>
  <div class="btn btn-sm btn-primary">
    <input type="checkbox" id="check2" ng-checked="isPublicationChecked(2)" ng-click="updateSelection(2, 'antibiotics')"> Antibiotic
  </div>
  <div class="btn btn-sm btn-primary">
    <input type="checkbox" id="check3" ng-checked="isPublicationChecked(3)" ng-click="updateSelection(3, 'antiretrovirals')"> Antiretroviral
  </div>
  <div class="btn btn-sm btn-primary">
    <input type="checkbox" id="check4" ng-checked="isPublicationChecked(4)" ng-click="updateSelection(4, 'antidiabetics')"> Antidiabetic
  </div>
  <div class="btn btn-sm btn-primary">
    <input type="checkbox" id="check5" ng-checked="isPublicationChecked(6)" ng-click="updateSelection(6, 'antituberculosis')"> Antituberculosis
  </div>
  <div class="btn btn-sm btn-primary">
    <input type="checkbox" id="check6" ng-checked="isPublicationChecked(5)" ng-click="updateSelection(5, 'maternal and reproductive')"> Maternal Health
  </div>

</div>

jsfiddle:https://jsfiddle.net/4vnuL4eL/16/

【讨论】:

  • 英雄!周一早上的开始!我不得不稍微调整一下以使其适应来自数据库的数据,但它就像一个魅力!谢谢
【解决方案2】:

部分问题在于 HTML 选项中的 ID 与控制器代码中的 ID 不对应。例如,HTML 将选项 2“Antibiotic”列为 ID 值为 2——但在控制器代码中,将 2 的 id 分配给“Antidiabetic”。

至少,^ 是选中错误复选框的原因。

另外,我建议从 HTML 中的手动列表中删除选项,并将数据仅放在控制器中,然后让 ngRepeat 和 Angular 直接根据控制器加载模型(发布)的状态绑定并显示您的复选框。

另外,您使用“publication”对象作为跟踪药物列表以及药物类型 ID 列表的模型——我在重复跟踪时经常遇到问题,所以我也简化了在我的示例中,我只使用视图中的发布对象来绑定数据。我发现这更容易阅读,也更容易测试和适应。

app.js

var app = angular.module('stevenApp', ['ngMaterial']);

/**
 *@summary
 *  "StevenApp" has three components:
 *    (1) Main Ctrl - the main page controller
 *            the checkbox() function is here
 *    (2) PublicationsService - 
 *            Create, track and manage the drugs list
 *            for publications;
 *            A Publication ~ {id:,drugTypeIds:,addDrug(),removeDrug()}
 *    (3) DrugsService - 
 *            Maintain a "master list" of all drugs, or get it.
 *            return, filter/sort and track drugs by TYPE, ID and NAME
 * 
 *    
 */
app.service('DrugsService', [function() {

  var Master_Drug_Types = [
    {id:1,name:'Antimalarial'},
    {id:2,name:'Antibiotic'},
    {id:3,name:'Antiretroviral'},
    {id:4,name:'Antidiabetic'},
    {id:5,name:'Antituberculosis'},
    {id:6,name:'Maternal Health'}
  ];
  
  function getAllDrugTypes() {
    return Master_Drug_Types;
  }
  
  function getAllDrugTypeIDs() {
    return _.pluck(Master_Drug_Types, 'id');
  }
  
  function getDrugByName(drugName) {
    return (_.findWhere(Master_Drug_Types, {name: drugName})) || {};
  } 
    
  return {
    getAllDrugs: getAllDrugTypes,
    getAllDrugIDs: getAllDrugTypeIDs,
    getDrugTypes: getAllDrugTypes,
    getDrugByName: getDrugByName
  };
  
}])

// Create an Object/Model for Publication data
// > Constructor, properties and methods for "Publication" Objects
app.factory('PublicationModel', [function() {
  
  Publication.serial = 0;
  
  /**
   * Model/Class Constructor
   */
  function Publication(name) {
    this.id = Publication.serial++;
    this.name = name;
    this.publicationDrugTypes = [];
  }

 
  /**
   * Model/Object methods
   */
  Publication.prototype.addDrug = function (drug) {
    this.publicationDrugTypes.push(drug);
  };
  
  Publication.prototype.removeDrug = function (drug) {
    
    var drugById = _.findWhere(this.publicationDrugTypes, {id: drug.id});
    var drug_index = _.findIndex(this.publicationDrugTypes, {id: drug.id});                                    // find in a collection of values ~ indexO

    // console.log('REMOVE drug ', drug);
    // console.log('THIS ', drugById);
    // console.log('@ ', drug_index);

    if (drug_index >= 0) { 
      this.publicationDrugTypes.splice(drug_index, 1); 
    }
  };


  return Publication;
  
}])

// > manage LIST of Publications and stuff related to
  // multiple/all publications
app.service('PublicationsService', ['PublicationModel', function(Publication) {
  
    var publications = [];
    
    function getDrugTypesByPublication(targetPubId) {
      return (_.findWhere(publications, {id: targetPubId}).publicationDrugTypes) || [];
    }

    function createNewPublication(name) {
      
      var newPub = new Publication(name);
      
      // STORE
      publications.push(newPub);

      return newPub;
    }
    
    
    return {
      create: createNewPublication,
      drugsByPubId: getDrugTypesByPublication
    };
    
}]);

// > Das Main Controller
app.controller('MainCtrl', ['$scope', 'PublicationsService', 'DrugsService',
  function($scope, Publications, Drugs) {
  
    /*
      We'll use "publication.publicationDrugTypes"
      to track the current drugs.
      
      Also, I've assumed there might be more than 1
      Publication, so the controller's list of checked
      drugTypes will be the same as the "currently loaded"
      Publication's .publicationDrugTypes.
    */
    $scope.publication = {};
    
    $scope.allAvailableDrugs = [];
    
    // Init - I assumed this button click was a demo
    // for loading the controller state, which was
    // when you saw the weird behavior.
    $scope.checkboxes = function () {
      activateController();
    };
  
    $scope.updateSelection = function (drug) { // TypeId, publication, type) {

      // Is the Drug in the Publication?...
      
      /* Using the other components allows simplifying readability like this :)  */

      if ( $scope.drugIsPrescribed(drug) ) {
        // IF Drug-Type NOT currently selected/checked,
          // REMOVE it FROM the publication-listing of drugs...
          $scope.publication.removeDrug(drug);
      } else {
        // ELSE
          // ADD it TO the publication-listing of drugs...
          $scope.publication.addDrug(drug);
      }
    };
    
    $scope.drugIsPrescribed = function(drug) {
      // CHECK the publication for drug prescribed...
        return _.findWhere($scope.publication.publicationDrugTypes, {id: drug.id})
    }
    
    $scope.prescribeAllTheDrugs = function() {
      _.each($scope.allAvailableDrugs, function(d) {
        if (!$scope.drugIsPrescribed(d)) {
         $scope.publication.addDrug(d); 
        }
      });
    }
    
    $scope.unprescribeAllTheDrugs = function() {
      _.each($scope.allAvailableDrugs, function(d) {
        if ($scope.drugIsPrescribed(d)) {
         $scope.publication.removeDrug(d); 
        }
      });
    }

    // ==========

    function activateController() {
      $scope.publication = Publications.create("Sick Mother's Milk");
      
      // Arbitrary -- I saw you had these 3 selected at first, so I added them on load().
      $scope.publication.addDrug( Drugs.getDrugByName('Antimalarial') );
      $scope.publication.addDrug( Drugs.getDrugByName('Antidiabetic') );
      $scope.publication.addDrug( Drugs.getDrugByName('Maternal Health') );
      
      $scope.allAvailableDrugs = Drugs.getAllDrugs();
    }

}]);

index.html

<!DOCTYPE html>
<html ng-app="stevenApp">
  <head>
    <meta charset="utf-8" />
    <title>AngularJS Plunker</title>
    <script>document.write('<base href="' + document.location + '" />');</script>
    <link rel="stylesheet" href="style.css" />
    <link rel="stylesheet" href="//rawgit.com/angular/bower-material/master/angular-material.css">
    <script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js
"></script>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.6/angular.js"></script>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.6/angular-animate.js"></script>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.6/angular-aria.js"></script>
    <script src="//rawgit.com/angular/bower-material/master/angular-material.js"></script>
    <script src="app.js"></script>
  </head>
  
  <body ng-controller="MainCtrl as ctrl">
    
    <button ng-click="checkboxes()">click first</button>
    
    <form ng-if="allAvailableDrugs">
      <h4>Publication: {{ publication.name }}</h4>
      
      <div>{{ publication.publicationDrugTypes | json }}</div>
      
      <hr>
    
      <div class="btn btn-sm btn-primary" ng-repeat="drug in allAvailableDrugs track by $index">
        <input type="checkbox"
          ng-click="updateSelection(drug)" 
          ng-checked="drugIsPrescribed(drug)" />
        
        {{ drug.name }}
      </div>
      
      <br />
      <a href="#" ng-if="publication.publicationDrugTypes" ng-click="prescribeAllTheDrugs()">SELECT ALL</a>
      <br/>
      <a href="#" ng-if="publication.publicationDrugTypes" ng-click="unprescribeAllTheDrugs()">DE_SELECT ALL</a>
    </form>

    
  </body>
</html>

Plunkr:https://embed.plnkr.co/0oc5MR/

【讨论】:

    【解决方案3】:

    您没有正确使用您的数据。这条线是错误的。

     publication.publicationDrugTypes.splice(publication.publicationDrugTypes.indexOf($scope.publicationDrugTypes[drugTypeId-1]),1); 
    

    您使用drugTypeId 作为publicationDrugTypes 数组的索引,而这根本不是。在这种特殊情况下,您尝试使用 drugTypeId-1,即 4-1=3,并尝试索引publicationDrugTypes[3],这甚至不是有效值,因为您的数组中没有那么多值。 你真的应该重新设计你这样做的方式。一种方法是让您的 publicationDrugTypes 成为所有可能值的数组,并在每个值上都有一个额外的字段来指示是否包含。

        $scope.publicationDrugTypes = [{id:1,name:'Antimalarial',included:0},
    {id:2,name:'whatever',included:0},{id:4,name:'Antidiabetic',included:0},{id:3,name:'Antiretroviral',included:0}];
    

    我在这里只展示其中的 4 个。然后,您可以使用 ng-repeat 显示复选框并将 ng-value 分配给 object.included 字段。现在,当您选中或取消选中某个框时,它将得到更新。当您准备好提交数据时,您只需在您的publicationDrugTypes 数组中使用_find 来获取所有包含=1 的值。 有许多不同的方法可以做到这一点并使其更清洁。

    【讨论】:

      猜你喜欢
      • 2015-04-02
      • 1970-01-01
      • 1970-01-01
      • 2020-10-31
      • 1970-01-01
      • 2023-03-22
      • 2021-02-22
      • 2016-08-11
      • 1970-01-01
      相关资源
      最近更新 更多