Validation fails for mutually exclusive checkboxes - angularjs

I have two checkboxes. The validation condition is on form-submit, the form should be valid if and only if one checkbox is checked.
Went about doing like this. Gave the two checkboxes same classname and on ng-click I looped through the checkboxes and found the checked count like this.
$scope.SetCheckDatesCount = function () {
$scope.CheckedDatesCount = 0;
var checkBoxes = document.getElementsByClassName("AcceptedChecks");
for (var i = 0; i < checkBoxes.length; i++) {
if (checkBoxes[i].checked) {
$scope.CheckedDatesCount++;
}
}
};
Now in markup I set,
ng-required="CheckedDatesCount != 1"
So, that the checkbox will be ng-required when CheckedDatesCount = 0 ||CheckedDatesCount = 2.
But the validation won't work if I check two checkboxes.
Plunkr Demo: https://plnkr.co/edit/ekGCpdXspQAf6zTwDToT?p=preview
I could stop form submit by using an extra check like this. (But is that very clean?)
if (theForm.$invalid && CheckedDatesCount != 1) {
$scope.showMessages = true;
return;
}
Why is the form not invalid when two checkboxes are checked. What am I doing wrong?

you don't have to check the state of the checkobox. i think you could do this-
<div class="row">
<button ng-disabled="!((Interview.InterviewAccepted || Interview.AlternateAccepted) && (Interview.InterviewAccepted != Interview.AlternateAccepted) )" class="btn btn-success" ng-click="AcceptInterview(DemoForm)">
Accept
</button>
</div>
OR you could do this:-
<body ng-app="app" ng-controller="DemoController">
<div class="container" ng-form="DemoForm">
<div class="row">
<div class="col-md-6">
<label>Is Interview Date Accepted: </label>
<input type="checkbox" class="AcceptedChecks" name="InterviewAccepted" ng-model="Interview.InterviewAccepted" ng-required="1 && !Interview.AlternateAccepted" ng-click="SetCheckDatesCount()" />
</div>
<div class="col-md-6">
<label>Is Alternate Date Accepted: </label>
<input type="checkbox" class="AcceptedChecks" name="AlternateAccepted" ng-model="Interview.AlternateAccepted" ng-required="1 && ! Interview.InterviewAccepted" ng-click="SetCheckDatesCount()" />
</div>
</div>
<div class="row">
<button class="btn btn-success" ng-click="AcceptInterview(DemoForm)">
Accept
</button>
</div>
</div>
</body>
</html>
<script>
// Code goes here
var app = angular.module("app", []);
app.controller("DemoController", ["$scope", function($scope){
$scope.showMessages = false;
$scope.Interview = {
AlternateAccepted: false,
InterviewAccepted: false
};
$scope.AcceptInterview = function (theForm) {
console.log(theForm.$invalid);
if (theForm.$invalid) {
$scope.showMessages = true;
return;
}
alert("valid");
}
}]);
</script>

Related

Angularjs cannot perform crud operations from accordion

I am trying to add a form to a bootstrap accordion and post a text value. Without accordion the form works alright. When i added the form to the accordion i am not able to pass text box value to angularjs controller. Basically i am not able to perform the CRUD operations as i am not able to pass the values. Minimum code related to the issue.
main.html
<div ng-controller="myController">
<accordion class="accordion" close-others="oneAtATime">
<accordion-group ng-repeat="group in groups" is-open="status.isOpen[$index]" >
<accordion-heading>
{{group.groupTitle}} <i class="fa chevron-icon" ng-class="{'fa-chevron-down': status.isOpen[$index], 'fa-chevron-right': !status.isOpen[$index]}"></i>
</accordion-heading>
<div ng-include="group.templateUrl"></div>
</accordion-group>
</accordion>
</div>
controller.js
App.controller('myController', ['$scope', 'Parts', function($scope, Parts) {
var original = $scope.parts;
$scope.submit = function() {
if ($scope.parts.a_id == null) {
$scope.createNewPart();
} else {
$scope.updatePart();
}
};
$scope.createNewPart = function() {
Parts.resource1.create($scope.parts);
};
$scope.updatePart = function() {
Parts.resource2.update($scope.parts)
};
$scope.oneAtATime = true;
$scope.groups = [{
groupTitle: "ADD 1",
templateUrl: "file1.html"
}, {
groupTitle: "ADD 2",
templateUrl: "file2.html"
}];
$scope.status = {
isOpen: new Array($scope.groups.length)
};
for (var i = 0; i < $scope.status.isOpen.length; i++) {
$scope.status.isOpen[i] = (i === 0);
}
} ]);
file1.html
<div>
<form name="myForm" ng-submit="submit()">
<div class="row">
<label class="col-md-2 control-lable" for="part">Add1</label>
<input type="text" ng-model="parts.part" id="part" required />
</div>
<div class="row">
<input type="submit" value="{{!parts.id ? 'Add' : 'Update'}}" ng-disabled="myForm.$invalid">
</div>
</form>
//inside table
<tr ng-repeat="a in availableparts >
<td>{{a.id}}</td>
<td>{{a.apart}}</td>
<td><button type="button" ng-click="editPart(a.id)" >Edit</button>
<button type="button" ng-click="deletePart(a.id)">Remove</button>
</td>
</tr>
</div>
Initially, you need to set $scope.parts to empty object {}, so when you access $scope.parts.id you will have null, instead of error saying id of undefined

How to add the values which is present inside the array (or) Json?

I been wondering if someone fixed my issue. my code looks like this.
var app = angular.module('myApp', []);
app.controller('myCtrl',function($scope){
//Adding New Check# and Check amount Text Boxes
$scope.checks = [{checkNum1: '',checkAmt1:''}];
$scope.add = function() {
var newCheckNo = $scope.checks.length+1;
$scope.checks.push({['checkAmt'+newCheckNo]:''});
};
$scope.tot = function() {
return $scope.checks;
};
$scope.total = function() {
var value = "";
for(var i =0 ; i<=$scope.checks.length;i++ ){
value += $scope.checks.get('checkAmt1');
}
return value;
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">
<div class="col-md-12">
<div class="col-md-6">
<div ng-repeat="check in checks">
<div class="form-group">
<label>check Amount:</label>
<div class="col-md-5">
<input type="text" class="form-control" id="{{'id'+($index+1)}}" ng-model="check['checkAmt'+($index+1)]" maxlength="6" />
</div>
</div>
</div>
<button type="button"
ng-click="add()">Add More</button>
</div>
</div>
<div class="col-md-6">
<!--<p ng-repeat="check in checks">{{check['checkAmt'+($index+1)]}}</p>-->
</div>
<label>{{tot()}}</label>
<label>{{total()}}</label>
</div>
I am initializing $scope.checks = [{checkAmt1:''}];
and pushing the additional values on clicking Add Button (checkAmt2,checkAmt3,...so on). i want to add those values(checkAmt1+checkAmt2+...so on) dynamically by using {{total()}}. total() function is calling, i know logic inside the for loop is wrong. Please help me to fix the logic (or) Suggest me if any other way to add those values.
Thanks in advance.
Note: please refer the result in full page view.
first of all, it is not a proper way of using an array.
You can sum up column with same name and not dynamic name.
I think to make the entries distinct you have used in such manner. But it is not the good way and will make your operation on array complicated.
You can try to construct array in following way,
$scope.checks = [{id:'',checkNum: '',checkAmt:''}];
The complete changed code will look like
var app = angular.module('myApp', []);
app.controller('myCtrl',function($scope){
//Adding New Check# and Check amount Text Boxes
$scope.checks = [{id:'', checkAmt:''}];
$scope.add = function() {
var newCheckNo = $scope.checks.length+1;
$scope.checks.push({'id':newCheckNo ,'checkAmt':''});
};
$scope.tot = function() {
return $scope.checks;
};
$scope.total = function() {
var value = 0;
for(var i =0 ; i<$scope.checks.length;i++ ){
value += parseInt( $scope.checks[i].checkAmt);
}
return value;
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">
<div class="col-md-12">
<div class="col-md-6">
<div ng-repeat="check in checks">
<div class="form-group">
<label>check Amount:</label>
<div class="col-md-5">
<input type="text" class="form-control" id="{{'id'+($index+1)}}" ng-model="check['checkAmt']" maxlength="6" />
</div>
</div>
</div>
<button type="button"
ng-click="add()">Add More</button>
</div>
</div>
<div class="col-md-6">
<!--<p ng-repeat="check in checks">{{check['checkAmt']}}</p>-->
</div>
<label>{{tot()}}</label>
<label>{{total()}}</label>
</div>
I'm not sure why indeed you push into the array such objects, and not just numbers, but as you iterate over it - you can just access each value by index, then take the correct object's value:
for(var i =0 ; i<=$scope.checks.length;i++ ){
value += $scope.checks[i]['checkAmt' + i];
}

add and remove text field dynmaically in angularjs

I want to add and remove text fields in angularjs with an add button click. And in the right side of the text fields, which were added there should be a remove option. While I click on the remove the text field should delete.
I would solve this using ng-repeat. Have a look at this example:
Edit updated the code:
angular.module("module",[])
.controller("ctrl",function($scope){
$scope.inputList = [];
$scope.add = function(){
$scope.inputList.push({content:""});
};
$scope.remove = function(input){
var idx = $scope.inputList.indexOf(input);
$scope.inputList.splice(idx,1)
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="module" ng-controller="ctrl">
<div ng-repeat="input in inputList">
<input type="text" ng-model="input.content">
<input type="button" ng-click="remove(input)" value="remove">
</div>
<input type="button" ng-click="add()" value="add">
</div>
You can use ng-repeat to achieve this functionality.
You'll have to add an object in a $scope object's array everytime the user presses Add button and removing the object when the user presses - button.
Here's the code sample.
<span ng-click="addTextBox()"> + </span>
<div ng-repeat="textBox in textBoxes">
<input type='text' />
<span ng-click="removeTextBox(textBox.id)"> - </span>
</div>
The controller goes like this
$scope.textBoxes = [];
$scope.addTextBox = function() {
$scope.textBoxes.push({id: $scope.textBoxes.length +1});
}
$scope.removeTextBox = function(id){
var indexToRemove;
for(i = 0; i < $scope.textBoxes.length; i++){
if($scope.textBoxes[i].id === id){
indexToRemove = i;
}
$scope.textBoxes.splice(indexToRemove, 1);
}
}
You can use this simple way:
HTML
<span ng-repeat="hobby in hobbies track by $index">
<div class="form-group">
<input type='text' ng-model='hobbies[$index]' class="form-control pull-right"/>
<button ng-click = "addHobby()" ng-show="$last">+</button>
<button ng-click = "removeHobby($index)" ng-show="hobbies.length > 1">-</button>
</div>
</span>
Angular Controller
$scope.hobbies = [''];
$scope.addHobby = function() {
$scope.hobbies.push('');
}
$scope.removeHobby = function(index) {
if(index >= 0){
$scope.hobbies.splice(index, 1);
}
}

Get the value of dynamic check boxes in angular js when submitting the form

In my HTML form there are 5 check boxes. How can I check which check boxes are checked or not at the time of the form submission?
I am using this little piece of code. Feel free to take it.
In your controller:
$scope.sentinel = [];
$scope.toggleSelection = function(value) {
// Bit trick, equivalent to "contains"
if (~$scope.sentinel.indexOf(value)) {
var idx = $scope.sentinel.indexOf(value);
$scope.sentinel.splice(idx, 1);
return;
}
$scope.sentinel.push(value);
};
Then in your HTML:
<span ng-repeat="key in $scope.yourarray">
<md-checkbox style="margin-left:30px;" aria-label="Select item"
ng-click="toggleSelection(key)"><span>{{ key }}</span></md-checkbox>
<br/>
</span>
This allows you to have an array of any size and using the sentinel array to register already checked values. If you check again a box, the toogleSelection will prevent you from adding again a value.
You can use the Checklist-model of Angular.js. It is very useful:
var app = angular.module("app", ["checklist-model"]);
app.controller('Ctrl1', function($scope) {
$scope.roles = [
'guest',
'user',
'customer',
'admin'
];
$scope.user = {
roles: ['user']
};
$scope.checkAll = function() {
$scope.user.roles = angular.copy($scope.roles);
};
$scope.uncheckAll = function() {
$scope.user.roles = [];
};
$scope.checkFirst = function() {
$scope.user.roles.splice(0, $scope.user.roles.length);
$scope.user.roles.push('guest');
};
$scope.showCheckedOnes = function() {
var checkedBoxes = "";
for (var i = 0; i < $scope.user.roles.length; i++) {
checkedBoxes += $scope.user.roles[i] + " ";
}
alert(checkedBoxes);
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://vitalets.github.io/checklist-model/checklist-model.js"></script>
<div ng-app="app">
<div ng-controller="Ctrl1">
<label ng-repeat="role in roles">
<input type="checkbox" checklist-model="user.roles" checklist-value="role"> {{role}}
</label>
<div>
<div>
<button ng-click="checkAll()" style="margin-right: 10px">Check all</button>
<button ng-click="uncheckAll()" style="margin-right: 10px">Uncheck all</button>
<button ng-click="checkFirst()" style="margin-right: 10px">Check first</button>
<button ng-click="showCheckedOnes()" style="margin-right: 10px">Show checked ones</button>
You can define the array value and map to html.
$scope.checkbox = [];
HTML
<input ng-model="checkbox[0] type="checkbox" />
<input ng-model="checkbox[1] type="checkbox" />
<input ng-model="checkbox[2] type="checkbox" />
<input ng-model="checkbox[4] type="checkbox" />
Or you can define checkbox as object and change checkbox[index] to checkbox[name].

How can I make ng-show test for the existance of some property value in an array?

I have the following array:
[{"action":"Start","currentStatus":1,"newStatus":2},
{"action":"Archive","currentStatus":1,"newStatus":6},
{"action":"Hide","currentStatus":1,"newStatus":7},
{"action":"Delete","currentStatus":1,"newStatus":8},
{"action":"Mark","currentStatus":1,"newStatus":5},
{"action":"Grade","currentStatus":1,"newStatus":4}]
In my HTML code I was using a repeat like this:
<div ng-repeat="control in home.$ts.controls">
<button
id="start"
ng-click="home.$ts.startTest()"
ng-disable="home.$ts.action"
ng-show="control.action == 'Start'">
Start
</button>
<button
id="stop"
ng-click="home.$ts.stopTest()"
ng-disable="home.$ts.action"
ng-show="control.action == 'Stop'">
Stop
</button>
</div>
This works but I now realize this actually gives me six elements with an id="start" and six with an id="stop"
Is there another way that I could do this without the ng-repeat so that for the ng-show I just check for
the existance of the action 'Start' in the home.$ts.controls and if it exists then show that button?
replace ng-show with ng-if
<div ng-repeat="control in home.$ts.controls">
<button
id="start"
ng-click="home.$ts.startTest()"
ng-disable="home.$ts.action"
ng-if="control.action == 'Start'">
Start
</button>
<button
id="stop"
ng-click="home.$ts.stopTest()"
ng-disable="home.$ts.action"
ng-if="control.action == 'Stop'">
Stop
</button>
</div>
You could find the required actions in the array and set them on the scope. This solution uses array.filter which should be polyfilled for older browsers:
angular.module('MyModule', [])
.controller('MyController', function( $scope ) {
function action(name){
var actions = $scope.actions.filter(function(action){
return action.action === name;
});
return actions.length > 0 ? actions[0] : null;
}
$scope.actions = [
{"action":"Start"},
{"action":"Archive"},
{"action":"Hide"},
{"action":"Delete"},
{"action":"Mark"},
{"action":"Grade"}
];
$scope.start = action('Start');
$scope.stop = action('Stop');
$scope.archive = action('Archive')
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app='MyModule' ng-controller='MyController'>
<button ng-show='start != null'>{{start.action}}</button>
<button ng-show='stop != null'>{{stop.action}}</button>
<button ng-show='archive != null'>{{archive.action}}</button>
</div>

Resources