Angular2: get value of input in dynamic form - angular2-forms

I need to get value of a certain input in my dynamic form.
I have JSON parameters like this
{
"etiquette":"Téléphone mobile",
"ordre":1,
"obligatoire":true,
"pattern":"^(?:(?:(?:\\\\+|00)33[ ]?(?:\\\\(0\\\\)[ ]?)?)|0){1}[1-9]{1}([ .-]?)(?:\\\\d{2}\\\\1?){3}\\\\d{2}$",
"section":"TelMail",
"type":"text",
"nom":"telephoneMobile",
"texteIndice":"Téléphone mobile"
}
,
{
"etiquette":"Mail",
"ordre":2,
"obligatoire":true,
"pattern":"(?:[a-zA-Z0-9!#$%&''*+=?^_`{|}~-]+(?:\\\\.[a-zA-Z0-9!#$%&''*+=?^_`{|}~-]+)*|\u201d(?:[\\\\x01-\\\\x08\\\\x0b\\\\x0c\\\\x0e-\\\\x1f\\\\x21\\\\x23-\\\\x5b\\\\x5d-\\\\x7f]|\\\\\\\\[\\\\x01-\\\\x09\\\\x0b\\\\x0c\\\\x0e-\\\\x7f])*\u201d)#(?:(?:[a-zA-Z0-9àâäçéèëêîïôôûüù](?:[a-zA-Z0-9-àâäçéèëêîïôôûüù]*[a-zA-Z0-9àâäçéèëêîïôôûüù])?\\\\.)+[a-zA-Z0-9àâäçéèëêîïôôûüù](?:[a-zA-Z0-9-àâäçéèëêîïôôûüù]*[a-zA-Z0-9àâäçéèëêîïôôûüù])?|\\\\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-zA-Z0-9-]*[a-zA-Z0-9]:(?:[\\\\x01-\\\\x08\\\\x0b\\\\x0c\\\\x0e-\\\\x1f\\\\x21-\\\\x5a\\\\x53-\\\\x7f]|\\\\\\\\[\\\\x01-\\\\x09\\\\x0b\\\\x0c\\\\x0e-\\\\x7f])+)\\\\])",
"section":"TelMail",
"type":"email",
"nom":"mail",
"texteIndice":"Mail"
},
{
"etiquette":"Type alerte",
"ordre":3,
"obligatoire":true,
"options": [{
"code" : "SMS",
"valeur" : "Alertes SMS"
},
{
"code" : "MAIL",
"valeur" : "Alertes Mail"
}],
"section":"Alerte",
"type":"radio",
"nom":"typeAlerte",
"texteIndice":"Type alerte"
}
I have Interface like below screenshot.
I customised radio component to contain radio input and input for mail and phone.
What I need is: get value of input phone/mail and put in in the input related to the radio.
Here is my radio component:
import {Component,Inject,Input} from '#angular/core';
import {NgForm, FormGroup} from '#angular/forms';
import {ExtraFormField} from '../model/form';
import {ExtraField} from './extra-field';
import { CatalogueService } from "../../catalogue/catalogue.service";
#Component({
selector: 'radio-extra-field',
template:`
<div class="form-group" >
<label [attr.for]="field.nom">{{field.etiquette}}</label>
<div *ngFor="let option of field.options" >
<input type="radio" name ="{{field.nom}}" value="{{option.code}}" id="{{option.code}}" [(ngModel)]="typeSelectionne">{{option.valeur}}
<input id="{{option.code}}" [attr.title]="field.etiquette" [attr.minlength]="field.longueurMin" [attr.min]="field.min" [attr.max]="field.max"
[attr.maxlength]="field.longueurMax" [attr.value]="field.valeur"
[attr.type]="text" [formControl]="fieldControl" (change)="maj(id.value)"
[attr.id]="option.code" type="text" [attr.disabled]="typeSelectionne != option.code? disabled : null ">
<error-messages [control]="field.nom"></error-messages>
</div>
<error-messages [control]="field.nom"></error-messages>
</div>
`
})
export class RadioExtraField extends ExtraField {
typeSelectionne: string;
#Input() field:ExtraFormField;
#Input() entity:{fields:Object};
#Input() formGroup:FormGroup;
constructor(public catalogueService: CatalogueService, #Inject(NgForm) formDir: NgForm) {
super(null, catalogueService, formDir);
}
get disabled():string {
if(this.field) {
return 'disabled';
}
return null;
}
}
Is there a way to do this ?
thank you

You can use
(ngModelChange)
what it do is it will call function ,there you can assign value to ngModel of input field.

Related

Read span value in angular reactive forms

<span class="headmain" style="cursor:pointer" (click)="modalshow(ratingImage,el.name+i,el)" >
hello</span>
How to get the value from span element in similar to formControlName?
Span element is in a form tag.
You can use #ViewChild / ElementRef.
HTML:
<span #mySpan (click)="handleClick()">
Hallo from span.
</span>
TS:
export class AppComponent {
#ViewChild("mySpan", { static: false }) mySpanRef: ElementRef;
public handleClick(): void {
const spanValue = this.mySpanRef.nativeElement.innerHTML;
console.log("Span-Value: ", spanValue);
}
}
Working stackblitz

React ant design typescript form validation not working

I used react typescript project to ant design and i used this ant design form validation, but its not working correctly, anyone know how to fix that issue?
Thanks
git a this error
index.tsx?789d:32 Uncaught TypeError: Cannot read property
'getFieldDecorator' of undefined
import * as React from "react";
import { Input, Form, Icon, Button, } from "antd";
import 'antd/dist/antd.css';
import "./style.css";
export class Registerform extends React.Component<any> {
handleSubmit = (e:any) => {
e.preventDefault();
this.props.form.validateFieldsAndScroll((err:any, values:any) => {
if (!err) {
console.log('Received values of form: ', values);
}
});
};
render() {
const { getFieldDecorator } = this.props.form;
return (
/* Start add bulk upload form*/
<div className="remindersform-section">
<Form onSubmit={this.handleSubmit}>
<Form.Item
label={
<span>
Nickname
<Icon type="question-circle-o" />
</span>
}
>
{getFieldDecorator('nickname', {
rules: [{ required: true, message: 'Please input your nickname!', whitespace: true }],
})(<Input />)}
</Form.Item>
<Form.Item >
<Button type="primary" htmlType="submit">
Register
</Button>
</Form.Item>
</Form>
</div>
);
}
}
Because default form props are not assigned with their types, antd provided a solution for it, Try like below
import * as React from "react";
import { FormComponentProps } from "antd/es/form";
import { Input, Form, Icon, Button, } from "antd";
import 'antd/dist/antd.css';
interface UserFormProps extends FormComponentProps {
form: any;
}
class Registerform extends React.Component<UserFormProps> {
handleSubmit = (e:any) => {
e.preventDefault();
this.props.form.validateFieldsAndScroll((err:any, values:any) => {
if (!err) {
console.log('Received values of form: ', values);
}
});
};
render() {
const { getFieldDecorator } = this.props.form;
return (
/* Start add bulk upload form*/
<div className="remindersform-section">
<Form onSubmit={this.handleSubmit}>
<Form.Item
label={
<span>
Nickname
<Icon type="question-circle-o" />
</span>
}
>
{getFieldDecorator('nickname', {
rules: [{ required: true, message: 'Please input your nickname!', whitespace: true }],
})(<Input />)}
</Form.Item>
<Form.Item >
<Button type="primary" htmlType="submit">
Register
</Button>
</Form.Item>
</Form>
</div>
);
}
}
const WrappedForm = Form.create<UserFormProps>({})(Registerform);
export default WrappedForm;

Identifier 'categoryName' is not defined. 'Array' does not contain such a member

<div class="example-container">
<div class="pb-16" fxLayout="row" fxLayoutAlign="start center">
<div class="h2 secondary-text">
<b>
<u>Profile Details of {{rows ? rows?.categoryName : ''}}</u>
</b>
</div>
</div>
<br />
<mat-form-field>
<mat-label>Category Name</mat-label>
<input matInput placeholder="category name" value="{{rows ? rows?.categoryName : ''}}">
</mat-form-field>
<br />
<br />
<mat-form-field class="example-full-width">
<mat-label>Category Description</mat-label>
<textarea matInput placeholder="category description" value="{{rows ? rows?.categoryDesc : ''}}"></textarea>
</mat-form-field>
</div>
This is component.html
import { Component,OnInit,Input } from "#angular/core";
import { MatSnackBar } from '#angular/material';
import { coerceBooleanProperty } from "#angular/cdk/coercion";
import { HttpClient } from "#angular/common/http";
import { ActivatedRoute } from "#angular/router";
import { FormBuilder, FormGroup, Validators,FormControl } from
'#angular/forms';
import { Location} from '#angular/common';
import 'rxjs/add/operator/debounceTime';
import 'rxjs/add/operator/delay';
import 'rxjs/add/operator/map';
import {ServiceContactsFakeDb} from '../../../../../fuse-fake-db/service-
contacts';
import { Data } from '../../../../../fuse-fake-db/hero';
import { LIST } from '../../../../../fuse-fake-db/mock-heroes';
import {CategoryService} from "../category.service";
#Component({
selector: 'profile-detail',
templateUrl: './profile.component.html',
styleUrls:['./component.scss'],
providers:[CategoryService]
})
export class ProfileComponent implements OnInit {
constructor (private location:Location,private http: HttpClient,private
service:CategoryService,private _Activatedroute:ActivatedRoute){
}
name = new FormControl('', [Validators.required]);
name1 = new FormControl('', [Validators.required]);
favoriteSeason: any;
_card = false;
profiles = LIST;
#Input() category;
selectedProfile: Data;
rawdata:any[];
rows: any[];
reorderable = true;
categoryName : any[];
categoryDesc : any = {};
data = [];
item:string[];
id:string;
catName: string;
catDesc: string;
//selectedProfile: ServiceContactsFakeDb;
setDataLayoutType(value: boolean) {
this._card = coerceBooleanProperty(value);
}
ngOnInit(){
// this.getDetail();
this.id=this._Activatedroute.snapshot.params['id'];
console.log(this.id);
this.service.getcategory().subscribe(res => {
this.rawdata = res;
for(var i=0;i<this.rawdata.length;i++){
if(this.id == this.rawdata[i].id){
this.rows=this.rawdata[i];
console.log(this.rows);
}
}
});
}
In this code I am getting error in component.html file like this :
[Angular] Identifier 'categoryName' is not defined. 'Array' does not contain such a member .
I am fetching the values from an api, I am getting the output but still it shows errors in this line "value="{{rows ? rows?.categoryName : ''}}"
I had defined rows as a array replace it with rows: any={} instead of rows: any[];

Programmatically open an N level self nested mat-menu component with matMenuTrigger openMenu

I am trying to make a self nested component that uses Angular Material mat-menu. I have a flyoutcomponent that is a wrapper for flyout-menu-item component, that will have a button as a matMenuTrigger for the nested component that will appear as many levels as the FeatureInput.FeatureChoices dictates. FeatureInput is an object that has FeatureChoices that may or may not contain other featurechoices etc N levels deep. Below code does not compile but it should demonstrate what I am doing. Basically I have flyout menu component as a input to a form and I am trying to load a stored answer on a form rather than select new, which I can do easily using the nested component. The desired behavior is that if the user clicks top matMenuTrigger button to open the top menu that it would expand all child menus to the menu item that matches with the FeatureInput.FeatureValue and sets the menu item _highlighted to true. I am using the menuOpen input parameter and ngChanges successfully to find the match(with I a setTimeout which cannot be right). Basically when I console.log this.trigger it is undefined. Ideally in the ngOnChange to the openMenu I would go through all menus and call openMenu on all the triggers but I cannot get access to the matMenuTrigger with ViewChild as the docs say. I get undefined. *-( All help welcome please and thanks.
Here is flyout template component.
<div>
<buttonmat-button [matMenuTriggerFor]="menu.childMenu"
(onMenuOpen)="onMenuOpen()"
(onMenuClose)="onMenuClose()">
<span [innerHTML]="featureInput.Text"></span>
</button>
<app-flyout-menu-item #menu
[featureChoicesObject]="featureInput.FeatureChoices"></app-flyout-menu-item>
</div>
And here is its .ts
import { Component, OnInit, Input, ViewChild } from '#angular/core';
import { MatMenuTrigger } from '#angular/material';
#Component({
selector: 'app-flyout',
templateUrl: './flyout.component.html',
styleUrls: ['./flyout.component.scss']
})
export class FlyoutComponent implements OnInit {
#Input() featureInput: FeatureInput
constructor() { }
ngOnInit() {
}
onMenuOpen() {
this.menuOpen = true;
}
onMenuClose() {
this.menuOpen = false;
}
}
And here is flyout-menu-item template
<mat-menu #childMenu="matMenu" [overlapTrigger]="false">
<span *ngFor="let featureChoice of featureChoices">
<span>
<button mat-menu-item [matMenuTriggerFor]="menu.childMenu">
<span [innerHTML]="featureChoice.Text"></span>
</button>
<app-flyout-menu-item #menu
[menuOpen]="menuOpen"
[featureInput]="featureInput"
[featureChoicesObject]="featureChoice.FeatureChoices"
(onOptionSelected)="someService.SomeMethod($event)"></app-flyout-menu-item>
</span>
<span *ngIf="!featureChoice.FeatureChoices">
<button mat-menu-item (click)="selectOption(featureChoice.ID)" [innerHTML]="featureChoice.Text" value="{{featureChoice.ID}}"></button>
</span>
</span>
</mat-menu>
And here is its .ts
import { Component, OnInit, Input, Output, ViewChild, EventEmitter, OnChanges, SimpleChanges } from '#angular/core';
import { MatMenuTrigger } from '#angular/material';
import { FeatureChoice } from 'app/model/feature-choice';
import { FeatureInput } from 'app/model/feature-input';
#Component({
selector: 'app-flyout-menu-item',
templateUrl: './flyout-menu-item.component.html',
styleUrls: ['./flyout-menu-item.component.scss']
})
export class FlyoutMenuItemComponent implements OnInit{
#ViewChild('menu') public menu;
#ViewChild('childMenu') public childMenu;
#ViewChild(MatMenuTrigger) public trigger: MatMenuTrigger;
#Input() featureInput: FeatureInput;
#Input() featureChoicesObject: FeatureChoice;
#Output() onOptionSelected: EventEmitter<FeatureInput> = new EventEmitter<FeatureInput>();
constructor(public solutionDataService: SolutionDataService) { }
ngOnInit() {
console.log(this.trigger);
}
ngOnChanges(simpleChanges: SimpleChanges) {
if (simpleChanges.menuOpen && simpleChanges.menuOpen.currentValue) {
setTimeout(() => {
// console.log(this.menu);
const itemsArray = this.childMenu.items.toArray();
for (let x = 0; x < itemsArray.length; x++) {
const menuItem = itemsArray[x];
if (this.featureInput.FeatureValue !== '' && menuItem._elementRef.nativeElement.value === this.featureInput.FeatureValue) {
menuItem._highlighted = true;
}
}
}, 1);
}
}
}
this.menuOpen = true;
Perhaps add menuOpen: boolean = false as an attribute at the top of your FlyoutComponent. I don't know where the value of menuOpen is saved.
the menuOpen property relates to the matMenuTrigger.
here's an example:
<button [ngClass]="{'active-icon': trigger.menuOpen}" type="button" mat-
icon-button #trigger="matMenuTrigger" [matMenuTriggerFor]="help">
<mat-icon></mat-icon>
</button>
<mat-menu #help="matMenu">
<div> textId </div>
</mat-menu>

#Input not Binding data from component

Angular2 #Input component is not Binding data from another component
DummyComponent.ts
import { Component,Input,ElementRef } from "#angular/core"
#Component({
selector: "Dummy-Selector",
template: `Hello Dummy How Are you....`,
// inputs: ["rating"]
})
export class DummyComponent {
debugger;
#Input() username: string;
}
LoginComponent.html
<input type="text" [(ngModel)]="LoginObj.username" value="user" />
<div>
<Dummy-Selector [username]='LoginObj.username'></Dummy-Selector>
</div>
Here I'm getting my Dummy-selector username data but when I insert some data in LoginObj.username via the input field - why is it not reflected?
It's not clear exactly what error you are seeing (if any) but it input binding should work with the following:
LoginComponent.ts
#Component({..})
export class LoginComponent {
LoginObj = {};
}
In DummyComponent.ts change the template to show that the username field reflects changes from the input field.
import { Component,Input } from "#angular/core"
#Component({
selector: "Dummy-Selector",
template: `Hello Dummy How Are you... {{username}}`,
})
export class DummyComponent {
debugger;
#Input() username: string;
}

Resources