私はまさに似たものを探していますこれら(「親」を持つ 3 状態のチェックボックス)。ただし、現時点では jQuery に依存していないため、このソリューションを使用するのは適切ではありません。また、モデルがクリックされたチェックボックスの自動チェック (チェック解除) を認識できるようにするには、$scope.$apply を呼び出す必要があります。
angular.jsのバグですng-indeterminate-value の実装を要求します。しかし、それでもすべての子要素への同期は得られません。これは、コントローラーの一部であるべきではないと思います。
私が探しているのは次のようなものです:
- 次のような構文を持つ「ng-children-model」ディレクティブ
<input type="checkbox" ng-children-model="child.isSelected for child in listelements">
。ブール値のリストが計算され、0 が選択されている場合はチェックボックスが false になります。すべて選択されている場合はチェックボックスが true になります。それ以外の場合はチェックボックスが不確定になります。 - 私のコントローラーでは、次のようになります。
$scope.listelements = [{isSelected: true, desc: "Donkey"},{isSelected: false, desc: "Horse"}]
- チェックボックスは通常どおりに作成されます
<tr ng-repeat="elem in listelements"><td><input type="checkbox" ng-model="elem.isSelected"></td><td>{{elem.desc}}</td></tr>
。 - 私の理解では、クリックされた不確定チェックボックスがどの状態になるかはブラウザによって決まります。
ベストアンサー1
あなたが提示したサンプル ソリューションでは、コントローラにコードが多すぎると思います。コントローラはリストのみに注意を払い、HTML/ディレクティブは表示 ([すべて選択] チェックボックスの表示を含む) を処理する必要があります。また、すべての状態変更はモデルを通じて行われ、関数を記述することによって行われるわけではありません。
私はPlunkerで解決策をまとめました:http://plnkr.co/edit/gSeQL6XPaMsNSnlXwgHt?p=preview
ここで、コントローラーはリストを設定するだけです。
app.controller('MainCtrl', function($scope) {
$scope.list = [{
isSelected: true,
desc: "Donkey"
}, {
isSelected: false,
desc: "Horse"
}];
});
ビューは単純にそれらをレンダリングします:
<div ng-repeat="elem in list">
<input type="checkbox" ng-model="elem.isSelected" /> {{elem.desc}}
</div>
「すべて選択」チェックボックス用に、次の新しいディレクティブを作成しましたcheckbox-all
:
<input checkbox-all="list.isSelected" /> Select All
使用方法はこれですべてです。新しいディレクティブを記述する以外は、簡単に使用できるはずです。
app.directive('checkboxAll', function () {
return function(scope, iElement, iAttrs) {
var parts = iAttrs.checkboxAll.split('.');
iElement.attr('type','checkbox');
iElement.bind('change', function (evt) {
scope.$apply(function () {
var setValue = iElement.prop('checked');
angular.forEach(scope.$eval(parts[0]), function (v) {
v[parts[1]] = setValue;
});
});
});
scope.$watch(parts[0], function (newVal) {
var hasTrue, hasFalse;
angular.forEach(newVal, function (v) {
if (v[parts[1]]) {
hasTrue = true;
} else {
hasFalse = true;
}
});
if (hasTrue && hasFalse) {
iElement.attr('checked', false);
iElement.addClass('greyed');
} else {
iElement.attr('checked', hasTrue);
iElement.removeClass('greyed');
}
}, true);
};
});
変数parts
は を 2 つの部分に分割するので、スコープから のlist.isSelected
値と各オブジェクトの プロパティを取得できます。list
isSelected
入力要素にプロパティを追加してtype="checkbox"
、ブラウザの実際のチェックボックスにします。つまり、ユーザーはクリックしたり、タブで移動したりすることができます。
チェックボックスはキーボードを含むさまざまな方法で変更できるため、onchange
ではなく イベントにバインドします。 onchange イベントは 内で実行され、モデルの変更が最後に確実に反映されるようにします。onclick
scope.$apply()
最後に、$watch
チェックボックスの変更に対する入力モデルを作成します (これにより、true
複雑なオブジェクトを監視できます)。つまり、チェックボックスがユーザーによって変更された場合、または他の何らかの理由で変更された場合、[すべて選択] チェックボックスは常に同期された状態に保たれます。これは、多数の ng-click ハンドラーを作成するよりもはるかに優れています。
チェックボックスがオンとオフの両方になっている場合は、マスター チェックボックスをオフに設定し、スタイル「greyed」を追加します (を参照style.css
)。この CSS スタイルは基本的に不透明度を 30% に設定し、チェックボックスがグレー表示されますが、クリックは可能です。また、タブで移動し、スペースバーを使用して値を変更することもできます。
Firefox、Chrome、Safari でテストしましたが、IE は手元にありません。これでうまくいくといいのですが。