Angular Key-Value how to insert new Key-Value using html - html

this is the class i use
export class Product
{
id: string;
title: string;
description:string;
numbersOfBuyers2Price: {[key: number]: number};
category: string;
img: string;
endDate: number;
}
the function that save the new product
onSaveProduct()
{
if (this.form.invalid) {
return;
}
if (this.mode === 'create')
{
this.productService.addProduct(
this.form.value.title,
this.form.value.description,
this.form.value.priceArray,
this.form.value.category,
this.form.value.img,
this.form.value.endDate
);
}
}
the html for create to new product
<form [formGroup]="form" (submit)="onSaveProduct()">
<table class="example-full-width" cellspacing="0"><tr>
<td>
<mat-label>Title:</mat-label>
<input formControlName="title" matInput>
</td>
<td>
<mat-label>Category:</mat-label>
<input matInput formControlName ="category">
</td>
<td>
<mat-label>IMG:</mat-label>
<input matInput formControlName ="img">
</td>
<td>
<mat-label>End Date:</mat-label>
<input matInput formControlName ="endDate">
</td>
</tr></table>
<button mat-raised-button color="accent" type="submit">Save product</button>
</form>
i'm trying to adding multiple keyValues to numbersOfBuyers2Price using the html component,
i found only how to display them with *ngFor

You could add UI to the HTML template to add new key value pairs to a member of your component clas. Then when the form is submitted you can use that in your onSaveProduct function.
HTML
<td>
<mat-label>New Buyers2Price:</mat-label>
<input matInput [formControl]="newKey">
<input matInput [formControl]="newValue">
<button (click)="addKeyValue()">Add</button>
</td>
TS
class YourComponent {
private buyer2price: {[key: number]: nuber} = {};
public newKey = new FormControl('');
public newValue = new FormControl('');
public function addKeyValue() {
this.buyer2price[this.newKey.value] = this.newValue.value;
}

Related

Angular Material mat-stepper not working with 4 child items

I'm trying to create a mat-stepper on a new, empty page in Angular
it does work generally, but disappears when I add the 4th mat-from-field (in step 2)
the whole mat-stepper won't show up anymore after refreshing the page
input fields are all bound to a variable through "[(ngModel)]"
every mat-step has it's own "[stepControl]"
every form has it's own "[formGroup]"
HTML:
<mat-stepper linear labelPosition="bottom" #stepper>
<mat-step [stepControl]="firstFormGroup" [editable]="true">
<form [formGroup]="firstFormGroup" class="groupFields">
<ng-template matStepLabel>Fill out Project Info</ng-template>
<mat-form-field appearance="fill">
<mat-label>Project Name</mat-label>
<input matInput formControlName="firstCtrl" [(ngModel)]="projectName" required>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Requirements</mat-label>
<textarea [(ngModel)]="requirements"
matInput
cdkTextareaAutosize
#autosize="cdkTextareaAutosize"
cdkAutosizeMinRows="5"
cdkAutosizeMaxRows="15"></textarea>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Employee Email</mat-label>
<input matInput [(ngModel)]="email" required>
</mat-form-field>
<div>
<button mat-button matStepperNext>Next</button>
</div>
</form>
</mat-step>
<mat-step [stepControl]="secondFormGroup" [editable]="true">
<form [formGroup]="secondFormGroup">
<div class="customerFrom">
<div class="groupFields">
<ng-template matStepLabel>Fill out Customer Info</ng-template>
<mat-form-field appearance="fill">
<mat-label>Customer Name</mat-label>
<input matInput formControlName="secondCtrl" [(ngModel)]="company" required>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Address</mat-label>
<input [(ngModel)]="customerAddress" matInput>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>City</mat-label>
<input [(ngModel)]="customerCity" matInput>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Customer Type</mat-label>
<input [(ngModel)]="customerType" matInput>
</mat-form-field>
</div>
</div>
<div>
<button mat-button matStepperPrevious>Back</button>
<button mat-button matStepperNext>Next</button>
</div>
</form>
</mat-step>
<mat-step [stepControl]="thirdFormGroup" [editable]="true">
<form [formGroup]="thirdFormGroup">
<div class="customerFrom">
<div class="groupFields">
<ng-template matStepLabel>Add Contacts</ng-template>
<mat-form-field appearance="fill">
<mat-label>Contact Stuff</mat-label>
<input formControlName="thirdCtrl" matInput>
</mat-form-field>
</div>
</div>
<div>
<button mat-button matStepperPrevious>Back</button>
<button mat-button matStepperNext>Next</button>
</div>
</form>
</mat-step>
<mat-step>
<ng-template matStepLabel>Create Project</ng-template>
Create the Project or go back and edit!
<div>
<button mat-button matStepperPrevious>
<mat-icon>edit</mat-icon> back
</button>
<button mat-button (click)="createProject()">
<mat-icon>done</mat-icon> create Project
</button>
</div>
</mat-step>
</mat-stepper>
TS:
export class ProjectCreationComponent implements OnInit {
projectName: string = '';
selectedStatus: string = '';
requirements: string = '';
company: string = '';
customerAddress: string = '';
customerCity: string = '';
customerType: string = '';
forename: string = '';
surname: string = '';
address: string = '';
city: string = '';
email: string = '';
mobile: string = '';
contacts: Contact[] = [];
unsubscribe$: Subject<void> = new Subject<void>();
firstFormGroup = this._formBuilder.group({
firstCtrl: ['', Validators.required],
});
secondFormGroup = this._formBuilder.group({
secondCtrl: ['', Validators.required],
});
thirdFormGroup = this._formBuilder.group({
thirdCtrl: ['', Validators.required],
});
constructor(
private service: ProjectService,
private router: Router,
private _formBuilder: FormBuilder) { }
ngOnInit(): void {
}
addContact() {
let contact = {} as Contact;
contact.forename = this.forename;
contact.surname = this.surname;
contact.address = this.address;
contact.city = this.city;
contact.email = this.email;
contact.mobile = this.mobile;
this.contacts.push(contact);
}
deleteContact(contact: Contact) {
const index: number = this.contacts.indexOf(contact);
if(index !== -1) {
this.contacts.splice(index, 1);
}
}
createProject() {
const customer: Customer = {
name: this.company,
contacts: this.contacts,
address: this.customerAddress,
city: this.customerCity,
customerTyp: this.customerType
}
const announcement: Announcement = {
requirements: this.requirements,
customers: [customer],
offers: [],
}
const project: ProjectCreationRequest = {
name: this.projectName,
employeeEmail: this.email,
announcements: [announcement],
offers: []
};
this.service.createProject(project)
.pipe(takeUntil(this.unsubscribe$))
.subscribe();
this.router.navigateByUrl('/');
}
ngOnDestroy() {
this.unsubscribe$.next();
this.unsubscribe$.complete();
}
}
I've also exactly tried removing a mat-form-field (so that I only have 3 in the form), for every single one of them, so there is not a specific one that's causing the problem.
One more thing I've tried is changing "[(ngModel)]" to "[value]", because 2 way binding isn't necessarily needed, but with that the value of the textfield can't be stored in the variable.
Also I didn't find anything in the material documentation about a maximum size of step child items or anything.
Stackblitz (not 1:1 because of too many classes): https://stackblitz.com/edit/angular-buspzu?file=src/app/app.component.ts

ERROR TypeError: can't assign to property "validator" on "12345": not an object

I want to build a pre filled form, as of now I am getting this error when i try to display the form page. I have tried various solutions that was given but that doesn't seem to work here.
My hardwareRequest.ts
hardwareReviewForm: FormGroup;
assetSerialNumber = new FormControl('');
modelType = new FormControl('');
ngOnInit(): void {
this.data = []
this.service.loadRequestData(this.requestId).subscribe(
(response: any) => {
this.data = response
console.log(this.data)
this.assetSerialNumber = this.data.assetSerialNumber
this.modelType = this.data.modelType
},
(error) => {
}
)
}
My HTML file
<form class="example-container" [formGroup]="hardwareReviewForm" (ngSubmit)="onFormSubmit()">
<div class="ds-col-12" style="margin-bottom: 10px;">
<div class="ds-col-6">
<mat-form-field appearance="outline">
<mat-label>Asset Serial Number: </mat-label>
<input formControlName="assetSerialNumber" readonly matInput type="text">
</mat-form-field>
</div>
<div class="ds-col-6">
<mat-form-field appearance="outline">
<mat-label>Part No./Model Type: </mat-label>
<input formControlName="modelType" readonly matInput type="text">
</mat-form-field>
</div>
</div>
</form>
You can make a 'View Model' of your fields and then reset your form with it.
export class testVm {
assetSerialNumber : number;
modelType : string;
}
var model: testVm = this.data;
this.hardwareReviewForm.reset(model)
Or if you want to assign value separately you should act like this:
this.hardwareReviewForm.controls["assetSerialNumber"].reset(this.data.assetSerialNumber.toString())
Firstly, you have to define form controls inside formGroup;
hardwareReviewForm = new FormGroup({
assetSerialNumber = new FormControl('');
modelType = new FormControl('');
});
Secondly, you set the values to controls like below;
this.hardwareReviewForm.get('assetSerialNumber').setValue(this.data.assetSerialNumber);
I figured this out.. It was a silly mistake of .setValue for form controls.
setting my value like below works fine.
this.Number.setValue(this.data.Number)
this.Type.setValue(this.data.Type)

register an angular form in a nested json

I am trying to convert a html form to a nested json.
These are my classes :
export class Config {
id: string;
name: string;
email: string;
lchart:ComponentLinechart;
}
export class ComponentLinechart {
name_linechart : String;
xAxis_linechart : String;
yAxis_linechart : String;
}
The formcomponent.ts:-
export class FormsComponent implements OnInit {
newConfig: Config = new Config();
constructor(private service : MyserviceService, private configservice:ConfigurationService) {
}
email = new FormControl('', [Validators.required, Validators.email]);
xAxisControl = new FormControl('', Validators.required);
yAxisControl = new FormControl('', Validators.required);
name_linechart = new FormControl('', Validators.required);
name = new FormControl('', Validators.required);
getConfig(): void {
this.configservice.getConfig()
.subscribe(data => this.configs = data );
}
createConfiguration(todoForm: NgForm): void {
this.configservice.createConfig(this.newConfig)
.subscribe(createconfig => {
todoForm.reset();
this.newConfig = new Config();
this.configs.unshift(createconfig)
});
}
The formcomponent.html :-
<form #todoForm="ngForm" (ngSubmit)="createConfiguration(todoForm)" novalidate>
<div class="example-container">
<mat-form-field appearance="fill">
<mat-label>Enter your name</mat-label>
<input matInput [(ngModel)]="newConfig.name" name="name" [formControl]="name" required>
</mat-form-field>
<br>
<mat-form-field appearance="fill">
<mat-label>Enter your email</mat-label>
<input matInput placeholder="pat#example.com" [(ngModel)]="newConfig.email" name="email"
[formControl]="email" required>
<mat-error *ngIf="email.invalid">{{getErrorMessage()}}</mat-error>
</mat-form-field>
<br>
<mat-form-field appearance="fill">
<mat-label>Name-linechart</mat-label>
<input matInput [(ngModel)]="newConfig.name_linechart" name="name_linechart"
[formControl]="name_linechart" required>
</mat-form-field>
<br>
<mat-form-field *ngIf = "sales" >
<mat-label>xAxis-linechart</mat-label>
<mat-select [(ngModel)]="newConfig.xAxis-linechart" name="xAxis-linechart"
[formControl]="xAxisControl" required>
<mat-option *ngFor="let field of fields" [value] = "field">
{{field}}
</mat-option>
</mat-select>
<mat-error *ngIf="xAxisControl.hasError('required')">Please choose a field</mat-error>
</mat-form-field>
<br>
<mat-form-field *ngIf = "sales" >
<mat-label>yAxis-linechart</mat-label>
<mat-select [(ngModel)]="newConfig.yAxis-linechart" name="yAxis-linechart"
[formControl]="yAxisControl" required>
<mat-option *ngFor="let field of fields" [value] = "field">
{{field}}
</mat-option>
</mat-select>
<mat-error *ngIf="yAxisControl.hasError('required')">Please choose a field</mat-error>
</mat-form-field>
Expected result :
{
"name": "adam",
"email": "adam#gmail.com",
"lchart": {
"name_linechart": "books",
"xAxis_linechart": "library",
"yAxis_linechart": "percentage"
}
}
But this is what I get :
{
"name": "adam",
"email": "adam#gmail.com",
"lchart": null
}
I tried to write newConfig.lchart.name_linechart in the formcomponent.html but it gives me the error :
TypeError : cannot read property name_linechart of undefined.
Foufa, NEVER, NEVER, NEVER, NEVER use [(ngModel)] and formControlName (or formControl) in the same tag. One is for template Form, another for ReactiveForms, see the docs
Well. You has an object that has properties, one of them is an object, so, you has a FormGroup with somes FormControls and one FormGroup, (again the docs)
myForm=new FormGroup({
name:new FormControl(),
email:new FormControl(),
lchart:new FormGroup({
name_linechart: new FormControl(),
xAxis_linechart: new FormControl(),
yAxis_linechart: new FormControl(),
})
})
And the .html
<form [formGroup]="myForm">
<!--see, under the formGroup, we using formControlName for the formControl-->
<input formControlName="name">
<input formControlName="email">
<!--when we has a FomgGroup, we use formGrpupName in a div-->
<div formGroupName="lchart">
<!--and formControlName under the div -->
<input formControlName="name_linechart">
<input formControlName="xAxis_linechart">
<input formControlName="yAxis_linechart">
</div>
</form>
<!--we can add, only for check-->
<pre>
{{myForm?.value|json}}
</pre>
Update as always, is util use a function that received an object and create the form
getForm(data:any)
{
data=data || { name:null,
email:null,
lchart:{
name_linechart:null,
xAxis_linechart:null,
yAxis_linechart:0
}
}
return new FormGroup({
name:new FormControl(data.name,Validator.required),
email:new FormControl(data.email,[Validator.required,Validators.emailValidator),
lchart:new FormGroup({
name_linechart: new FormControl(data.lchart.name_linechart),
xAxis_linechart: new FormControl(data.lchart.xAxis_linechart),
yAxis_linechart: new FormControl(data.lchart.yAxis_linechart),
})
}
And use as
myForm=this.getForm(data) //<--if we has an object "data"
//or
myForm=this.getForm(null) //if we want a empty form
I guess your [(ngModel)] binding wrong for name_linechart,xAxis_linechart,yAxis_linechart fields.
It should be
[(ngModel)]="newConfig.lchart.name_linechart"
[(ngModel)]="newConfig.lchart.xAxis_linechart"
[(ngModel)]="newConfig.lchart.yAxis_linechart"
change your constructor to-
constructor(private service : MyserviceService, private configservice:ConfigurationService) {
this.newConfig.lchart=new ComponentLinechart(); //add this line
}

Reactive form with dynamic data change from component

I am setting up a reactive form in angular 6, where I have 2 input boxes(one input is an optional entry) and a submit button. If I enter a value to one input box and press submit, I need to fill the other input box by setting corresponding value from component side. If I enter values to both input boxes, then another function is called. If so how is two-way data bindin possible in form controls? I tried using ngModel, which is not working as expected and from stackoverflow answers, came to know that using ngmodel with form controls is soon to be deprecated. How Can I achieve the same if so? Below is the code snippet I am using:
Component.ts:
export class myComponent implements OnInit {
converterForm: FormGroup;
model: myModel = new MyModel();
constructor(private formBuilder: FormBuilder, ) {
this.myForm = this.formBuilder.group({
vOne: [this.model.vOne],
vTwo: [this.model.vTwo],
});
}
onSubmit(searchInputs) {
this.model.vTwo= "new"; //I need to edit the form value and reflect it in html.. two-waybinding
this.converterForm.value.vOne = "edited";
console.log("Submit called");
}
}
html file:
<div>
<div>
<form [formGroup]="myForm" (ngSubmit)="onSubmit(myForm.value)">
<div>
<div>
<mat-form-field>
<input id="vOne" matInput formControlName="vOne" [(ngModel)]="model.vOne">
</mat-form-field>
</div>
<div>
<mat-form-field>
<input id="vTwo" matInput formControlName="vTwo" [(ngModel)]="model.vTwo">
</mat-form-field>
</div>
</div>
<div>
<button mat-raised-button color="primary" type="submit" (click)="search()">
<mat-icon aria-label="Search icon">search </mat-icon>
Search
</button>
</div>
</form>
</div>
thanks in advance.
Using valueChanges for access to live changes, and using setValue func for setting value per input.
in ts file try:
export class myComponent implements OnInit {
myForm: FormGroup;
constructor(private formBuilder: FormBuilder) {
this.myForm = this.formBuilder.group({
vOne: [null],
vTwo: [null],
});
searchHandler();
}
searchHandler() {
const searchInputs = {
vOne: '',
vTwo: '',
};
for (const propertyName in searchInputs) {
const property = this.form.get(propertyName);
property.valueChanges
.subscribe((searchText) => {
// this.form.controls.vOne.setValue('whatever');
// this.form.controls.vTwo.setValue('whatever');
// searchText is what keypress in input tag
});
}
}
onSubmit() {
// this.form.controls.vOne.setValue('whatever');
// this.form.controls.vTwo.setValue('whatever');
}
}
in html file try:
<form [formGroup]="myForm" (ngSubmit)="onSubmit()">
<div>
<mat-form-field>
<input matInput formControlName="vOne">
</mat-form-field>
</div>
<div>
<mat-form-field>
<input matInput formControlName="vTwo">
</mat-form-field>
</div>
</form>

post empty value from autocomplete material typescript

I want to post data from autocomplete material.
My ts code, like this. I used registerUserForm formgroup.
export class AddUserFormComponent implements OnInit {
countryes: Country[];
registerUserForm: FormGroup;
filteredOptionsCountry: Observable<Country[]>;
myControlCountry: FormControl = new FormControl();
constructor(private fb: FormBuilder,
private router: Router,
private cs: CountryService)
{
this.registerUserForm = new FormGroup({
'username': new FormControl(),
'email': new FormControl(),
'country_id': new FormControl(),
});
}
ngOnInit() {
this.registerUserForm = this.fb.group({
'username': ['', Validators.compose([Validators.required, Validators.minLength(5)])],
'country_id': ['', Validators.required],
'email': ['', [Validators.required, ValidationService.emailValidation]],
});
this.filteredOptionsCountry = this.myControlCountry.valueChanges.pipe(
startWith(''),
map(val => this.filterCountry(val))
);
this.cs.getAllCountry().subscribe(
countryes => {
this.countryes = countryes.map((country) => {
return new Country(country);
});
}
);
}
onRegisterUser() {
this.loading = true;
this.invalidInputs = true;
let newUser = new User(
this.registerUserForm.value
);
this.userService.createUser(newUser).subscribe(
);
}
onCancel() {
this.router.navigate(['/main/users']);
}
//Country
filterCountry(val: string): Country[] {
if (val) {
let filterValue = val.toLowerCase();
console.log(this.countryes)
return this.countryes.filter(country => country.name.toLowerCase().startsWith(filterValue));
}
return this.countryes;
}
}
my html code. In this code i have 3 parameters, only email and username i can post, country_id post empty
<form [formGroup]="registerUserForm" (ngSubmit)="onRegisterUser()" class="col s12" materialize>
<div class="row">
<div class="input-field col s12">
<input formControlName="username" id="username" type="text" class="validate" placeholder="Enter Username" minlength="3" maxlength="20"
required="" [ngClass]="{invalid: invalidInputs}">
</div>
</div>
<div class="row">
<div class="input-field col s12">
<input formControlName="email" id="email" type="email" class="validate" placeholder="Enter Email" required="" aria-required="true"
[ngClass]="{invalid: invalidInputs}">
</div>
</div>
<!-- Autocomplete Country Material-->
<input formControlName="country_id" id="country_id" matInput placeholder="Select Country" aria-label="State" [matAutocomplete]="auto"
autoActiveFirstOption [formControl]="myControlCountry">
<mat-autocomplete #auto="matAutocomplete">
<mat-option *ngFor="let country of filteredOptionsCountry | async" [value]="country.name">
{{ country.name }}
</mat-option>
</mat-autocomplete>
<!-- End Autocomplete Country -->
<div id="register_user_button_container" class="row">
<button id="register_user_button" type="submit" class="btn waves-effect waves-light">
Register
</button>
<button id="cancel_button" (click)="onCancel()" class="btn waves-effect waves-light grey lighten-4 black-text">
Cancel
</button>
</div>
</form>
Can you suggest me, how to used this FormControl inside registerUserForm ? Or, something solution.
Your code is litteral chaos.
First, group everything in a single form.
registerUserForm: FormGroup;
Then, instantiate your form only once, you don't need to do it more.
constructor() {
this.registerUserForm = this.fb.group({
username: ['', [Validators.required, Validators.minLength(5)]],
country_id: ['', Validators.required],
email: ['', [Validators.required, ValidationService.emailValidation]],
myControlCountry: ''
});
}
Next, use a getter to get your countries. (This is one of the many ways)
countries: Country[];
get filteredCountries() {
const query = this.registerUserForm.get('country_id').value;
return query ?
this.countries.filter(c => c.name.toLowerCase().includes(query.toLowerCase)) :
this.countries;
}
Now you must bind it to your HTML :
<mat-option *ngFor="let country of filteredCountries" [value]="country.name">
{{ country.name }}
</mat-option>