Angular FormGroup - Automatically divide value from another field by 100 - javascript

I have 3 fields in an angular form group and one of the fields is basically a tool for the user that divides the value from another field automatically. So, the user types in a number and the other field automatically displays that value divided by 100.
It looks like this:
formGroup = new FormGroup({
Buildyear: new FormControl(this.buildyear, [Validators.minLength(4), Validators.maxLength(4)]),
Areasize: new FormControl(this.areasize, [Validators.required] ),
Areasize_divided: new FormControl(''),
});
"Areasize_divided" automatically divides the value that's inside "Areasize", by default there's already a value in that field but if the user types in a new value into "Areasize" that should be automatically calculated in "Areasize_divided" as well. And the other way around, if the user types in a value into "Areasize_divided" it will automatically multiply "Areasize" by 100.
What would be the best way of achieving something like this?

You should listen on form control changes and update your other control accordingly.
formGroup.get('Areasize')
.valueChanges
.subscribe(value => formGroup
.get('Areasize_divided')
.setValue(isNaN(value) ? 0 : value / 100)
);

Related

Angular 14: Nested FormGroup not resetting validators

I am trying to implement a nested FormGroup. So far, I am getting error while trying to reset the form. The form structure looks like this:
form: UntypedFormGroup;
this.form = this.fb.nonNullable.group({
f1: [''], f2: this.fb.nonNullable.array([], Validators.required),
f3: this.fb.nonNullable.array([]), f4: this.fb.nonNullable.array([]),
f5: this.fb.nonNullable.group({ id: ['', Validators.required] })
});
I noticed that required validator for the id field is not getting reset while resetting the overall form.
I have a similar project built on Angular 14 but there isn't any nested formgroup. But from my experience and research, I wrote this.form.reset() which is resetting the form with initial value but keeping the valid state of id field as false.
How this can be solved? Also the array fields are getting initialized with NULL even though I have set the formgroup & formarray to not allow NULL.
Current Logic:
this.form.reset();
console.log("Form after reset:", this.form.value);
console.log("Id field valid? ", this.form.get('f5').valid);
Current Output:
Output 1: Form after reset: {"f1":"","f2":[null],"f3":[],"f4":[],"f5":{"id":""}}
Output 2: Id field valid? false
NOTE: Here I only set value of f2 field so it is only having NULL now.
Expected Output:
Output 1: Form after reset: {"f1":"","f2":[],"f3":[],"f4":[],"f5":{"id":""}}
For the second output, the form should just reset to it's initial state as it is marking the mat-form-field associated with the id field as red.
Per documentation, control's value will be reset to initial value, if there is any, and if nonNullable is set to true. nonNullable does not mean that value will never be null, falsy or invalid after reset() call.
In Validator.required() documentation you read that empty field value will trigger invalid state. There is example for zero length string:
const control = new FormControl('', Validators.required);
console.log(control.errors); // {required: true}

Can Tabulator autocomplete be set up per cell? Not column?

I need to have have two autocompletes in my Tabulator definition. A user will select an employee - first autocomplete - then when he moves to select a contract - second column the autocomplete must be linked to the value selected in the first column.
To my knowledge Tabulator does not have such feature. So I was thinking that upon clicking the "contract" cell that column definition - autocomplete definition - would be updated. I cannot make it work because the function updateDefinition is buggy. It creates new column instead of updating its definition.
Working jsFiddle
table.on("cellEditing", function(cell){
//e - the click event object
//cell - cell component
updateTitle(cell)
})
table.on("cellClick", function(e, cell){
updateTitle(cell)
})
function updateTitle(cell){
var field = cell.getField()
if (field == "contract" || field =="id"){
var column = cell.getColumn()
var name = cell.getRow().getData().name
console.log(field)
console.log(name)
column.updateDefinition({title:"Updated Title"})
}
}
I am using MaterializeCSS and its autocomplete but I do not know how to use it inside Tabulator. And if it is actually a good idea.
Could you please suggest the best solution?
In your example you still want to have a different auto complete per column, you just want to make the values of "contract" autocomplete dependent on the value of the "name" column.
You can pass a function into the editorParams option instead of an object, that function will be triggered every time the editor is opened, and should return the params object for the editor.
Using this you can make a function that will changed the values prop of the editor params based on the value of the name cell. in this example we will asume these values are stored in a simple contracts lookup list for a name of each user, but you can look this up however you like
{title:"contract", field:"contract", editor:"autocomplete", editorParams: function(cell){
var contracts = {
bob:["A", "B", "C"],
jim:["D", "E", "F"],
};
return {
values: contracts[cell.getData().name] //set values list based on name cell value
}
}},

RxJs: Have observable triggered by 2 independent observables

I have an observable named "workcentersFiltered" of type Observable<Workcenter[]>
When I select a plant, I can successfully filter down my workcenters with the following code - no problem:
this.workcentersFiltered = this.newLineForm.get('plant').valueChanges
.flatMap(selectedPlant => {
return this.dataStore.Workcenters.map(workcenters => {
return workcenters.filter(x => x.PlantNumber === selectedPlant.PlantNumber);
});
});
The problem is, I would like to narrow that array down furtherly, when an entirely different, independent observable "'workcenter'.valuechanges" emits a string (it is an input field - I am trying to implement autocompletion).
So the question is, how can I subscribe to this.newLineForm.get('workcenter').valueChanges, so that the string-values it emits can be used to furtherly narrow down the data "hidden" within workcentersFiltered (which is already tied to this.newLineForm.get('plant').valueChanges.
Does my dilemma make sense? Must I instead redo workcenteresFiltered as aBehaviorSubject instead, or what is the proper solution here?
editing in more explanation
Currently workcentersFiltered gets data from dataStore.Workcenters, when plant-forminput.valuechanges emits a change, because a plant was selected. So I can narrow down all workcenters to only ones matching the chosen plant. It works fine with the code I have above.
However I would like to introduce a new operation on the sequence between plant-forminput.valuechanges and workcentersFiltered. I would like to narrow the options even further, based on the emission from workcenter-forminput.valuechanges.
So Step 1 on my UI, the user can select a plant from a dropdown and all workcenters from other plants are filtered out - this works.
Then, Step 2 is for the user to chose a specific workcenter. This is a text-input field. I want every letter typed here (which emits on workcenter-forminput.valuechanges), to further narrow down the options (for autocompletion).
I have a difficult time imagining the solution, because the newly introduced observable from step 2 (workcenter-forminput.valuechanges), is only relevant when it emits.
You can use combineLatest for this.
I couldn't follow your full description, so I'll just present an approximate example, which you can hopefully adapt to your specific use case:
workcentersForPlant = this.newLineForm.get('plant').valueChanges
.flatMap(selectedPlant => {
return this.dataStore.Workcenters.map(workcenters => {
return workcenters.filter(x => x.PlantNumber === selectedPlant.PlantNumber);
});
});
const workCenterNameChanges = this.newLineForm.get('workCenterName').valueChanges;
// combine the 2 observables, this will trigger when either observable
// changes. Use the combined values to do the filtering by name
this.workcentersFiltered = Observable
.combineLatest(workcentersForPlant, workCenterNameChanges$)
.map(([workCenters, workCenterName]) => workCenters.filter(w => w.name.startsWith(workCenterName)));

making calculation on property of the scope doesn't work

I'm very very new to Angular js concept so I have trouble with a calculation. I have a form where I'm expecting from user to enter a volume number. I would like to make a calculation and the result of this calculation will be a field for my mongo document. I can create mongo document but my calculation doesn't work. It always insert the original product volume, not the one after the calculation.
This is the object that will be a mongo document. I can fill types and tags array without problem.
$scope.product = {
types: [],
tags: []
};
Form group where I retrieve product volume
.form-group
label.col-sm-3.control-label Volume
.col-sm-4
input.form-control(
ng-model='product.volume',
type='number',
placeholder='Volume')
I have a submit button in my controller. Inside this submit button I'm creating a new product document for mongo and filling the values. I'm also doing my calculation inside this submit function.
var product = new Product($scope.product);
var capacity = 100
$scope.product.volume = (capacity / $scope.product.volume);
Finally after finishing my mongo document, I'm saving it.
product.$save(function ()...
What might be the problem?
It seems like you are creating the Product, and then editing the $scope.product. You should do the transformation on $scope.product.volume before creating the Product.
var product;
var capacity = 100;
$scope.product.volume = (capacity / $scope.product.volume);
product = new Product($scope.product);
product.$save(...);

Javascript validate X number of fields in an HTML form

I have a form, that has about 10 text entries (user, address, email etc;)
and about 50+ entries that are quantity entries (users select 2x of this item, 5x of this item).
Now I inherited this form from someone else (now its my duty to keep it up to date, when the customer requests it).
I don't want to re-write it all, but I would like to add validation for the quantity fields.
Now the quantity fields are all named different things (b1,c55,d,12)
Basically I would like to write a script (but don't know how to search for this, or accomplish this) JS side, that would ignore the tags I know (user, address, email etc;) but check if the others are numbers (either empty - not selected, or 1-99)
Apply a class to the elements (my code uses a class check) like so:
<input type="text" name="b1" class="check" />
and the following jQuery code, which will only check those elements with the check class.
$('#myformid').submit(function(){
$(':input.check').each(function(){
field = $(this);
valInt = parseInt(field.val()); // value as an integer
if (isNaN(valInt) || (valInt < 1 || valInt > 99)) // displays an error if the val is < 1 or > 99
alert('Error in the field ' + field.attr('name') + ': must be number from 1-99'); // change this to whatever you want the form to do if there's an error
});
});
Basically what this does is the following: when the form is submitted, it goes through every field you'd like it to (denoted :input.class to catch each field with the correct class) and checks if it's (a) a number, and (b) less than 1 or greater than 99. If it's a number and is outside the range, it alerts the user of an error. You can change the alert() notification to whatever error management you'd like your form to have.

Categories