How to update parent component when using MatDialog in angular? - angularjs

I need to pass data from a dialog, back to the parent component.
I found the same question from another user, but I cant get mine to work, but I cant get the thing to work:
Angular 6 - MatDialog - EventEmitter - share object to parent component from MatDialog
here is the parent html:
<button mat-raised-button color="accent" type="button" (click)="openDialog()">Open </button>
here is the parent ts:
openDialog(){
console.log('openDialog')
this.dialog.open(EditChannelFieldsComponent,
{
width:'50%',
data: "right click"
})
}
here is the childs html:
<form [formGroup]="form" (submit)="onSaveChannelFields()" *ngIf="!isLoading">
<mat-form-field>
<input matInput type="text" formControlName="name" placeholder="Data name">
<mat-error *ngIf="form.get('name').invalid">Please enter data name.</mat-error>
</mat-form-field>
<mat-form-field>
<input matInput type="text" formControlName="description" placeholder="Data description">
<mat-error *ngIf="form.get('description').invalid">Please enter data description.</mat-error>
</mat-form-field>
<button mat-raised-button color="accent" type="submit">Save Channel</button>
</form>
here is the child ts:
onSubmitReason = new EventEmitter();
form: FormGroup;
ngOnInit() {
this.initializeFormAndItsFields();
}
initializeFormAndItsFields() {
this.form = new FormGroup({
name: new FormControl(null, {
validators: [Validators.required]
}),
description: new FormControl(null,{
validators:[Validators.required]
}),
});
}
onSaveChannelFields(){
this.onSubmitReason.emit("selectedIssue");
}
I know am close but I can't pin point the issue.
any help is appreciated!

here is the solution that worked
parent ts:
const dialogRef = this.dialog.open(EditChannelFieldsComponent);
const subscribeDialog = dialogRef.componentInstance.onSubmitReason.subscribe((data) => {
this.channelFields = [...this.channelFields, data];
});
dialogRef.afterClosed().subscribe(result => {
subscribeDialog.unsubscribe();
});
child ts:
onSaveChannelFields() {
console.log('emitting data')
const formData = { name: this.form.value.name, description: this.form.value.description };
this.onSubmitReason.emit(formData);
}

Related

Display more than one object from array on Angular Update CRUD Form

I am currently able to edit all data from my update CRUD form except for the dynamic nested array (called 'mitigations') that only returns the first object on my form. I have 4 objects, but it's only showing 1 out of 4, and I want the end user to be able to edit all of them through the same form they originally created. I also want them to be able to add new mitigations or remove existing ones as they can with the create CRUD form.
Please let me know what I'm missing. Thanks.
edit.component.ts
export class EditComponent implements OnInit {
getId: any;
updateForm: FormGroup;
constructor(
public formBuilder: FormBuilder,
private router: Router,
private ngZone: NgZone,
private activatedRoute: ActivatedRoute,
private crudService: CrudService
) {
this.getId = this.activatedRoute.snapshot.paramMap.get('id');
this.crudService.GetRisk(this.getId).subscribe(res => {
this.updateForm.setValue({
...
mitigations: res['mitigations']
});
});
this.updateForm = this.formBuilder.group({
...
mitigations: this.formBuilder.array([])
})
}
addMitigation() {
let control = <FormArray>this.updateForm.controls.mitigations;
control.push(
this.formBuilder.group({
mitigation_description: ['', Validators.compose([Validators.required, Validators.minLength(10)])],
mitigation_option: ['', Validators.required]
})
)
}
removeMitigation(index) {
let control = <FormArray>this.updateForm.controls.mitigations;
control.removeAt(index)
}
ngOnInit() {
let control = <FormArray>this.updateForm.controls.mitigations;
control.push(
this.formBuilder.group({
mitigation_description: ['', Validators.compose([Validators.required, Validators.minLength(10)])],
mitigation_option: ['', Validators.required]
})
)
}
onUpdate(): any {
this.crudService.updateRisk(this.getId, this.updateForm.value)
.subscribe(() => {
console.log('Data updated successfully!')
this.ngZone.run(() => this.router.navigateByUrl('/risk/details'))
}, (err) => {
console.log(err);
});
}
}
edit.component.html
<div class="card-body widget-body">
<form [formGroup]="updateForm" (ngSubmit)="onUpdate()">
<div formArrayName="mitigations">
<div *ngFor="let mitigation of updateForm.get('mitigations')['controls']; let i=index">
<div [formGroupName]="i">
<div class="form-group">
<label for="textarea">Mitigation {{i+1}} Description</label>
<textarea class="form-control form-control-sm checking-field" formControlName="mitigation_description" required></textarea>
<span class="help-block" *ngIf="mitigation.get('mitigation_description').touched">
<span class="text-danger" *ngIf="mitigation.get('mitigation_description').hasError('required')">Description is required</span>
<span class="text-danger" *ngIf="mitigation.get('mitigation_description').hasError('minlength')">Minimum of 10 characters</span>
</span>
</div>
<div class="form-group">
<label for="select">Mitigation {{i+1}} Option</label>
<select class="form-control form-control-sm checking-field" formControlName="mitigation_option">
<option>Accept</option>
<option>Transfer</option>
<option>Reduce</option>
<option>Avoid</option>
</select>
<span class="help-block text-danger" *ngIf="mitigation.get('mitigation_option').touched && mitigation.get('mitigation_option').hasError('required')">Option is required</span>
</div>
</div>
<div class="form-group">
<button type="button" class="btn-sm btn-main" (click)="addMitigation()">Add Mitigation</button>
<button [hidden]="i == 0" type="button" class="btn-sm btn-danger pull-right" (click)="removeMitigation(i)">Remove Mitigation {{i+1}}</button>
</div>
</div>
</div>
</form>
</div>
I got it working with the help of a developer. This is what the working constructor looks like:
constructor(
public formBuilder: FormBuilder,
private router: Router,
private ngZone: NgZone,
private activatedRoute: ActivatedRoute,
private crudService: CrudService
) {
this.getId = this.activatedRoute.snapshot.paramMap.get('id');
this.crudService.GetRisk(this.getId).subscribe(res => {
const mitigations = this.updateForm.get('mitigations') as FormArray;
while (mitigations.length) {
mitigations.removeAt(0);
}
this.updateForm.patchValue(res);
res.mitigations.forEach(mitigation =>
mitigations.push(this.formBuilder.group(mitigation)));
this.updateForm.setValue({
...
mitigations: res['mitigations']
});
});
this.updateForm = this.formBuilder.group({
...
mitigations: this.formBuilder.array([])
})
}

Trying to add a new element to array of objects but after successfully pushing 1st object in Array(users). it rewrites it again

I have a array of objects(users) where 2 elements in array are already hardcoded.While inserting new elements in array it overwrites the same element again & again.
I am trying to get new elements in my array every time I click Submit button.
Here is my code:
File users.component.ts
import { User } from './../Model/user';
import { Component, OnInit,ViewChild } from '#angular/core';
import { getMaxListeners } from 'process';
#Component({
selector: "app-users",
templateUrl: "./users.component.html",
styleUrls: ["./users.component.css"],
})
export class UsersComponent implements OnInit {
users?: User[] = [
{
name: "test1",
email: "test#gmail.com",
},
{
name: "test2",
email: "test2#gmail.com",
}
];
addUserData: User = { name: null, email: null };
bannerMsg: string = null;
constructor() {}
ngOnInit() {}
addUser(addUserData) {
this.users.push(addUserData);
}
onSubmit(e) {
console.log(
"user data :" + this.addUserData.name + " " + this.addUserData.email
);
this.addUser(this.addUserData);
this.users.forEach(item => {
console.log("\n userObject"+ " "+ item.name+ "" + item.email);
});
}
}
File users.component.html
<form (ngSubmit)="onSubmit('usersForm')" class="form-group" class="solidBorderWithPadding" class="container" >
<div>
<label for="firstName">First Name </label>
<input required minlength="3" [(ngModel)]="addUserData.name" name="firstName" type="text" id="firstName" class="form-control" class='form-control'>
</div>
<div>
<label for="email">Email </label>
<input required minlength="3" [(ngModel)]="addUserData.email" name="email" type="email" id="email" class="form-control" class='form-control'>
</div>
<button class="btn btn-primary" type="button" (click)='onSubmit()'>Submit</button>
</form>
<ul>
<li *ngFor="let user of users">
Name : {{ user.name }}
Email : {{ user.email}}
</li>
</ul>
Calling push will not copy your object, because JavaScript Objects are passed by reference: you're pushing the same Object as the array entry.
You can fix this easily by creating a new addUserDataObject every time you try to push one into the array.
Creating a clone of the User object solves this problem
addUser(addUserData) {
var newobj = Object.assign({}, addUserData); //new code
this.users.push(newobj);
}

patchValue returning only values of the last index

I have an issue while looping through and array, I'm getting all the index from this array correctly but when I use angular patchValue it updates all the inputs with the last index values and not with their respective values as shown :
I want every input to have theirs, for example, first input values should be "1" (left input => longueur) and "1" (right input => quantity)
I tried with .forEach but no success
CODE SAMPLE
component.ts .forEach
ngOnInit() {
this.requiredFields();
this.service.checkExistQuot().subscribe(res => {
this.quotDetails.forEach( (myArray, index) => {
this.dropForm.patchValue({
longueur: this.quotDetails[index].longueur,
quantity: this.quotDetails[index].quantity
})
console.log(index);
});
});
}
HTML, input example
<div class="products">
<div class="d-flex flex-row" *ngFor="let products of selectedDiam;let i = index">
<input class="number" formControlName="longueur" value="" (change)="postQuotationDatas(products.part_id)" type="number">
</a>
<input class="mb-1 flex1 checkbox" type="checkbox">
<a class="tac flex1"></a>
<a class="flex1 mb-1">
<input class="number" value="" formControlName="quantity" (change)="postQuotationDatas(products.part_id)" type="number">
</a>
<a class="flex1"></a>
</div>
</div>
Your problem is that you only have one form group,dropForm, with 2 controls: quantity and longueur. Even though you have multiple html inputs for longueur and quantity, they are share the same reference in the component
So, with your forEach loop, you are actually patching all your controls for each iteration. That's why you have the same value for all your controls, which is the value for the lasst object the loop went over.
Option #1
A possible solution is to have multiple form groups, like in this stackblitz example
component.ts
//dropForms initialisation
this.quotationDetails.map(() =>
{
let group = this.formBuilder.group(
{
longueur: [''],
quantity: [''],
});
this.dropForms.push(group)
}
this.quotationDetails.forEach( (myArray, index) => {
this.dropForms[index].patchValue({
longueur: this.quotationDetails[index].longueur,
component.html
<div class="d-flex flex-row" *ngFor="let products of quotationDetails; let index=index">
<form [formGroup]="dropForms[index]"> <!-- 1 form group per quotation -->
Option #2
The other solution, to have only 1 formGroup, is to give dynamic control names
component.ts
//Initialisation of dropForm
this.quotationDetails.forEach((val, index)=>
{
group[`longueur_${index}`] = '';
group[`quantity_${index}`] = ''
});
this.dropForm = this.formBuilder.group(
group
)
//Patch
this.quotationDetails.forEach( (myArray, index) => {
let patchValue = {};
patchValue[`longueur_${index}`] = this.quotationDetails[index].longueur;
patchValue[`quantity_${index}`] = this.quotationDetails[index].quantity;
this.dropForm.patchValue(patchValue);
component.html
<form [formGroup]="dropForm">
<div class="products">
<div class="d-flex flex-row" *ngFor="let products of quotationDetails; let index = index">
<a>
<input class="number" formControlName="longueur_{{index}}" value="" type="number">
Stackblitz example
Use FormArray and wrap inputs in arrays.
Example add FormControl to FormArray with FormBuilder:
FormArray - A FormArray aggregates the values of each child FormControl into an array.
in componenent ts:
const EMPLOYEE_FORM = {
firstName: ['', Validators.required],
lastName: ['', Validators.required],
isActive : [false, Validators.required]
}
const COMPANY_FORM = {
employees: new FormArray([], [Validators.required])
}
export class AppComponent {
form: FormGroup;
constructor(private fb: FormBuilder) {
this.form = this.fb.group(COMPANY_FORM);
}
get employees(): FormArray {
return this.form.get('employees') as FormArray;
}
addEmployee() {
const employee = this.fb.group(EMPLOYEE_FORM);
this.employees.push(employee);
}
}
in html
<div *ngFor="let item of employees.controls; let i = index;">
<form [formGroup]="item">
<input type="text" formControlName="firstName" class="form-control" placeholder="FirstName">
<input type="text" formControlName="lastName" class="form-control" placeholder="LastName">
<input class="checkbox" type="checkbox" formControlName="isActive">
</form>
</div>
<button (click)="addEmployee()">add new employee</button>
<div *ngIf="employees.length > 0">
{{employees.value | json}}
</div>
See this link: https://stackblitz.com/edit/add-input-to-formarray-with-frombuilder

Data not showing up and sbmit button not working correctly MEAN stack

Working on a demo project (trying to learn MEAN stack) and I am not sure what it is, but I can't get the data to output.
Can someone see if I have misspelled or misnamed a file? Also, the submit button submits the data even if the form isn't filled out.
Post-create.component.html
<h2 align = "center">Fill Out the Form Below: </h2>
<!-- How to comment -->
<mat-card style="margin:1;" style="width: 37%">
<form (submit)=onAddName() class="information-form" #postForm="ngForm">
<mat-form-field class = "information-full-width">
<input
matInput
placeholder="First name"
name="first"
ngModel
required
#first="ngModel">
<mat-error *ngIf="first.invalid">First Name is <strong>required</strong></mat-error>
</mat-form-field>
<mat-form-field class = "information-full-width">
<input
matInput
placeholder="Last Name"
name="last"
ngModel
required
#last="ngModel">
<mat-error *ngIf="last.invalid">Last Name is <strong>required</strong></mat-error>
</mat-form-field>
<p>
<mat-form-field class = "information-full-width">
<input
matInput
placeholder="Email"
[formControl]="emailFormControl"
name="email"
ngModel
required>
<mat-error *ngIf="emailFormControl.hasError('email') && !emailFormControl.hasError('required')">
Please enter a valid email address
</mat-error>
<mat-error *ngIf="emailFormControl.hasError('required')">
Email is <strong>required</strong>
</mat-error>
</mat-form-field>
<mat-form-field class = "information-full-width">
<input
matInput
placeholder="Address"
name = "address"
ngModel
required
#address="ngModel">
<mat-error *ngIf="address.invalid">Address is <strong>required</strong></mat-error>
</mat-form-field>
</p>
<mat-form-field class = "information-full-width">
<input
matInput
placeholder="City"
name = "city"
ngModel
required
#city="ngModel">
<mat-error *ngIf="city.invalid">City is <strong>required</strong></mat-error>
</mat-form-field>
<mat-form-field class = "information-full-width">
<input
matInput
placeholder="State"
name="state"
ngModel
required
#state="ngModel">
<mat-error *ngIf="state.invalid">State is <strong>required</strong></mat-error>
</mat-form-field>
<mat-form-field class = "information-full-width">
<input
matInput
#postalCode
maxlength="5"
matInput
placeholder="Zip Code"
name="zip"
ngModel
required
#zip="ngModel">
<mat-error *ngIf="first.invalid">Zip code is <strong>required</strong></mat-error>
<mat-hint align="end">{{postalCode.value.length}} / 5</mat-hint>
</mat-form-field>
<button mat-raised-button color="warn" type="submit">Submit</button>
</form>
</mat-card>
This is my post-create.ts
import { Component } from '#angular/core';
import {FormControl, Validators, NgForm} from '#angular/forms';
import { InformationService } from '../information.service';
#Component(
{
selector: 'app-post-create',
templateUrl: './post-create.component.html',
styleUrls: ['./post-create.component.css']
}
)
export class PostCreateComponent {
enteredFirstName = '';
enteredLastName = '';
enteredAddress = '';
enteredEmailAddress = '';
enteredCity = '';
enteredState = '';
enteredZipCode = '';
emailFormControl = new FormControl('', [
Validators.required,
Validators.email
]);
// informationEntered = new EventEmitter<Information>();
constructor(public informationService: InformationService) {}
onAddName(form: NgForm) {
if (form.invalid) {
return;
}
// const information: Information = {
// first: form.value.first,
// last: form.value.last,
// email: form.value.email,
// state: form.value.state,
// zip: form.value.zip,
// address: form.value.address,
// city: form.value.city
// };
this.informationService.addInformation(form.value.first,
form.value.last,
form.value.email,
form.value.state,
form.value.zip,
form.value.address,
form.value.city);
form.resetForm();
}
}
This is my post-information.component.html
<mat-accordion multi="true" *ngIf="information.length > 0">
<mat-expansion-panel *ngFor="let info of information">
<mat-expansion-panel-header>
{{ info.email }} {{ info.city }} {{ info.state }} {{ info.zip }} {{ info.first }}
</mat-expansion-panel-header>
{{ info.email }} {{ info.city }} {{ info.state }} {{ info.zip }} {{ info.first }}
</mat-expansion-panel>
<mat-action-row>
<button mat-button color = "primary" >EDIT</button>
<button mat-button color = "warn" >DELETE</button>
</mat-action-row>
</mat-accordion>
<p align = center class = "info-text mat-body-1" *ngIf="information.length <= 0" > No information added yet.</p>
and this is my post-information.component.ts
import { Component, OnInit, OnDestroy } from '#angular/core';
import { Information } from '../post.model';
import { InformationService } from '../information.service';
import { Subscription } from 'rxjs';
#Component(
{
selector: 'app-post-information',
templateUrl: './post-information.component.html',
styleUrls: ['./post-information.component.css']
}
)
export class PostInformationComponent implements OnInit, OnDestroy {
information: Information[] = [];
private informationSubs: Subscription;
constructor(public informationService: InformationService) {}
ngOnInit() {
this.informationService.getInfo();
// this.information = this.informationService.getInfo();
this.informationSubs = this.informationService.getInfoUpdateListener()
.subscribe((information: Information[]) => {
this.information = information;
});
}
ngOnDestroy() {
this.informationSubs.unsubscribe();
}
}
Any help or guidance would be great!
I find reactive forms to be much easier to work with validation:
https://angular.io/guide/reactive-forms
Instead of ngModel, you create a form object, with form controls as inputs.
This is another good reference:
https://toddmotto.com/angular-2-forms-reactive
Once you have the form validated, use setValue and call your service method to send the data wherever it's going.

How to save an Array with angular

I'm new with the mean stack and I'm building a phonebook system. Each person can have more than one phone number and I what to be able to save it to the model hereunder. I'm able to save it when I'm using postman as following:
Postman
key:phones[1][type]
value:"mobile"
key:phones[1][number]
value:"123-123-1234"
key:phones[2][type]
value:"home"
key:phones[2][number]
value:"987-987-9876"
Schema
const PhonesSchema = new Schema({
type: { type: String},
number: { type: String}
});
const PersonSchema = new Schema({
first_name: { type: String},
last_name: { type: String},
email: { type: String, unique: true},
phones: [PhonesSchema]
});
module.exports = mongoose.model('Person', PersonSchema);
my issue came when I try to achieve it with angular... I'm able to do it for 1 phone number but not when I want to add more then one... when I trying to pass person.phones[$index][type] it's not working neither....
<form ng-submit="save(person)">
<fieldset data-ng-repeat="Phonefield in Phonefields track by $index">
<select name="type[$index]" ng-model="person.phones.type" class="form-control">
<option>Mobile </option>
<option>Home </option>
<option>Urgence</option>
</select>
<input type="text" placeholder="Phone" name="number[$index]" ng-model="person.phones.number" class="form-control">
<button class="btn btn-danger" ng-show="$last" ng-click="removePhonefield()">-</button>
<button class="btn btn-primary" ng-click="addNewPhonefield()">Add fields</button>
</fieldset>
<button type="submit" class="btn btn-primary" ng-click="save($index, person)">Create</button>
</form>
My phone fields are added dynamically using this code (works well)
$scope.Phonefields = [{id: '0'}];
$scope.addNewPhonefield = function() {
var newItemNo = $scope.Phonefields.length+1;
$scope.Phonefields.push({'id':newItemNo});
};
$scope.removePhonefield = function() {
var lastItem = $scope.Phonefields.length-1;
$scope.Phonefields.splice(lastItem);
};
this is my save function
$scope.save = function(index,person) {
$http.post('http://localhost:3001/api/person', person)
.then(function(response) {
$scope.persons.push(response.data);
});
How can I convert the postman value I passed but within Angular?
key:phones[1][type]
value:"mobile"
Thanks everyone
I solved my issue base on this demo
https://coderwall.com/p/r7bl4w/ng-repeat-index-for-a-form-field-array-ie-add-new-option
and at the end, I copy my new array inside the empty one, enjoy!

Resources