Disable input with dynamically generated fields in Angular - javascript

Imagine this:
http://jsfiddle.net/wcuuj8do/9/
My current code:
var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
$scope.rowData = [];
$scope.addRow = function(title, number)
{
$scope.rowData.push({
'title': title,
'number': number
});
};
$scope.addRow('Car', '1200');
$scope.addRow('Car','');
}
When i type "Car" inside first input (T1) and then type some text to input (N1) i want angular to check each T# input if has same value as (T1). If has disable (or readonly) all N# inputs related to currently checked T# input.
Afterwards when i remove duplicated values from T# fields, related T# fields should be returned to default input states (remove disable / readonly)
This should work by adding new dynamic inputs as seen in fiddle.

You should create a method, that will do the checking part. This method will should be bound to blur or change event on T# inputs, depends on what you want.
The method will check for duplicity, and if found, mark the object, e.g. add new property disabled: true. This property will be then used in the template on N# fields via ng-disabled directive.
Here is your update fiddle: http://jsfiddle.net/wcuuj8do/10/
Note the new method $scope.checkDuplicity and new binding:
<tr ng-repeat="(key, item) in rowData">
<td>T{{ ($index+1) }}: <input type="text" ng-model="rowData[key].title" ng-change="checkDuplicity(key)" value="" style='margin-bottom:15px' /></td>
<td>N{{ ($index+1) }}: <input type="text" ng-model="rowData[key].number" value="" style='margin-bottom:15px' ng-disabled="rowData[key].disabled" /></td>
</tr>

Related

Dynamic Forms Angular 2 - Checkbox

I am new in Angular 2. I am trying to expand dynamic forms according to https://angular.io/guide/dynamic-form. I did input radios and work as I need. But now I am trying to do checkboxes, but there is a problem. I have a group of checkboxes and I get only boolean value, if some checkbox is checked. Bud I need values, which checkboxes is checked. There is my plunker: https://plnkr.co/edit/EhtpprYdXIFmYJG7Lzxg
Thanks for help!
I hope this would be the solution for you.
templet.html
<form [formGroup] = "myForm" (ngSubmit) = "confirmFlights(myForm.value)">
<ng-template ngFor [ngForOf]="flightList" let-flight let-i="index" >
<input type="checkbox" [value]="flight.id" formControlName="flightid"
(change)="flightids[i]=[$event.target.checked,$event.target.getAttribute('value')]" >
</ng-template>
</form>
component.ts
flightids array will have another arrays like this
[ [ true, 'id_1'], [ false, 'id_2'], [ true, 'id_3']...]
here true means user checked it, false means user checked then unchecked it.
The items that user have never checked will not be inserted to the array.
flightids = [];
confirmFlights(value){
//console.log(this.flightids);
let confirmList = [];
this.flightids.forEach(id => {
if(id[0]) // here, true means that user checked the item
confirmList.push(this.flightList.find(x => x.id === id[1]));
});
//console.log(confirmList);
}
Why it isn't working:
because you are using one formControl key (question.key === 'skills') for all 3 checkboxes.
<span *ngSwitchCase="'checkbox'">
<p *ngFor="let opt of question.options">
<input [formControlName]="question.key"
[id]="opt.key" type="checkbox" [value]="opt.key">
<label>{{opt.value}}</label></p>
</span>
How to deal with it:
You should use formControl key for each input (checkbox), to track model changes - this is how Angular forms works.
So, if you split your Checkbox.options to separate Checkbox, it would work:
in dynamic-form-question.component.html change Checkbox to:
<span *ngSwitchCase="'checkbox'">
<input [formControlName]="question.key"
[id]="question.key" type="checkbox" [value]="question.value">
</span>
in question.service.ts change Checkbox to:
new CheckboxQuestion({
key: 'fast',
label: 'Fast',
value: false,
order: 5
}),
Here is changed Plunker:
https://plnkr.co/edit/2XIfMU?p=preview
A checkbox or radio doesn't update automatically (at this point I'm not sure if this is caused by angular design or possibly due to MDN: DOM input event).
The usage of a template reference variable works but only for one FormControl within a FormGroup.
More elegant solution: you can set a FormControl's value (in a FormGroup) directly from the change event:
(change)="formGroup.controls[element.name].setValue($event.target.checked)"
Since FormControl.setValue's emitEvent, emitModelToViewChange and emitViewToModelChange default to true, it's seems not necessary to update other attributes manually.
Modified for angular's dynamic form (working example on stackblitz):
<input *ngSwitchCase="'checkbox'" [formControlName]="question.key"
[id]="question.key" [type]="question.type" (change)="form.controls[question.key].setValue($event.target.checked)">

Angular UI-Bootstrap Typeahead: Accept top item as selected on ENTER

Simple question, but is there a way to have the first item in the dropdown results be the selected item when ENTER is pressed?
An example of this is the user types in "PC0" and sees "PC001" listed as the first option, can we have it use "PC001" on the typeahead-on-select option when ENTER is hit?
I am currently using typeahead-on-select to run a function that calls the input via id and grabs the Value for use in the function. It seems to use what was entered into the textbox instead of the selected value, either on ENTER or Click.
HTML:
<input id="applicationComboBox"
type="text"
ng-model="applicationComboBox"
uib-typeahead="a as a.Value for a in applicationList | filter:$viewValue"
typeahead-on-select="getApplication()"
class="form-control">
JS for the getApplicationValue() looks like this:
$scope.getApplication = function () {
$scope.ApplicationValue = applicationComboBox.value;
}
The issue is the applicationComboBox.value is what text the user has typed into the input at the time of the click/enter instead of the clicked/highlighted value respectively. So in previous example "PC0" would be the value instead of "PC001".
When the user selects/press enter the ng-model applicationCombox is is updated automatically. If you want another value $scope.ApplicationValue to be updated after the selection, do the following
$scope.applicationCombox = ""; //your existing model.
$scope.getApplication = function () {
$scope.ApplicationValue = $scope.applicationCombox;
}
Let us know.
I was able to get a solution that worked for me.
HTML:
<input id="applicationComboBox"
type="text"
ng-model="applicationComboBox"
uib-typeahead="a as a.Value for a in applicationList | filter:$viewValue"
typeahead-on-select="onApplicationSelect($item, $model, $label, a)"
class="form-control">
JS:
$scope.onApplicationSelect = function (item, model, label, application) {
applicationComboBox.value= item.Value;
}

How to capture the value of a textbox from an OnChange event

In my C# MVC app, I have a series of textboxes that are generated as such...
#foreach (object item in items)
{
#Html.TextBox(....)
}
The rendered result is a series of text boxes that look like this....
<input class="item-quantities valid" data-bomid="1939" data-rid="2054" id="AddedItemIDs_1939_" name="AddedItemIDs[1939]" onchange="ChangeItemQuantity(156,78)" onkeypress="return isNumberKey(event)" type="text" value="7" aria-invalid="false">
<input class="item-quantities valid" data-bomid="1940" data-rid="1055" id="AddedItemIDs_1940_" name="AddedItemIDs[1940]" onchange="ChangeItemQuantity(159,90)" onkeypress="return isNumberKey(event)" type="text" value="1">
Now, I need a javascript / jquery function in which I can capture three values:
bomid
rid
the new value of the textbox
I am just fine capturing the value when the textbox loses focus (tab out, etc.)
I have tried this (WITHOUT onchange="ChangeItemQuantity()" in the textbox), but for some reason I can never get this event to fire. Plus, I'd rather NOT do it this way, because then I am forced to be rigid on what classes I assign to the textboxes....
$(function () {
$('.item-quantities.valid').change(function () {
var value = $(this).val();
var bomid= $(this).data('bomid');
var rid= $(this).data('rid');
});
});
And I have tried this (WITH onchange="ChangeItemQuantity(159,90)" in the textbox). I would RATHER do it this way, as it allows me to be flexible with the classes in the text box...
function ChangeItemQuantity(bomid, rid) {
// no idea how I would capture the value here.
}
Add another argument to the function to pass the element in and get it's value:
onchange="ChangeItemQuantity(156,78, this)"
function ChangeItemQuantity(bomid, rid, el) {
alert(el.value)
}
You could fetch the attribute's value like this,
function getValues(){
var actual=$(this).value;
var bomid=$(this).attr('bomid');
var rid=$(this).attr('rid');
}

Angular form with dynamic input values

I am having issues with angular not picking up the dynamic values from my inputs.
This is what I'm trying to do. When a user clicks on map, the angular populates the hidden form fields with lat/lon, and the user then submits the form, which ends up missing data on the controller.
Here is the relevant controller code :
$scope.formData = {};
$scope.submit = function(addressform) {
addressService.createAdddress($scope.formData).then(function(result) {
$scope.addressResponse = result;
}, function(err) {
alert(err);
});
}
$scope.userSelectedPoint = function () {
$scope.lat = map.getLat();
$scope.lon = map.getLon();
$scope.address = map.getAddress();
}
This is the relevant HTML :
<form id="address_form" name="addressform" ng-submit="submit(addressform)">
<input "lattitude" name="lattitude" type="hidden" ng-model="formData.lattitude" value="{{lat}}">
<input id="longitude" name="longitude"type="hidden" ng-model="formData.longitude" value="{{lon}}">
<p>Selected Address: {{address}}</p>
</form>
Everything looks ok in the chrome inspector(random point on a map) :
However when I submit this form and print out a $scope.formData I get an empty object:
$scope.formData
Object {}
What am I doing wrong here? Why is the formData in my controller empty, when obviously the value is set in the HTML as it can be seen from the screenshot I pasted?
you need to assign the values to ng-model variable, not to the value
as
<input "lattitude" name="lattitude" type="hidden" ng-model="formData.lattitude" />
<input id="longitude" name="longitude"type="hidden" ng-model="formData.longitude" />
assign the value to formData.lattitude.
$scope.formData = {};
$scope.userSelectedPoint = function () {
$scope.formData.lattitude = map.getLat();
$scope.formData.longitude = map.getLon();
$scope.formData.address = map.getAddress();
}
in angular if you provide a value to a variable and u assign that variable to input using ng-model then the input is getting the value of variable, anf if we change input value variable value gets change.
so your assign the lattitude property of formData object to a input. that means if you change the $scope.formData.lattitude input value gets change.
In angular you can't use the value property. You have to initialize the formData object with longitude/lattitude. And therefore you also need any fake hidden field. You don't need this pattern in Angular.

Using an array of ng-model

I am new to AngularJS. In my scenario, the user has to create a mcq question. The question has 4 default option and one of the options is correct. Now the user who is teacher can give greater or less then 4 options for the question. So its a variable number of options. If hard code the input as follow
<input name = "input0" type = "text", class = "form-control" ng-model = "input_0" required>
<input name = "input1" type = "text", class = "form-control" ng-model = "input_1" required>
and so on it works good. I want to use dynamic solution here, so it does not matter how many options the teacher provide.
What I was trying to do is
$scope.mcq_options = [$scope.input_0,$scope.input_1 ...]
use ng-repeat in html template and do something like
<div ng-repeat = "input in mcq_options">
<input name = "input1" type = "text", class = "form-control" ng-model = "input" required>
For removing splice entry from array
For adding more push entry in array
The solution is quite straightforward (Associated PLUNKER):
1 Create an empty array that you may store all your options, in your controller.
var inputArray = $scope.inputArray = [];
[2] Create a function to add new options.
$scope.addNewOption = function() {
inputArray.push('');
};
[3] Create another function to splice an option entry that accepts the index of an option to remove.
$scope.removeOption = function(index) {
inputArray.splice(index, 1);
};
[4] Your view can be something like this:
<form name="form" novalidate>
<div ng-repeat="input in inputArray track by $index" ng-form="subform">
<input name="input" type="text" ng-model="inputArray[$index]" required> <button ng-click="removeOption($index)">Remove</button>
<br>
<span ng-show="subform.input.$error.required">This field is rqeuired</span>
</div>
<button ng-click="addNewOption()">Add New Option</button>
</form>
Note:
The track by $index in the ng-repeat directive helps in avoiding duplicate values error.
The ng-form directive helps you in validating each models that is created in every ng-repeat iteration.
Instead of using the input value in the ng-repeat directive, use its direct reference by using the ng-repeat's $index property. If you dont't do this, changes in the inputArray may affect the current ngModel reference of your inputs. e.g. adding or removing options will give you weird behaviours.

Categories