ngIf an angular reactive form component value - javascript

I have a set of radio buttons. If a user selected the value "yes" I want to show an additional box on the form.
https://stackblitz.com/edit/angular-4bgahw?file=src/app/personal/personal.component.ts
HTML.component
<div formGroupName="radioButtonsGroup" class="form-group col-6 pl-0 pt-3">
<div class="form-check-inline" *ngFor="let item of personal.radioButtonsdata">
<label for="{{item.section}}" class="col-12 customradio"
><span>{{item.section}}</span>
<input [value]="item" id="{{item.section}}" type="radio" formControlName="selectedButton"/>
<span class="checkmark"></span>
</label>
</div>
<!-- <div class="col-md-8" *ngIf="selectedButton.control.item === 'yes'"> --> //my attempt to target above input value
<div class="col-md-8" >
<input type="text" formControlName="title" class="form-control" placeholder="Title">
</div>
</div>
Can anybody get this to work and show me what I am doing wrong here please?

You need to access the value of the form control:
*ngIf="form.get('radioButtonsGroup.selectedButton').value.section === 'yes'">
STACKBLITZ

Everything you write in the template is resolved against the corresponding class (or against template variables), so you have to refer to the JavaScript control like this:
*ngIf="form.controls['selectedButton'].value === 'yes'"

Call a function to set flag based on value of the radio button, (ngModelChange)="onRadiochange($event)"
Try like this:
Working Demo
.html
<input [value]="item" (ngModelChange)="onRadiochange($event)" id="{{item.section}}" type="radio" formControlName="selectedButton" />
<div class="col-md-8" *ngIf="showTitle">
<input type="text" formControlName="title" class="form-control" placeholder="Title">
</div>
.ts
onRadiochange(e) {
if(e.section == 'yes'){
this.showTitle = true
} else {
this.showTitle = false
}
}
It can also be done in one line like this:
<input [value]="item" (ngModelChange)="$event.section == 'yes' ? showTitle=true:showTitle=false" id="{{item.section}}" type="radio" formControlName="selectedButton" />

Whenever yes checkbox is selected, you have to display the title textbox.
In that case, change your code like this.
In personal.component.ts, add this variable.
yesSelected: boolean = true;
Also in ngOnInit(),
this.form.valueChanges.subscribe(val=>{
if(val.radioButtonsGroup.selectedButton.section === "yes")
this.yesSelected = true;
else
this.yesSelected = false;
});
In personal.component.html, rewrite your if condition like this.
<div class="col-md-8" *ngIf="yesSelected">
<input type="text" formControlName="title" placeholder="Title">
</div>
These changes will show the title textbox only when the yes check box is selected.

Related

Angular 4 - using ngModel inside (click)

So I have the following html:
<div class="workflow-row">
<input type="checkbox" id="new-workflow" [(ngModel)]="new_checkbox">
<label>New Workflow</label>
<input type="text" *ngIf="new_checkbox" placeholder="Enter Workflow Name">
</div>
<div class="workflow-row">
<input type="checkbox" id="edit-workflow" [(ngModel)]="edit_checkbox">
<label>Edit Workflow</label>
<select *ngIf="edit_checkbox"></select>
</div>
I want the checkboxes to act like radio buttons, ie: if one is checked, the other one becomes unchecked with angular 4. I tried doing
<input type="checkbox" id="edit-workflow" (click)="new_checkbox.checked = false"
[(ngModel)]="edit_checkbox">
but I get an error and it says that new_checkbox is undefined. The weird thing is that new_checkbox and edit_checkbox work inside the ngIf statements but not inside the (click)'s. What am I doing wrong?
I suggest you to try the following:
component.ts:
export class AppComponent {
edit_checkbox = false;
new_checkbox = true;
dropNewValue() {
this.new_checkbox = false;
}
dropEditValue() {
this.edit_checkbox = false;
}
}
Then in your template file, e.g. component.html, change your template slightly to:
<div class="workflow-row">
<input type="checkbox" id="new-workflow" [(ngModel)]="new_checkbox" (ngModelChange)="dropEditValue()">
<label>New Workflow</label>
<input type="text" *ngIf="new_checkbox" placeholder="Enter Workflow Name">
</div>
<div class="workflow-row">
<input type="checkbox" id="edit-workflow" [(ngModel)]="edit_checkbox" (ngModelChange)="dropNewValue()">
<label>Edit Workflow</label>
<select *ngIf="edit_checkbox"></select>
</div>
I've just tried this and it works. However I do recommend to switch to radio buttons approach, because you will get the same behavior out of the box.
Don't write Angular like you're writing regular javascript instead of
(click)="new_checkbox.checked = false"
do something like
// .html
(click)="uncheckNewCheckbox()"
// .js or .ts
uncheckNewCheckbox() {
this.new_checkbox.checked = false;
}

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.

Javascript check bootstrap checkbox by id

I have the following form :
<form class="form-inline" role="form">
<div class="col-xs-3">
<div class="pic-container">
<div class="checkbox">
<label>
<input type="checkbox" name="discounting" onchange='handleChange(this);' id='check11' > Show only price-discounted products
</label>
</div>
</div>
</div>
<div class="col-xs-3">
<div class="pic-container">
<div class="checkbox" id='check21'>
<label>
<input type="checkbox" name="discounting" onchange='' id='check21'> Show only price-discounted products
</label>
</div>
</div>
</div>
</form>
I'd like to be able to check the second checkbox automatically with JavaScript once I check the first one. I tried using the following script :
<script>
function handleChange(cb) {
if(cb.checked == true) {
alert('Message 1');
document.getElementById("check21").checked = true;
} else {
alert('Message 2');
var x = document.getElementById("check21").disabled= false;
}
}
</script>
But it doesn't work since I think with bootstrap is a question of classes.
The problem as Didier pointed out is that you have two elements with the same ID:
<div class="checkbox" id='check21'>
and
<input type="checkbox" name="discounting" onchange='' id='check21'>
The call to document.getElementById('check21') will probably (because the behavior is undefined) return the first one, which in this case is the <div> element, not the checkbox.
You must not use the same ID on two HTML elements, so you need to change the ID on one or the other of them.
http://jsfiddle.net/uywaxds5/2/
I included boostrap as an external reference.
<div class="checkbox" id='check22'>
<label>
<input type="checkbox" name="discounting" onchange='' id='check21'> Show only price-discounted products
</label>
</div>
Fixing the duplicate id seems to work.
If it does not works, the issue might be in another part of your code.
Use a different name for the second radio button
<input type="checkbox" name="discounting21">
There can only be one selected radio button belonging to the same group(ie. name).

Angular ng-model changes to undefined when checkbox on ng-repeat has the required attribute

I have an array of applications. A subset of that array is pushed into another array.
$scope.applicant.selectedApps = [];
$scope.applicant.applications = applications;
angular.forEach(applications, function (application) {
if(application.isSelected){
$scope.applicant.selectedApps .push(application);
}
}
I know have 2 ng-repeats that loop over those arrays:
<div class="row">
<div class="form-group col-sm-10 col-sm-offset-1">
<div class="radio">
<label>
<input type="radio" name="intent" ng-model="applicant.intent" value="Y" required />YES
</label>
</div>
<div class="row" ng-show="applicant.intent == 'Y'">
<div class="col-xs-11 col-xs-offset-1">
<div class="row" ng-repeat="app in applicant.selectedApps">
<div class="col-sm-11 col-sm-offset-1">
<div class="checkbox">
<label>
<input id="Prog{{app.appid}}" name="Progs" type="checkbox" ng-model="app.isSelected" ng-change="appChange(app)" ng-required="applicant.intent == 'Y'" />
{{app.Objective}} - {{app.Name}} - {{app.Description}}
</label>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="form-group col-sm-10 col-sm-offset-1">
<div class="radio">
<label>
<input type="radio" name="intent" ng-model="applicant.intent" value="N" required />NO
</label>
</div>
<div class="row" ng-show="applicant.intent == 'N'">
<div class="col-xs-11 col-xs-offset-1">
<div class="row" ng-repeat="dApp in applicant.applications">
<div class="col-sm-11 col-sm-offset-1">
<div class="checkbox">
<label>
<input id="dProg{{dApp.appid}}" name="dProgs" type="checkbox" ng-model="dApp.isSelected" ng-change="dProgChange(dApp)" ng-required="applicant.intent == 'N' && appCount <= 0" />
{{dApp.Objective}} - {{dApp.Name}} - {{dApp.Description}}
</label>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
the two change functions are as followed:
$scope.dProgChange = function (app) {
if (app.isSelected) {
$scope.appCount++;
} else {
$scope.appCount--;
}
};
$scope.ProgChange = function (app) {
if (app.isSelected) {
$scope.selectedAppCount++;
} else {
$scope.selectedAppCount--;
}
};
What i observe is that every app that was initializes with "isSelected" = false will be set to undefined as soon as the radio button is switched to "NO". When switched back to "YES" is selected switches back to false.
This causes the dProgChange to trigger every time the Radio button value changes.
I can't figure out why the "isSelected" switches to undefined.
UPDATE
While trying to create a simplified example, i noticed that the problem occurs as soon as the checkbox is required.
In the plunker listed bellow, the model value for the checkbox is set to undefined as soon as the checkbox is unchecked. That seems to me the same issue i am having.
http://plnkr.co/edit/SBsdew8tzWdNgNOf6W1c?p=info
This is the way AngularJS (ng-model and NgModelController) is supposed to work.
NgModelController has two properties: $viewValue (value entered by user) and $modelValue (value bound to your model). When the value entered by the user fails validation, NgModelController sets the model to undefined.
In AngularJS 1.3, they added the ng-model-options directive. It lets you configure how/when the model gets updated. You can use the allowInvalid option to prevent your model from being set to undefined:
<input type="checkbox"
ng-model="myModel.value"
ng-model-options="{allowInvalid: true}">
So, I am going to add to this answer for future reference. This applies to <input> also. If you have something such as
<input ng-model="speaker.vrange" ng-blur= "updateSpkV()" type="number" data-placement="right" min ="0" max="10"/>
then you will have an invalid input if you set the value to something outside of the range and the model variable will be set to undefined. This became an issue with me when I directly entered an out of bound value rather than using up/down arrows for adjusting a value.

Angularjs input radio and ng-repeat issue

Okay so here is my setup i have the following array:
answers = [answer1, answer2]
with these i do the following:
<form>
<div class="col-xs-12" ng-repeat="answer in component.question.answers">
<div class="col-xs-1" style="width: 1%">
<div class="radio">
<label class="i-checks">
<input type="radio" name="a" ng-model="answer.is_correct">
<i></i>
</label>
</div>
</div>
<div class="col-xs-11">
<input type="text" ng-model="answer.answer" class="form-control" placeholder="Svar">
</div>
</div>
</form>
Now the input[radio] are inside the same form as they should. My goal is that when i set one as selected both of the answer objects should be updated so that only one of the object has the value is_correct = true
However what happens right now is that if i click the first and then second both values have is_correct = true
So what can i do?
Radio buttons are used to choose between different values for a single field or, in Angular's case, a single model. The logical solution would be to select the correct answer:
<input type="radio" ng-model="component.question.correctAnswer" ng-value="answer">
If you really need to set a flag you can easily achieve that with a watcher:
$scope.$watch('component.question.correctAnswer', function(correctAnswer) {
component.question.answers.forEach(function(answer) {
answer.is_correct = answer === correctAnswer ? true : false;
});
});

Categories