Select at least one checkbox validation - angularjs

I have the array of checkboxes from which I want to select at least one checkbox and want to display the validation error
How can I do that? Here is my code
<div class="form-group" ng-class="{ 'has-error' : submitted && form.field.$invalid }">
<div class="col-md-12"><label for="field" >Select at leat one</label></div>
<div class="col-md-2" data-ng-repeat="i in [1,2,3,4]">
<label><input type="checkbox" name="field[$index]" value="{{i}}" data-ng-model="form.field[$index]" required/>Choice {{i+1}}</label>
</div>
<div ng-show="submitted && form.field.$invalid" class="help-block">
<p ng-show="form.field.$error.required">Please select at least one choice<p>
</div>
</div>
</div>

You can use native javascript functions to iterate over your array. First that come in mind are Array.prototype.some() and Array.prototype.filter().
With some, you can determine if one item in your array validates true and with filter you can find all the elements that pass a custom expression and check if the newly created array has a certain length.
E.g.:
var atleastOne = this.form.field.some(function(element) {
return element;
});
if(atleastOne) {
window.alert("validated with some");
}
var filtered = this.form.field.filter(function(element) {
if(element) { return element; }
});
if(filtered.length > 0) {
window.alert('validated with filter');
}
You can flag the variables that show the errors based on the results of your validation. A working demo can be found here.

You can create your checkbox list object array properly then bind it. Please find the demo
<div ng-controller="ChckbxsCtrl">
<div ng-repeat="chk in items">
<div style="width:500px;height:100px;border:1px solid #000;">
<B>{{chk.group}}</B><br>
<label ng-repeat="vale in chk.values">
<input type="checkbox" ng-model="vale.val" />
{{vale.label}}</label>
</div>
<span ng-show="chk.isValid">Select at least one option from {{chk.group}}</span>
</br> </div>
</br>

Related

get values from each ng-repeat input elements

I have the following code where I have added 5 input texts via ng-repeat and now am trying to fetch each of the input element's values. I am hitting some roadblock, so please help me out on how to fetch individual values.
HTML:
<form class="quick-add-form" method="post">
<label class="quick-add-label">Enter the catalog number and quantity</label>
<div class="quick-add">
<div class="catalog-list">
<label class="catalog-number-label" for="catalog-number-input">Catalog Number:</label>
<div ng-repeat="values in catalogNumber(number) track by $index">
<input id="catalog-number-input-{{$index}}" class="catalog-number-input"
type="text" ng-model="catalog.description" validate-input>
</div>
</div>
<div class="qnty-list">
<label class="pdt-qnty-label" for="pdt-qnty-input">Quantity:</label>
<div ng-repeat="values in catalogNumber(number) track by $index">
<input id="pdt-qnty-input-{{$index}}" class="pdt-qnty-input" type="number" pattern="[0-9]*"
inputmode="numeric" min="1" max="999" ng-model ="catalog.quantity" name="qty"
maxlength="3">
</div>
</div>
</div>
<div>
<button type="submit" class="btn btn-danger cta-button quick-add-btn"
ng-click ="quickAdd(catalog)">Add to List</button>
</div>
</form>
and controller:
$scope.catalog = {};
$scope.catalogNumber = catalogNumber;
$scope.initializeModal = initializeModal;
$scope.quickAdd = quickAdd;
function catalogNumber(num) {
return new Array(num);
}
function quickAdd(val) {
console.log(val);
}
function init() {
$scope.number = 5;
$scope.catalog.quantity = 1;
}
I am pretty sure its because of indexing and which is why by adding value in one input, its adding same value in all at once. But I am not sure how/where to use the $index properly to achieve the result.
Thanks.
Perhaps a better way would be to use the model? For example:
<div ng-repeat="values in catalogNumber(number) track by $index">
<input
id="catalog-number-input-{{$index}}"
class="catalog-number-input"
type="text"
ng-model="catalog.description[$index]"
validate-input>
</div>
Now in your controller:
catalog.description = [];
Then you have an array of objects, which you can perform your math on:
var total = _.sum(Object.values(catalog.description));
Edit: I had forgot I was using Lodash/Underscore there, but if you wanted to use standard JS you could use a standalone method, or reduce etc.,

Angular - Binding data to dropdownlist never clears out previous items on updating (keeps old items plus add new)

Hopefully a simple Angular binding question.
I have a TextBox on my Angular 4 [x.component.html] that has an (input) event tied to it, so each time the user types in a character into the textbox it reaches out to a method in the [x.component.ts] typescript file - which then retrieves data from a service to populate a local array of data in the typescript file - which is bound to a dropdownlist on the [x.component.html]. This process functionally works fine.
However the problem I am having is that when it updates the data in the local array, it is not clearing out the previous data in the dropdown, so the dropdown list ends up getting populated with lots of duplicate data. Has anyone experienced this same problem before? The local array of items seems to have the correct number of items in it, it just seems to keep populating the dropdownlist with the items without ever clearing the previous.
Thanks so much for your help.
Please note I have cut the code down to only the relevant parts for brevity.
[x.component.ts]
export class CreateComponent {
testService: TestService;
valueList: testValue[];
constructor(testService: TestService) {
this.testService = TestService;
}
ngOnInit() {
}
FieldChanged(event: any, controlNameToPopulate: string){
if (event.target.value.length >= 9) {
this.testService.getRecords(event.target.value).subscribe((data: any[]) => {
if (data.length != 0){
document.getElementById(controlNameToPopulate).hidden = false;
//this.valueList.slice();
this.valueList = data;
}
});
}
}
}
[x.component.html]
<div class="row">
<div class="col-md-6">
<nb-card>
<nb-card-header>Testing with Updating dropdownlist</nb-card-header>
<nb-card-body>
<form [formGroup]="formGrp">
<div class="form-group row">
<label class="col-sm-3 col-form-label">Quick search</label>
<div class="col-sm-9 input-group">
<input type="text" class="form-control input-sm" style="width: 50%" id="txtbx_ValTest" formControlName="testVal" (change)="FieldChanged($event, 'ddValuesToUpdate')">
<select id="ddValuesToUpdate" class="btn btn-secondary dropdown-toggle" style="width: 50%" hidden>
<option *ngFor="let val of valueList" [value]="val.id">{{val.id}}</option>
</select>
</div>
</div>
<div class="form-group row">
<div class="offset-sm-3 col-sm-9">
<button type="submit" class="btn btn-success pull-right">Add</button>
</div>
</div>
</form>
</nb-card-body>
</nb-card>
</div>
</div>

Input validation: Validation message and ng-disabled buttons not working as expected

I have the following code which I'm trying to validate using AngularJS:
<div ng-form="transWizard" novalidate>
<div style="word-wrap:break-word; padding-top:4px; padding-left:14px">
<p style="font-family:'MetricWeb-Regular'; font-size:17.5px;"><span style="font-family:'MetricWeb-Semibold'">Question {{carousel.currentQuestionIndex+1}}:</span> {{carousel.currentQuestionObject.question}}</p>
<ul style="padding-left:30px;">
<li ng-repeat="query in carousel.currentQuestionObject.choices" style="padding-bottom:5px;">
<input class="TWInputField" name="inputname"
type="{{carousel.currentQuestionObject.inputType}}" id="{{query.id}}"
ng-model="query.selected" ng-change="carousel.changeOnSelection(query.selected, query.id)"
value="" ng-value="true" ng-required="{{carousel.currentQuestionObject.inputType === 'radio' || carousel.currentQuestionObject.inputType === 'text' ? true : false}}">
<label for="{{query.id}}" style="font-family:'MetricWeb-Regular';font-size:17px;cursor:pointer"> {{query.question}}</label>
</li>
</ul>
<p class="msg-required" ng-show="transWizard.inputname.$invalid">
Input is required.
</p>
</div>
<div class="carousel-wizard-btn-container">
<div class="carousel-wizard-buttons" ng-click="carousel.wizardPrevious()" ng-hide="carousel.currentQuestionIndex == 0">Previous</div>
<div class="carousel-wizard-buttons" ng-click="carousel.wizardNext()" ng-hide="carousel.currentQuestionIndex == carousel.wizardQuestionSet.length - 1" ng-disabled="transWizard.$invalid">Next</div>
<div class="carousel-wizard-buttons" ng-click="carousel.showResults()" ng-show="carousel.currentQuestionIndex == carousel.wizardQuestionSet.length - 1" ng-disabled="transWizard.$invalid">Finish</div>
</div>
</div>
As you can see, I'm not using the <form> tag, but I've read that it's possible to validate even without using forms thanks to the ng-form directive.
My conditions are to require input only if type is radio or text.
However, when I executed this, I got the following:
ng-disabled is not working for the Next button. I can still click it even though I haven't selected any answers for the required sections.
Validation message only disappears when I click the last item in a set of radio buttoned-questions.
Am I missing something here?
Please help. Thank you.
your validation will not work as expected because u are using same name for input controls in ng-repeat.
you can use ng-form inside ng-repeat like this.
<div ng-form="transWizard" novalidate>
<li ng-repeat="query in carousel.currentQuestionObject.choices" style="padding-bottom:5px;">
<ng-form name="innerForm" >
<input class="TWInputField" name="inputname" type=" {{carousel.currentQuestionObject.inputType}}" id="{{query.id}}" ng-model="query.selected" ng-change="carousel.changeOnSelection(query.selected, query.id)" value="" ng-value="true" ng-required="{{carousel.currentQuestionObject.inputType === 'radio' || carousel.currentQuestionObject.inputType === 'text' ? true : false}}">
<label for="{{query.id}}" style="font-family:'MetricWeb-Regular';font-size:17px;cursor:pointer"> {{query.question}}</label>
<p class="msg-required" ng-show="innerForm.inputname.$invalid">
Input is required.
</p>
</ng-form>
</li>
</div>

angularjs clear backing field when input box hides

I have a page that will hide/show additional elements when an option is selected:
<div ng-app>
<div ng-controller="ctrl">
opt: <select ng-model="model.opt" ng-options="item.id as item.text for item in model.opts"></select>
<br/> <span ng-show="model.opt > 1">
alt: <input type="checkbox" ng-model="model.alt" />
</span>
<div> <pre>{{ model | json }}</pre>
</div>
</div>
</div>
http://jsfiddle.net/v7wsdj74/
How would I setup to get notification when the "ng-hide" is evaluated so that the model fields being hidden can be set back to some default values (in this case null)?
Thanks
Perhaps something like this?
scope.$watch('myParameter', (value) => {
// if myParameter is false set it to null?
}
What you can do, is reset the model on changes:
<select ng-model="..." ng-options="..." ng-change="model.alt = null"></select>
https://jsfiddle.net/bfrola/wzpha8c3/
You can also define a more complex reset function and use ng-change="reset()". Hope this helps.

How do i make text start going on a new line with angular/bootstrap?

Write now my message text is all going to be on one single line like this:
I would like it to start wrapping like iPhone text messages, is there anyway to do it programatically? insert br tags every 20 chars?
The actual message is the {{message.message}}
<div class="col-md-8 chatWindow">
<div ng-show="activeFriend">
<div class="activeFriendBox text-center">Chat with {{activeFriend.name}}</div>
<div class="messageList" scroll-glue>
<div class="messages"
ng-class="{ 'message-right': message.from === currentUser, 'message-left': message.from !==currentUser }"
ng-repeat='message in activeFriend.messages track by $index | orderBy:"timeStamp"'>
<span
ng-class="{ 'messageTextFrom': message.from === currentUser, 'messageTextTo': message.from !==currentUser }"
ng-click="revokeMessage(message)" class="messageText">{{message.message}}
</span>
</div>
</div>
<div class="sendMessage">
<form ng-submit='sendMessage(messageText)' name='messageForm'>
<input class="sendMessageInput" type='text' name='message' ng-model='messageText' maxlength="120" required/>
<input ng-disabled='!messageForm.$valid || !activeFriend.key' type='submit' value='send'/>
</form>
</div>
</div>
</div>[![enter image description here][1]][1]
This can be done with just CSS. Set a width on the container and also use word-break: break-all;
With the break-all, you can be assured that long consecutive strings, like the one in your example, will wrap in the space defined in your style sheet. You may also need to add white-space:normal; but it will all depend on the browsers you are required to support.
I would use a custom filter to split the string every 20 characters.
angular.filter('split',function(){
return function(str,length) {
str = str || "";
length = Math.max(1,~~length);
return str.match(new RegExp(".{1,"+length+"}","g")).join("<br>");
}
});
Then you can just use the filter in your template.
<span
ng-class="{ 'messageTextFrom': message.from === currentUser, 'messageTextTo': message.from !==currentUser }"
ng-click="revokeMessage(message)" class="messageText">{{message.message | split:20}}
</span>

Resources