2013-04-23 5 views
0

Я пытаюсь создать иерархию флажков в AngularJS. Я могу создать родительский флажок, который будет автоматически проверять дочерний флажок, и если я установил флажок вручную вручную, он обновит его дочерний (внук родителя). Однако, если я нажму на родительский флажок, он не обновит флажок внука.AngularJS: Grandchild checkbox select from Parent checkbox

Перед тем, как перейти к JavaScript, чтобы убедиться, что флажок parent обновлен флажок внука, я просто хотел бы узнать, есть ли более простой способ. Здесь мой код и jsFiddle для вашего удовольствия.

<div ng-app=""> 
    <strong>Parent</strong> (will check all Child boxes): 
    <input type="checkbox" ng-model="parent" /> 
    <br/> 
    <strong>Child 1</strong>: 
    <input type="checkbox" ng-checked="parent" /> 
    <br /> 
    <strong>Child 2</strong>: 
    <input type="checkbox" ng-checked="parent" /> 
    <br /> 
    <strong>Child 3</strong> (will check all Grandchild boxes): 
    <input type="checkbox" ng-checked="parent" ng-model="child" /> 
    <br /> 
    <strong>Grandchild 1</strong>: 
    <input type="checkbox" ng-checked="child" /> 
    <br /> 
    <strong>Grandchild 2</strong>: 
    <input type="checkbox" ng-checked="child" /> 
    <br /> 
    <strong>Grandchild 3</strong>: 
    <input type="checkbox" ng-checked="child" /> 
</div> 

Любая помощь будет оценена!

Кроме того, может ли кто-нибудь из 1500 rep помочь мне, создав тег «angularjs-ng-checked»? Это было бы здорово!

+0

Недавно я написал что-то вроде этого: http://jsfiddle.net/langdonx/hQqQV/2/. Я просто использовал модель и повторил через некоторые массивы, чтобы проверить, было ли все проверено или нет (вместо проверки элементов dom). См. '$ Scope.groupChecked' и' _syncGroupCheckBox' (вызывается '$ scope.unitChecked'). – Langdon

+0

Это может помочь с частью JavaScript, но меня больше интересует гораздо более простой подход, прежде чем я решит получить фантазию. Цените код, хотя! – incutonez

+0

К сожалению, нет более простого подхода. Это невозможно сделать просто через HTML. См. Комментарии Misko здесь: https://github.com/angular/angular.js/pull/1057 – Langdon

ответ

3

К сожалению, нет более простого подхода.

От Мисько via github:

... мы думаем, что вы пытаетесь сделать, не имеет смысла. ng-checked создает одностороннюю привязку данных, но ng-model создает двустороннюю привязку данных. В сущности, у вас есть две модели, связанные с одним и тем же элементом ввода, и я думаю, что это просто неправильно. Я думаю, что ng-model и ng-checked должны использоваться исключительно, то есть то или другое, но не вместе.

Вне использования директивы или синхронизации проверок себя в контроллере не существует много вариантов.

0

Я занимаюсь какой-то причудой (ха-ха), и я придумал решение, которое кажется довольно общим ... что означает, что у вас может быть столько гнездовых флажков, сколько пожелает ваше сердце. Я уверен, что есть некоторые странные практики, за которыми я следую, и могут быть области, где производительность может быть увеличена - это, безусловно, цикл через множество объектов - так что не стесняйтесь критиковать его! Я хотел бы услышать любую обратную связь.

Код можно найти здесь jsFiddle. Я также отправлю его здесь.

HTML-

<!DOCTYPE html> 
<html> 
    <head> 
    <script src="../js/angularjs106.js"></script> 
    <script src="angular_checkbox.js"></script> 
    <link rel="stylesheet" href="angular_checkbox.css" /> 
    </head> 
    <body ng-app> 
    <div ng-controller="Ctrl"> 
     <ul> 
     <li> 
      <input type="checkbox" value="allChecks.id" ng-model="allChecks.isChecked" ng-change="checkChange(allChecks)"> 
      <label>{{allChecks.id}}</label> 
     </li> 
     <li ng-repeat="child in allChecks.children"> 
      <input type="checkbox" ng-model="child.isChecked" ng-change="checkChange(child)"> 
      <label>{{child.id}}</label> 
      <ul> 
      <li ng-repeat="grandchild in child.children"> 
       <input type="checkbox" ng-model="grandchild.isChecked" ng-change="checkChange(grandchild)"> 
       <label>{{grandchild.id}}</label> 
       <ul> 
       <li ng-repeat="grandgrandchild in grandchild.children"> 
        <input type="checkbox" ng-model="grandgrandchild.isChecked" ng-change="checkChange(grandgrandchild)"> 
        <label>{{grandgrandchild.id}}</label> 
       </li> 
       </ul> 
      </li> 
      </ul> 
     </li> 
     </ul> 
    </div> 
    </body> 
</html> 

JavaScript

function Ctrl($scope) { 
    function Node(id, isChecked, parent) { 
    this.id = id; 
    this.isChecked = isChecked; 
    this.parent = parent; 
    this.children = []; 
    } 

    var parent = new Node('ALL', true, ""); 
    var child1 = new Node('Child 1', true, parent); 
    var gchild1 = new Node('Grandchild 1', true, child1); 
    var gchild2 = new Node('Grandchild 2', true, child1); 
    var gchild3 = new Node('Grandchild 3', true, child1); 
    child1.children.push(gchild1, gchild2, gchild3); 
    var child2 = new Node('Child 2', true, parent); 
    var child3 = new Node('Child 3', true, parent); 
    var child4 = new Node('Child 4', true, parent); 
    var gchild4 = new Node('Grandchild 4', true, child4); 
    var gchild5 = new Node('Grandchild 5', true, child4); 
    var gchild6 = new Node('Grandchild 6', true, child4); 
    var ggchild1 = new Node('Grandgrandchild 1', true, gchild6); 
    var ggchild2 = new Node('Grandgrandchild 2', true, gchild6); 
    var ggchild3 = new Node('Grandgrandchild 3', true, gchild6); 
    gchild6.children.push(ggchild1, ggchild2, ggchild3); 
    child4.children.push(gchild4, gchild5, gchild6); 
    var child5 = new Node('Child 5', true, parent); 
    parent.children.push(child1, child2, child3, child4, child5); 
    $scope.allChecks = parent; 

    function parentCheckChange(item) { 
    for (var i in item.children) { 
     item.children[i].isChecked = item.isChecked; 
     if (item.children[i].children) { 
     parentCheckChange(item.children[i]); 
     } 
    } 
    } 

    function childCheckChange(parent) { 
    var allChecks = true; 
    for (var i in parent.children) { 
     if (!parent.children[i].isChecked) { 
     allChecks = false; 
     break; 
     } 
    } 
    if (allChecks) { 
     parent.isChecked = true; 
    } 
    else { 
     parent.isChecked = false; 
    } 
    if (parent.parent) { 
     childCheckChange(parent.parent); 
    } 
    } 

    $scope.checkChange = function(item) { 
    // We're handling the ALL checkbox 
    if (item.id === $scope.allChecks.id) { 
     parentCheckChange(item); 
    } 
    // We're handling the toggling of all of the children here 
    else { 
     if (item.children) { 
     parentCheckChange(item); 
     } 
     childCheckChange(item.parent); 
    } 
    }; 
} 

Крошечная CSS

ul { 
    list-style: none; 
} 

Во всяком случае, я хочу чтобы выяснить способ поиска родителя в объекте. Оказывается, родной объект JavaScript не содержит ссылки на родительский объект ребенка, поэтому я решил создать класс под названием Node. Когда я создаю экземпляр узла, я могу установить родительский объект, содержащий дочерний элемент. Как только я это сделаю, рекурсия становится довольно простой.

parentCheckChange вызывается, когда мы понимаем, что у нас есть родитель. childCheckChange вызывается, когда чек ребенка изменяется (duh!), но он используется, чтобы следить за всеми родительскими детьми ...если все они отмечены, то мы должны убедиться, что родительский флажок установлен, и поскольку этот родитель был проверен, нам нужно проверить, должен ли его родительский элемент проверяться (рекурсивно).

Код может быть немного запутанным, поэтому, пожалуйста, задавайте вопросы, если вы в замешательстве!