Angular JS /Angular Material .How to validate Checkbox group on click? - javascript

I am using Angular Material and i am doing a simple validation with checkboxes.
The Problem :
At least One checkbox should be checked.
1-If i click a checkbox and then i click again,the "required message" is not shown.
2-If i click a checkbox and then i click again,and press "Tab Key" going throught each checkbox pressing Tab,when i reach the last one and press Tab Key,the message "Required" appears.
I want that ,condition number 1 occurs too,and one more thing ,i dont want to show the "required" message when the application loads. Here is my example : https://codepen.io/anon/pen/zrjjyL
I Hope you can give me a hand,Thanks!!!!!
Code :
HTML:
<form name="myForm" ng-app="myApp" ng-controller="myController"
class="container-fluid" ng-submit="submit()">
<div class="row">
<div class="col-xs-8">
<md-input-container md-no-float>
<label>Name *</label>
<input required="" name="nombre" ng-model="model.nombre">
<div ng-messages="myForm.nombre.$error" ng-
show="myForm.nombre.$touched || myForm.$submitted">
<div ng-message="required">Required.</div>
</div>
</md-input-container>
<md-input-container md-no-float>
<label>Search Options *</label>
<input type="text" id="query" ng-model="query"/>
</md-input-container>
<md-input-container md-no-float>
<md-list-item ng-repeat="item in items | filter:query">
<p style ="font-size: 1.3rem;font-family: Roboto,'Helvetica
Neue',sans-serif"> {{ item.title }} </p>
<md-checkbox name ="permiso" ng-
model="model.opciones[item.id]['checked']" ng-required="!isChecked" ></md-
checkbox>
</md-list-item>
<div ng-messages="myForm.permiso.$error" ng-show=" myForm.permiso.$touched
|| myForm.$submitted">
<div ng-message="required">Required.</div>
</md-input-container>
</div> </div>
JS:
var app = angular.module('myApp', ['ngAnimate', 'ngAria', 'ngMaterial',
'ngMessages'])
.controller('myController', function($scope) {
$scope.items = [{
id: 1,
title: 'Item A'
}, {
id: 2,
title: 'Item A'
}, {
id: 3,
title: 'Item C'
}];;
$scope.model = {}
$scope.model.opciones = {};
$scope.isChecked = false;
$scope.$watch('model.opciones', function(selected) {
$scope.isChecked = false;
angular.forEach(selected, function(selectedItem) {
if (selectedItem.checked) $scope.isChecked = true;
});
}, true);
});

You can check if the form has been modified with formName.$dirty. Then you can only show the error if the form is actually dirty.
<div ng-message="required" ng-if="myForm.$dirty">Required.</div>

You are iterating over your items and overwriting the myFrom.permiso with each new item which means myForm.permiso is always the model of the last item in your items. That is why, when you tab through them, only the last change registers.
You should remove the name attribute of the checkboxes and add a ng-change handler instead of the $watch.
And you add a hidden checkbox for the permiso model which you update on change.
https://codepen.io/kuhnroyal/pen/LGrzGv

Related

How do I show angularjs material validation for another model property?

Using angularjs and material, I want to be able to have a readonly textbox that displays the name for a selected object a user looks up (via a modal popup), but the textbox validation should show as required and fire off if a separate id property is not populated. Here is an example plnkr.
I was originally thinking that I could do this simply by adding a hidden field with an ng-model, name, and required attribute, it would create the associated form property for the field with required validator (which it does), and I would be able to show the validator on the readonly textbox like so:
<form name="myCtrl.myForm" novalidate>
<input type="hidden" ng-model="myCtrl.id" name="id" required />
<div layout="row">
<md-input-container flex="50">
<label>Selected Object</label>
<input ng-model="myCtrl.selectedObject.selectedText" readonly />
<div ng-messages="myCtrl.myForm.id.$error">
<div ng-message="required">Please select an object.</div>
</div>
</md-input-container>
<div>
<md-button class="md-icon-button md-primary" ng-click="myCtrl.select($event)">
<md-tooltip md-direction="top">
Select Object
</md-tooltip>
<md-icon>search</md-icon>
</md-button>
</div>
</div>
<div>
<md-button class="md-raised md-primary" type="submit">Submit</md-button>
</div>
</form>
JS:
vm.select = function(evt) {
// Set the selected Object
vm.selectedObject = { selectedText: "Object id 1 selected", id: 1 };
// Set the associated ID
vm.id = 1;
};
However, the <div ng-message="required">Please select an object.</div> never displays when the form is submitted and validation fires. Any idea how I can accomplish this?
While I was typing up this question I had an idea - perhaps I should be creating a custom validator that I can apply to this input which references a separate property. That appeared to do what I needed. Here's the plnkr and here's the directive:
angular.module('MyApp', ['ngMessages', 'ngMaterial'])
.directive('requiredOther', RequiredOther);
function RequiredOther() {
return {
require: "ngModel",
scope: {
requiredOtherValue: "=requiredOther"
},
link: function(scope, element, attributes, ngModel) {
ngModel.$validators.requiredOther = function(modelValue) {
return scope.requiredOtherValue !== undefined && scope.requiredOtherValue !== null && scope.requiredOtherValue !== '';
};
scope.$watch("requiredOtherValue", function() {
ngModel.$validate();
});
}
};
}
This is the updated HTML:
<form name="myCtrl.myForm" novalidate>
<input type="hidden" ng-model="myCtrl.id" />
<div layout="row">
<md-input-container flex="50">
<label>Selected Object</label>
<input name="id" ng-model="myCtrl.selectedObject.selectedText" readonly required-other="myCtrl.id" />
<div ng-messages="myCtrl.myForm.id.$error">
<div ng-message="requiredOther">Please select an object.</div>
</div>
</md-input-container>
<div>
<md-button class="md-icon-button md-primary" ng-click="myCtrl.select($event)">
<md-tooltip md-direction="top">
Select Object
</md-tooltip>
<md-icon>search</md-icon>
</md-button>
</div>
</div>
<div>
<md-button class="md-raised md-primary" type="submit">Submit</md-button>
</div>
</form>
The required-other="myCtrl.id" directive references the id property and watches for changes and fires off validation on change:
I guess I don't really need the hidden input field anymore either.

Need to get value of the radio button and pass it to the backend using HTML and angularJS,and the data displayed in the frontend is a list

//This is my HTML code wherein am returning a list from backend.
<ul>
<li ng-repeat=" opt in bcfList1 track by $index" > <input type="radio" name="buildid" id="buildid" ng-model = $parent.selected ng-value="bcfList1" required>
{{ opt }}
</li>
</ul>
//This is my controller.js program
$scope.getDetails =function(data){
var id=data.id;
$('#addNode3').modal('show');
UpgradeService.getDataById(id).then(function(data){
if(data!=null){
$scope.List1=data.BUILDNUMBER;
}
});
}
I need to get the string value that'll be listed in front of the radio button. So once I click on radio button it should send that value to the controller.js
By using ng-model I need a solution.
Help me out!!
You need to add ng-change to your input fields with a call to that function. Here is a quick demo:
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.b = [1, 2, 3, 4, 5, 6, 7, 8, 9];
$scope.getDetails = function(index) {
console.log("sending data", index,$scope.selected);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">
<div ng-repeat="a in b track by $index">
<input type="radio" ng-model="$parent.selected" ng-value="a" ng-change="getDetails($index)" /> {{a}}
</div>
</div>
If I understand correctly, you need to gather which input type radio was clicked in controller and send this information to backend.
ng-model directive is very good approach here and you can use it just like so:
html
<label>
One
<input type="radio" value="one" ng-model="radio">
</label>
<label>
Two
<input type="radio" value="two" ng-model="radio">
</label>
<br><br>{{ radio }}<br>
JS
app.controller('MainCtrl', function($scope) {
$scope.radio = '';
$scope.consoleLogRadio = function() {
console.log($scope.radio);
}
});
Take a look at plunker example

textbox validation for number and required in repeating mode angular js

Please refer below link
https://plnkr.co/edit/9HbLMBUw0Q6mj7oyCahP?p=preview
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.NDCarray = [{val: ''}];
$scope.NDCadd = function() {
$scope.NDCarray.unshift(
{val: ''}
);
};
$scope.data = angular.copy($scope.NDCarray);
$scope.NDCcancel=function(){debugger
$scope.NDCarray=$scope.data;
}
$scope.NDCdelete = function(index) {
if(index != $scope.NDCarray.length -1){
$scope.NDCarray.splice(index, 1);
}
};
});
It contains the textbox with add button. I have added validation for number and required field, it is working fine. but when i click add button it will create another textbox with entered value that time it showing the validation message for all the textboxes , i don't want to show validation message for all the textboxes. need to show validation for corresponding textbox only. that means when i enter something wrong in second textbox it is showing message to that textbox only.refer below screenshot.
validation message displaying for all textboxes.that should display for only one textbox.
Working plnkr : https://plnkr.co/edit/f4kAdZSIsxWECd0i8LDT?p=preview
Your problem is in your HTML, to get independant fields you must :
Move outside the form of the ng-repeat
Provide a dynamic name using $index on your fields, because name is what make each fields independant on the validation.
Here is the final HTML from the plnkr i didn't touch at all the javascript :
<body ng-controller="MainCtrl">
<form name="myForm">
<div ng-repeat ="ndc in NDCarray">
<div class="col-sm-4 type7" style="font-size:14px;">
<div style="margin-bottom:5px;">NDC9</div>
<label>Number:
<input type="number" ng-model="ndc.value"
min="0" max="99" name="{{'input_'+$index}}" required>
</label>
<div role="alert">
<span class="error" ng-show="myForm.input.$dirty && myForm.input.$error.required">
Required!</span>
<span class="error" ng-show="myForm.input.$error.number">
Not valid number!</span>
</div>
<tt>value = {{example.value}}</tt><br/>
<tt>myForm['input_{{$index}}'].$valid = {{myForm['input_'+$index].$valid}}</tt><br/>
<tt>myForm['input_{{$index}}'].$error = {{myForm['input_'+$index].$error}}</tt><br/>
</div>
<div class="col-sm-4 type7 " style="font-size:14px;">
<div style="padding-top:20px; display:block">
<span class="red" id="delete" ng-class="{'disabled' : 'true'}" ng-click="NDCdelete($index)">Delete</span>
<span>Cancel </span>
<span id="addRow" style="cursor:pointer" ng-click="NDCadd()">Add </span>
</div>
</div>
</div>
<tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
<tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
</form>
</body>
Couple of changes:
If you add "track by $index" to your ng-repeat it will make each group of elements unique so that you don't have to worry about deriving unique names for elements.
Your validation on the number (myForm.ndcValue.$error.number) didn't work so I changed it to myForm.ndcValue.$error.max || myForm.ndcValue.$error.min
Also, you can throw an ng-form attribute directly on the div with your ng-repeat.
Like this:
<div ng-repeat="ndc in NDCarray track by $index" ng-form="myForm">
<div class="col-sm-4 type7" style="font-size:14px;">
<div style="margin-bottom:5px;">NDC9</div>
<label>Number:
<input type="number" ng-model="ndc.value" min="0" max="99" name="ndcValue" required>
</label>
<div role="alert">
<span class="error" ng-show="myForm.ndcValue.$dirty && myForm.ndcValue.$error.required">
Required!</span>
<span class="error" ng-show="myForm.ndcValue.$error.max || myForm.ndcValue.$error.min">
Not valid number!</span>
</div>
<tt>value = {{example.value}}</tt>
<br/>
<tt>myForm.ndcValue.$valid = {{myForm.ndcValue.$valid}}</tt>
<br/>
<tt>myForm.ndcValue.$error = {{myForm.ndcValue.$error}}</tt>
<br/>
</div>
Here's the working plunker.
I changed the input element name from "input" to "ndcValue" to be less confusing.

Angular radio validation in ng-repeat

I'm trying to create a form that is valid if a radio button is selected. The radio button is part of a group from which the user can choose one. I'm assigning the required attribute to the radio buttons using a function in my controller, and this seems to be causing issues with the validation. I think it's some sort of scope problem but I can't figure it out.
Here's a jsfiddle showing the problem: http://jsfiddle.net/flyingL123/x27nv8fq/5/
You can see that the radio inputs correctly have the required attribute assigned to them, but even if the user doesn't select an option, the form still validates and submits.
Here's the HTML:
<div ng-app="test" ng-controller="TestController">
<form name="testForm" ng-submit="testForm.$valid && submitForm()" novalidate>
<div ng-repeat="option in options">
<input type="radio" name="testInput"
ng-value="option"
ng-model="$parent.selectedOption"
ng-required="required()" />
{{ option.value }}
</div>
<button type="submit">Submit</button>
<p ng-show="testForm.testInput.$invalid">Form is invalid</p>
{{ selectedOption }}
</form>
</div>
And the JS:
var test = angular.module('test', []);
test.controller('TestController', ['$scope', function($scope){
$scope.options = [{id: '0', value: 'blue'}, {id: 1, value: 'green'}]
$scope.selectedOption = {};
$scope.submitForm = function(){
alert('Form valid and submitted');
}
$scope.required = function(){
if(!$scope.selectedOption.id){
return true;
}
return false;
}
}]);
Why is the form considered valid even though a required radio input is not selected?
There were 2 issues that I noticed:
1) The $scope.selectedOption (as you mentioned)
2) The $scope.required function is unnecessary as far as I can tell. You should just set required to true on those inputs - Angular knows via the name attribute that only 1 of the inputs needs to be checked.
You can see it in action here - http://jsfiddle.net/x27nv8fq/6/
HTML
<div ng-app="test" ng-controller="TestController">
<form name="testForm" ng-submit="testForm.$valid && submitForm()" novalidate>
<div ng-repeat="option in options">
<input type="radio" name="testInput"
ng-value="option"
ng-model="selectedOption"
ng-required="true" />
{{ option.value }}
</div>
<button type="submit">Submit</button>
<p ng-show="testForm.testInput.$invalid">Form is invalid</p>
{{ selectedOption }}
</form>
</div>
Javascript
var test = angular.module('test', []);
test.controller('TestController', ['$scope', function($scope){
$scope.options = [{id: '0', value: 'blue'}, {id: 1, value: 'green'}]
$scope.selectedOption;
$scope.submitForm = function(){
alert('Form valid and submitted');
}
}]);
It looks like the issue is that I'm initializing $scope.selectedOption to {} rather than leaving it undefined. I'm guessing that since an empty object is "truthy", Angular considers it valid. Remove this from the code seems to have fixed the problem.

AngularJS directive move checkboxes

If I have two or more checkboxes how would I move unchecked checkboxes below the ones that are checked. At the moment I have simple HTML below, so if Checkbox 2 is checked it should move to the top and Checkbox 1 should move down.
The 2 ways I have thought of doing this is:
create and array on the scope and use ng-repeat to populate the checkboxes then apply a filter based on weather or not a checkbox is checked or splice the array. Only problem with this is I don't really want to define my checkboxes on the scope.
create a directive to somehow manipulate the dom element.
If someone has had a similar problem what would you recommend to be the best solution?
<div class="col-md-6">
Please check one or more boxes <i tooltip-placement="bottom" tooltip="On the Bottom!" class="fa fa-question-circle"></i>
<span ng-show="checked || checked_2" class="glyphicon glyphicon-ok text-success"></span>
<span ng-hide="checked || checked_2" class="glyphicon glyphicon-remove text-danger"></span>
<div class="checkbox">
<label>
<input ng-model="checked" type="checkbox" value="1">
Checkbox 1
</label>
</div>
<div class="checkbox">
<label>
<input ng-model="checked_2" type="checkbox" value="2">
Checkbox 2
</label>
</div>
<div ng-hide="checked || checked_2" class="text-danger">Some error message!</div>
<br/>
</div>
Try using the orderBy filter:
JS
var app = angular.module("app", []);
app.controller('Ctrl', function ($scope) {
$scope.users = [
{ Name: 'John', Selected: false },
{ Name: 'Mary', Selected: false },
{ Name: 'Jane', Selected: false },
{ Name: 'Tom', Selected: false },
{ Name: 'Benny', Selected: false }
];
});
HTML
<body ng-app="app" ng-controller='Ctrl'>
<ul>
<li ng-repeat="user in users | orderBy: ['-Selected','Name']">
{{user.Name }} <input type="checkbox" ng-model="user.Selected" />
</li>
</ul>
</body>
Demo Plunker

Categories