Tri-state md-checkbox with angular materials - javascript

I'm working with Angular material 1.0.5 and the md-checkbox directive.
I was wondering if anyone knows how to make this into a tri-state checkbox.
The three states (and the associated variable values for my situation) are:
Checked (true)
Unchecked (false)
Indeterminate (null)
For the version of Angular Material specified (1.0.5), when the checkbox is disabled, it
shows the indeterminate state as a checkbox with a question mark in it.
However, when it is not disabled, it defaults back to a two state checkbox.
So far my failed attempts have been to wrapping the directive in another directive and trying to take over control of the md-checkbox.
Does anyone have any pointers in this situation?
Thanks.

If you use angular material >1.0.8, you are able to use the md-indeterminate attribute and manage the value with your own ng-change function.
HTML
<md-checkbox ng-model="vm.checkModel"
md-indeterminate="vm.checkModel === null"
ng-change="vm.checkModelChange()">
Checkbox
</md-checkbox>
CONTROLLER
var checkValues = [false, true, null];
var index = 0;
vm.checkModel = checkValues[index];
vm.checkModelChange = function() {
vm.checkModel = checkValues[++index % checkValues.length];
}
Check this JSFIDDLE for angular material >1.0.8. (Best solution)
Check this JSFIDDLE for angular material 1.0.5. (I've used ng-class css to simulate the indeterminate state).

Related

Select dropdown not adding CSS first time only

So I'm being cracking my head at this issue for quite some time and I'm stumped as to why the code is behaving as such.
So I'm using the following in my project:
AngularJS v1.2.22
Bootstrap v3.1.1
jQuery v1.5
Scenario:
I have 2 select dropdown's where the values are retrieved from the DB using angular (working), on the UI aspect I have to disable the 2nd dropdown based on the first dropdown's value (selected) also works (used scope.watch), but it fails only on the first time i.e. based on the default values set, it doesn't disable it.
Actual:
On load first time based on the default value the 2nd dropdown should be disabled but its not
Excepted:
It should get disabled
This is what stumps me,
I have got it to work using ng-disabled="dropdown2" and the angular side $scope.dropdown2 = true;
This disables the dropdown but, the CSS doesn't work.
IfI change the above to ng-disabled="{{dropdown2}}" and the angular side $scope.dropdown2 = 'disabled';
Then dropdown doesn't get disabled but, the CSS works.
Code
AngularJS
$scope.$watch('formItem.dropdown1',function(newValue,oldValue){
if(newValue.cd==='A' || newValue.cd==='B'){
//$scope.dropdown2= 'disabled';
$scope.dropdown2= true;
$document.find("#eldropdown2").next().addClass('disabled');
$document.find("#eldropdown2").attr('disabled',true);
}
HTML
<div class="col-lg-7" >
<select class="form-control" id="eldropdown2" ng-model="formItem.dropdown2" ng-options="c.valueForDisplay for c in dropdown2" ng-disabled="dropdown2" paCombobox></select>
</div>
Can anyone help me figure out why AngularJs/Js does this ??
EDITED
My colleague helped me fix this issue my adding the following line in the JS
ANGULAR JS
$scope.dropdown2= true;
$scope.$watch('formItem.dropdown1',function(newValue,oldValue){
if(newValue.cd==='A' || newValue.cd==='B'){
$scope.dropdown2= 'disabled';
// $scope.dropdown2= true;
$document.find("#eldropdown2").next().addClass('disabled');
$document.find("#eldropdown2").attr('disabled',true);
}
HTML
<div class="col-lg-7" >
<select class="form-control" id="eldropdown2" ng-model="formItem.dropdown2" ng-options="c.valueForDisplay for c in dropdown2" ng-disabled="{{dropdown2}}" pa-combobox></select>
</div>
Above scope.watch, But how did it work ?? clearly this is a hack right ?? I mean since ng-disabled="{{dropdown2}}" will accept el-value and not boolean value right but how does it work ??
Also upon further investigation I came across this piece of code in the JS side
app.directive('paCombobox', function () {
return function (scope, element, attrs) {
scope.$watch(attrs.ngModel, function (value) {
element.selecter('destroy');
if(scope.disableEle || element.attr('ng-disabled')==='disabled'){
element.selecter();
element.selecter('disable');
}else{
element.selecter({
inputFilter:true
});
element.selecter('enable');
}
var tabIndex = element[0].tabIndex;
if(tabIndex != -1){
element.parent().find('div.selecter')[0].tabIndex = tabIndex;
}
});
};
});
Can anyone tell me Why and how this works?? and what is the best practice to follow, clearly the above seems like a hack and it shouldn't work right ??
I have two initial ideas for you to try,
At the end of the $scope.$watch maybe try adding a $scope.$apply()? It could update the DOM to inform it of the needed css change.
The other idea I would have would be to use an ng-class and query for dropdown2.
ng-class="dropdown2?'class for dropdown2 == true':'class for dropdown2 == false'"
Instead of adding the class try to use the attribute disabled:
<select disabled id="eldropdown2" ng-disabled="dropdown2"></select>
And then with angular remove the attribute instead of the class.

AngularJs keep lists in pristine state

We have a mover directive with 2 lists controls and 4 buttons. I want to be able to add keepPristine property to this directive and if I set it to true, the control should not react on changes and set ng-dirty flag. I tried adding to the ng-change event of the list:
$scope.onChanged = function (assigned) {
$scope.selectedItem = assigned[0];
if ($scope.keepPristine)
{
$scope.form.assignedList.$pristine = true;
$scope.form.unAssignedList.$pristine = true;
}
}
Unfortunately, when I inspect this control using Developer's Tools I see it's still has ng-dirty state. What should I do to make sure both lists are always in the pristine state regardless on my interaction with them?
You should try to use the method $setPristine() instead... and, if after that, it's not "pristine" yet then add an $scope.$apply() after the $setPristine() call.

Binding two models in SAPUI5

I have two components, a multiComboBox and a checkbox.
And both of the components are binding with one model.
I want to know whether the data of the model can be connected in one way. If I select the checkbox, the comboBox is enabled. And if the comboBox is disabled, the property 'selected' of the checkbox cannot be changed.
var comboBox = new sap.m.MultiComboBox({
enabled:'{isOthers}',
});
var checkbox = new sap.m.CheckBox({
selected: '{checked}'
});
I don't understand this "And if the comboBox is dis enabled, the property 'selected' of checkbox won't be changed.", anyway, check the following code: JS Bin Demonstration

How to select Parent Checkbox when a Child is selected inside ng-repeat

I am having a very hard time trying to figure out a solution for this. I have a checkbox group where the first checkbox is the parent and the following in that set will be child. I want the parent checkbox to be selected automatically if one of the child's checkbox is selected. Similarly parent needs to be get unchecked if no child is selected.
Here is my jsfiddle example: http://jsfiddle.net/Alien_time/PqTR7/3/
The main difficulty I am facing is because the checkboxes are created dynamically and it has dynamic ng-models for each. I have tried the following so far:
1) ng-checked: This doesnt work for me since ng-checked doesnt bind the value with ng-model. I need the ng-model of the parent to be updated as well since this is going to reflect in the main form.
2) JS solution: I thought js method will be the solution, but dont know how to add the js to controller as the ng-model is dynamically generated.
3) On other posts, there are some method that uses select all when parent is checked. But I couldnt find a solution for my approach since its the other way around where I only want the parent selected if one of the child is selected.
For my form, I need to have a different ng-model for each checkbox thats why I am using the name to create a dynamic ng-model name. But I just couldnt figure out how to select the parent checkbox if a child is selected in this dynamic list.
I have been stuck on this for 2 days and searched a lot on the net. Can you help me please?
HERE is the working solution based on your fiddle.
JS
$scope.select = function(index){
if(index === 0){
$scope.slaves.forEach(function(slave, ind){
$scope.slaves[ind].isChecked = $scope.slaves[0].isChecked;
});
}
else {
var anyChild = false;
for(var i = 1; i < $scope.slaves.length; i++){
anyChild = anyChild || $scope.slaves[i].isChecked;
}
$scope.slaves[0].isChecked = anyChild;
}
}
HTML
<div ng-repeat="slave in slaves">
<input type="checkbox" ng-model="slave.isChecked" ng-click="select($index)" />
{{slave.name}} - {{ slave.description }}
</div>
To tell the truth I do not find the solution elegant -- you would be better off by encapsulating the logic of it in a custom directive.
Moreover it would be probably better to express parent-child relation by:
var parent = {
... // parent data
childeren : [child_1, ... , child_N] // array of children
}
A solution to this problem is to add a watch.
Add the following in your controller
$scope.$watch('checkboxData', function (newValue, oldValue) {
var anyChecked = false;
// see if any are checked
$scope.slaves.reduce(function (pVal, cVal, idx, arr) {
if (newValue[cVal.name]) anyChecked = anyChecked || newValue[cVal.name];
});
// replace the parent 'checked' in the model
$scope.checkboxData['Parent'] = anyChecked;
}, true);
And add the following to your input elements.
ng-checked='checkboxData[slave.name]'

Angular ng-model bound from nested ng-repeat

This must have been already done, and I am missing something about how Angular works on that point.
In short, I have <select ng-model><option ng-repeat/></select> and I don't know how to give it a default value at page load.
View:
<div ng-ctrl="MyCtrl">
<form ng-submit="submitChoice()">
<select ng-model='choice'>
<option ng-repeat='choice in choices' value='{{choice.id}}'>{{choice.id}}</option>
</select>
</form>
</div>
Way 1: When user updates the view (select the 'choice' he wants), the $scope used in MyCtrl gets it and I can perform whatever I want with it:
Way 2: But if, the other way round, I want to programmatically set the default value for the choices from the controller (at start), it can't change the value displayed:
function MyCtrl ($scope) {
$scope.submitChoice = function() {return;}; // Way1: OK!
$scope.choice = choice4; // Way2: Doesn't change the view!!
}
I guess it's because each element in ng-repeat has its own scope (fyi if I hardcode options in view instead of a ng-repeat, it works well).
In way 1 the inner scope selected by the use emits choice to the upper scope, if I understand well. But I have no idea how to do way 2.
Is it doable in a simple way? Is a directive necessary?
You would be better off using the ng-options directive with the select directive. Using select + ngRepeat has all sort of limitations and is better avoided. Is there any particular reason for generating options with ngRepeat?
If you could share more code (especially the structure of your data model) I might be able to provide more info.

Categories