Managing a Reactive Form value and the value is an object - javascript

I have an Array I'm getting from the server, which contains Objects like this:
[
{LanguageName: 'English', ID : 2},
{LanguageName: 'Dutch', ID : 1},
{LanguageName: 'portuguese', ID: 3},
]
I'm handling this by by creating a Form-Array.
My Issue:
I want that if the user changes this input, it will change only the property of the Name, something like: anyFormName.controls.value.LanguageName, and not replacing the whole value altogether to a string, so insted of end up getting :
anyFormName.controls.value = "User's Input"
, I'll get:
anyFormName.controls.value = {LanguageName: "User's Input", ID : 2}
I've worked around this issue before with setValue() to the specific control, and saving the data in another array so I can compare the position by the indexes of the form Array. seems to me there probably be a better way...
thanks a lot!

Tal, in general you'll get a formArray like
<div *ngIf="myFormArray" [formGroup]="myFormArray">
<div *ngFor="let item of myFormArray.controls; let i=index" [formGroupName]="i">
<input formControlName="ID">
<input formControlName="LanguageName">
</div>
</div>
{{myFormArray?.value|json}}
//Or
<div *ngIf="myForm" [formGroup]="myForm">
<div formArrayName="data">
<div *ngFor="let item of myForm.get('data').controls; let i=index" [formGroupName]="i">
<input formControlName="ID">
<input formControlName="LanguageName">
</div>
</div>
</div>
{{myForm?.value|json}}
where you has some like
myForm:FormGroup
myFormArray:FormArray;
values=[
{LanguageName: 'English', ID : 2},
{LanguageName: 'Dutch', ID : 1},
{LanguageName: 'portuguese', ID: 3},
]
ngOnInit() {
this.myForm=this.fb.group({
data:this.fb.array(this.createFormArray(this.values))
})
this.myFormArray=this.fb.array(this.createFormArray(this.values));
}
createFormArray(values:any):FormGroup[]
{
return values.map(x=>{
return this.fb.group(
{
LanguageName:x.LanguageName,
ID:x.ID
}
)
})
}
Just not include the input formControlName="ID"

As long as I understand you properly, you're trying to change the form control name instead of its value. That can be accomplished by this method:
changeFormFieldName(oldField: string, newField: string): void {
var newControls: {[key: string]: FormControl} = {};
Object.keys(this.form.controls).map((field: string) => {
if (field==oldField) {
newControls[newField] = this.form.controls[field];
} else {
newControls[field] = this.form.controls[field];
}
});
this.form = new FormGroup(newControls);
}
assuming your form group object is under this.form.

Related

Console.log shows my element as an array instead of an element

I'm doing a view where the customer is able to edit items, it comes with a filter so he/she can select between the options given. Everytime I edit it and save it works, however, if I return to the edit section the text box is empty and even though it was saved. If i use the inspect tool, the Console shows this:
impuestos_compra: Array [ {…} ]
If I open it, this is the information displayed:
impuestos_compra: (1) […]
"$$hashKey": "object:87"
0: Object { id: 2, empresa_id: 6, nombre: "IVA", … }
​​
length: 1
​​
<prototype>: Array []
This is the <DIV> label where I display this:
<div class="form-group col-md-6">
<label>
Impuestos de Mario
</label>
<select ng-model="articulo.impuestos_compra" name="impuestos_compra" class="form-control input-lg" required>
<option value="">Seleccione impuesto de compra</option>
<option ng-repeat="item in impuestos_compra" value="#{{ item.abreviacion }}">#{{ item.abreviacion }}</option>
</select>
</div>
In my try to iterate it, I did this code:
impuestos_compra = ['IVA' , 'IVAT0' ];
impuestos_compra.forEach(function(impuestos_compra) {
console.log(impuestos_compra);
});
And, finally, the controller from Laravel with the edit function looks like this:
public function edit($id)
{
$articulo = Articulo::with('sat_producto:clave,descripcion', 'sat_unidad:clave,descripcion')->findOrFail($id);
return view('panel.configuracion.articulo', [
'id' => $id,
'presentaciones' => Presentacion::select('nombre')->get()->toArray(),
'impuestos_compra' => Impuesto::select('abreviacion')->where('tipo' , 'compra')->get(),
]);
What am'I doing wrong? I tried ->get()->toArray() and it works neither.
Thanks in advance.
I think the problem is in your impuestos_compra initialization. You can try pluck instead of select. Pluck returns the value of the column as a collection. Try the following code.
public function edit($id)
{
$articulo = Articulo::with('sat_producto:clave,descripcion', 'sat_unidad:clave,descripcion')->findOrFail($id);
return view('panel.configuracion.articulo', [
'id' => $id,
'presentaciones' => Presentacion::select('nombre')->get()->toArray(),
'impuestos_compra' => Impuesto::where('tipo' , 'compra')->pluck('abreviacion')->toArray(),
]);
}

How to push array of string in formArray?

I need to create this:
instructions: ['value one' , 'value two' , 'value three'];
I am using formArray and check my code on stackblitz first:
https://stackblitz.com/edit/formarray-obj?file=app/app.component.ts
html:
<div class="form">
<form id="form" [formGroup]="filmForm" (ngSubmit)="save()">
<button type="button" (click)="addItem()"> add new row</button>
<div formArrayName="instructions" *ngFor="let a of filmForm.get('instructions').controls; let i = index">
<div [formGroupName]="i" style="margin-bottom: 10px;">
<label for="name">Name:</label>
<input type="text" name="name" formControlName="instructions">
<br><br>
</div>
</div>
<div class="submit">
<button type="submit">Save</button>
</div>
</form>
</div>
TS:
registerForm: FormGroup;
submitted = false;
instructions: FormArray;
filmForm: FormGroup;
constructor(private formBuilder: FormBuilder) { }
ngOnInit() {
this.filmForm = this.formBuilder.group({
instructions: this.formBuilder.array([this.createItem()])
})
}
createItem() {
return this.formBuilder.group({
instructions: ['']
})
}
addItem() {
this.instructions = this.filmForm.get('instructions') as FormArray;
this.instructions.push(this.createItem());
}
save() {
console.log(this.filmForm.value)
}
I am sending array of object: check stackblitz console.log
I am send like
instructors = [{instructs : 'value one'} , {instructs : 'value one'}..]
But I need to sent:
instructors = ["value one" , "value two"];
There are two ways in which you go ahead with this.
1 - Using .map in save()
For the desired output, you can use the .map in save() function:
save() {
const instructions = this.filmForm.value.instructions.map(inst => inst. instruction);
console.log(instructions);
}
Desired Output will be:
["value one" , "value two"]
2 - Using a tags input control like ng-select
Your use case looks like a tags control use case for instructions.
There is a popular library #ng-select/ng-select which has a tags control.
You can see the usage of this library for your use case on this stackblitz.
Approach 1 is the easiest one to do but I would suggest you use tags control in approach 2 for good user experience.
You can try this.. i had the same issue.
Make the Form
form = new FormGroup({
instructorsArray: new FormArray([]),
})
get instructors(): FormGroup {
return FormControl('')
}
addInstructors() {
this.instructors.push(this.instructors);
}

AngularJS ng-repeat questions and init inputs with matching answer object

I am using an ng-repeat to repeat through questions provided by an ajax response and I need the ng-model of each question input to point to a separate answers array.
The question array looks like this
bookingQuestions: [
0: {
label: 'Any allergies?',
type: 'text',
id: 1234
},
1: {
label: 'Names of attendees',
type: 'text',
id: 1235
}
]
I create the answers array by looping through all the questions and pushing the id and an empty answerValue property into my empty bookingAnswers array. The answers array looks like this:
bookingAnswers: [
0: {
id: 1234,
answerValue: ''
},
1: {
id: 1235,
answerValue: ''
}
]
In the markup, I'm attempting to init the answerObj by getting the correct answer object to match the corresponding question.
<div class="question" ng-repeat="question in bookingQuestions">
<label class="question-label" for="{{question.id}}">{{question.label}}
</label>
<input type="text" name="{{question.id}}" ng-model="answerObj"
ng-init="answerObj = getAnswerObj(question)">
</div>
The JS function:
$scope.getAnswerObj = function(question) {
angular.forEach(bookingAnswers, function(answer) {
if(question.id === answer.id) {
return answer.answerValue;
}
});
}
Even though the JS function successfully returns the correct object property, the ng-model isn't being updated to use it. How do I get this working?
You bind the ng-model of all your inputs to some answerObj meaning they all point to the same variable. Using $index you can access the index of the current iteration. So you could do something like this:
<input type=“text“ name="{{question.id}}"
ng-model="bookingAnswers[$index].answerValue"> </div>
<div class="question" ng-repeat="question in bookingQuestions">
<label class="question-label" for="{{question.id}}">{{question.label}}
</label>
̶<̶i̶n̶p̶u̶t̶ ̶t̶y̶p̶e̶=̶"̶t̶e̶x̶t̶"̶ ̶n̶a̶m̶e̶=̶"̶{̶{̶q̶u̶e̶s̶t̶i̶o̶n̶.̶i̶d̶}̶}̶"̶ ̶n̶g̶-̶m̶o̶d̶e̶l̶=̶"̶a̶n̶s̶w̶e̶r̶O̶b̶j̶"̶
<input type="text" name="{{question.id}}" ng-model="answerObj.answerValue"
ng-init="answerObj = getAnswerObj(question)" />
</div>
$scope.getAnswerObj = function(question) {
angular.forEach(bookingAnswers, function(answer) {
if(question.id === answer.id) {
̶r̶e̶t̶u̶r̶n̶ ̶a̶n̶s̶w̶e̶r̶.̶a̶n̶s̶w̶e̶r̶V̶a̶l̶u̶e̶;̶
return answer;
}
});
}

select - populate when editing post

I have my angularjs view in wich I must populate my select box with value saved in database, and to allow for other options to be selected. I have tryed like this:
<div class="form-group">
<label class="control-label" for="status">Status zaposlenika</label>
<div class="controls">
<select required name="status" class="form-control" ng-model="employee.status" ng-options="statusType.name for statusType in statusTypes" >
</select>
</div>
But my value is not populated in my view. ( {{employee.status}} - > "test" )
$scope.statusTypes = [
{
name: 'test'
},
{
name:'Test1'
},
{
name: 'Test2'
},
{
name:'Test3'
}
];
How can I do this ?
EDIT
My model employee.status is populated with value "test". But my select box is not. Othe values are listed as items for selection. How can I set default value that is saved in my database to be pre-selected in my select box.
Your model employee.name is a string and selectbox is bound to an object similar to {name: "Test1"}. So if you want to select option from statusTypes you have to find corresponding object in array of object.
$scope.statusTypes = [
{name: 'Test1'},
{name: 'Test2'},
{name: 'Test3'}
];
var selectedStatus = $scope.statusTypes.filter(function(type) {
return type.name = 'Test2';
})[0];
$scope.employee = {
status: selectedStatus
};
So you have to make employee.status to be one of the objects from statusTypes array.
Or other option is to continue to use string for employee.status and change ngOptions to bind to a string instead of object:
ng-options="statusType.name as statusType.name for statusType in statusTypes"

Filter by property of a object that is a property

I have an array of objects set up something like this:
$scope.people = [{name:
{last:"Doe", first:"John"}},
{name:
{last:"Smith", first:"Joe"}}];
and I'm trying to do a live filter by text box of last names.
Here's the jsfiddle: http://jsfiddle.net/HB7LU/4287/
Any help would be nice. Thank you!
Edit: sorry I put in the wrong jsfiddle
Taking your fiddle as starting point, I'd say:
HTML
<div ng-controller="MyCtrl">
<input ng-model="search" ng-init="search = ''" placeholder="enter search" />
<div ng-repeat="person in people | filter:{name.last: search}">
{{ person | json }}
</div>
</div>
JS
var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
$scope.people = [{ name: { last: 'Doe', first: 'John' } },
{ name: { last: 'Smith', first: 'Joe' } }];
}
Here's the plunker http://plnkr.co/edit/W46Fkj
So create a filter!
Building off your existing code:
myApp.filter("search", function() {
return function(people, startPhrase) {
if(!startPhrase) {
return people;
}
var filtered = [];
for(obj in people) {
if(people[obj].name.last.indexOf(startPhrase) == 0) {
filtered.push(people[obj]);
}
}
console.log(filtered);
return filtered;
}
});
Now, you can use a filter called "search" anywhere in the HTML. Call it like this:
<div ng-controller="MyCtrl">
<input ng-model="search.name.last"/>
<div ng-repeat="person in people | search:search.name.last">
{{person.name.last}}, {{person.name.first}}
</div>
</div>

Categories