I created a simple reusable component as:
TS
import {Component, Input, OnInit} from '#angular/core';
import {FormControl} from '#angular/forms';
#Component({
selector: 'app-select',
templateUrl: './select.component.html',
styleUrls: ['./select.component.css']
})
export class SelectComponent implements OnInit {
#Input() control: FormControl;
#Input() label: string;
#Input() options: [];
#Input() idAndForAttributes: string;
#Input() customClass: string;
constructor() { }
ngOnInit() {
}
}
HTML
<div class="form-group" [ngClass]="{'invalid': control.invalid && control.touched && control.dirty}">
<label [attr.for]="idAndForAttributes">{{ label }}:</label>
<select class="form-control" [ngClass]="customClass" [formControl]="control" [attr.id]="idAndForAttributes">
<option value="0">- Select -</option>
<option *ngFor="let item of options" [ngValue]="item.id">{{item.description}}</option>
</select>
<ng-container *ngIf="control.dirty && control.touched && control.invalid">
<div *ngIf="control.errors.required || (control.errors.min && control.value == 0)">
<small style="color: #c62828;">
Value is required.
</small>
</div>
</ng-container>
</div>
Now I'm trying to use it in my other html as:
<form [formGroup]="profileActivityForm">
<app-select [control]="profileActivityForm.get('activityType')" [idAndForAttributes]="'type'" [label]="'Type'"
[options]="profileActivityTypes"></app-select>
</form>
Then in TS
profileActivityTypes: string[] = [];
ngOnInit() {
this.profileActivityTypes.push('New')
this.profileActivityTypes.push('Update')
this.profileActivityForm = this.fb.group({
activityType: [0]
});
}
But it is showing invisible options like the following picture:
I think the problem is on the html of the reusable component <option *ngFor="let item of options" [ngValue]="item.id">{{item.description}}</option>
Because it is looking for a description, how can I send the item as a description from the child component?
UPDATE
I tried:
profileActivityTypes: [] = [];
....
let profileActivities = [{ description: 'New' }, { description: 'Update' }]
this.profileActivityTypes.push(profileActivities)
but it is throwing an error on push:
Argument of type '{ description: string; }[]' is not assignable to
parameter of type 'never'
In order to solve this, I changed the assignation of the profileActivities array instead of creating the array and then pushing it. I assign it directly as:
profileActivityTypes = [];
this.profileActivityTypes = [{ id: 1, description: 'New' }, {id: 2, description: 'Update'}]
I hope this works for more people!
Related
I woudlike to send data selected from my another component (variable in file .ts)
.html :
<div class="liste">
<select class="form-control" name="Container" (change)="selectChangeHandler($event)">
<option disabled selected value> -- select an Container -- </option>
<option *ngFor="let v of values;let i = index" [value]="i">
{{v.Name}}
</option>
</select>
</div>
<div class="tableau" *ngIf="show" >
<table align="center">
<tr align="center"><b>{{selectedValue.Name}}</b></tr>
<tr align="center"><td>Matricule: {{selectedValue.Matricule}}</td></tr>
<tr align="center"><td>Material: {{selectedValue.Material}}</td></tr>
<div class="modal-body">
<app-heat-local> </app-heat-local>
</div>
How can I get value for this component with using to send my data in this component ?
another component .html (heat-local):
<h6 class="container-name">{{selectedValue.Name}}</h6>
my file .ts :
import {Component, OnDestroy, OnInit} from '#angular/core';
import {Cell} from 'app/data/cell';
#Component({
selector: 'app-heat-global',
templateUrl: './heat-global.component.html',
styleUrls: ['./heat-global.component.css'],
providers: [HeatService]
})
export class HeatGlobalComponent implements OnInit{
selectedValue = {
Name: '',
Matricule: '',
Material:'',
Quantity:'',
Coordonates:'',
}
values = [{
Name: "Container A",
Matricule: "ABC",
From the question it seems that it could be possible to solve it this way.
You can set value of a selected option to property inside of selectChangeHandler()
selectChangeHandler(event) {
this.currentValue = event.target.value;
}
To get it inside of app-heat-local
<div class="modal-body">
<app-heat-local [value]="currentValue"> </app-heat-local>
</div>
To be able to set [value] attribute you need to define #Input() property inside of HeatLocalComponent
You could use #Input() to achieve this.
import {Component, Input} from '#angular/core';
#Component({
selector: 'app-heat-local',
templateUrl: './heat-local.component.html',
styleUrls: ['./heat-local.component.scss']
})
export class HeatLocalComponent {
#Input() value: number;
}
To display the value in heat-local.component.html you can you use interpolation
<h6 class="container-name">{{value}}</h6>
You can read more about component interaction
Update
To receive name instead of index just change value from i which is index to v.Name.
{{v.Name}}
Or you can provide the whole object
<option *ngFor="let v of values;let i = index" [value]="v">
{{v.Name}}
</option>
Becareful with type you specify in here. In previous part there is number type specified so it won't take anything else than number
import {Component, Input} from '#angular/core';
#Component({
selector: 'app-heat-local',
templateUrl: './heat-local.component.html',
styleUrls: ['./heat-local.component.scss']
})
export class HeatLocalComponent {
#Input() value: string // <== Here you can specify the type by TS type
}
string will be used just when value of an option is string, if you want to send whole object then change it to this #Input() value: any or define your own interface
I'm using Angular 7 reactive forms in my component. Part of my component:
#Component({
selector: 'my-form',
templateUrl: './my-form.component.html',
styleUrls: ['./my-form.component.scss']
})
export class MyFormComponent implements OnInit {
form: FormGroup;
loaded: boolean = false;
item: Item;
// item gets loaded from the server and looks like this:
// {
// id: 'dksldfkfjdk',
// title: 'first',
// selected: 'basic'
// }
itemsForSelect = ['basic', 'primary', 'admin'];
isNew: boolean = false;
constructor(private route: ActivatedRoute,
private resourceService: ResourceService,
private fb: FormBuilder,
private router: Router) {
}
ngOnInit() {
this.resourceService.getItem().subscribe(res => {
if (res.success) {
this.item = res.item;
this.createForm();
this.loaded = true;
}
});
}
createForm() {
this.form = this.fb.group({
'title': [this.item.title, Validators.compose([])],
'selected': [this.item.selected, Validators.compose([])]
});
}
}
Part of component HTML template related form:
<form [formGroup]="form" (ngSubmit)="isNew ? create() : update()" [class.error]="!form.valid && form.touched">
<div class="form-group">
<label for="item"></label>
<select placeholder="Choose Select" [formControl]="form.controls.selected" class="form-control"
id="item">
<option *ngFor="let itemForSelect of itemsForSelect">{{ itemForSelect }}</option>
</select>
</div>
<button class="btn btn-primary udpate pointer" [disabled]="!form.valid" type="submit">
{{ isNew ? 'Create' : 'Update' }}
</button>
</form>
The problem is that after updating item with, for example admin value, it has this value from server in property selected, but it still shows basic in HTML select as selected, after fetching data and showing form. How to set selected in Angular 7? I know I can use [(ngModel)] = item.selected, but as I'm using form.controls, I'm getting warning in console.
You can use patchValue on your form control like that:
public updateValue() {
this.form.get('selected').patchValue('basic');
}
Improvement: Dont use formControl with formControlName in same form control. Here is link to deeper explanation
You need to add [value] property to options
<option
[value]="itemForSelect"
*ngFor="let itemForSelect of itemsForSelect"
>{{ itemForSelect }}</option>
Sandbox: https://codesandbox.io/s/angular-l0d09
When I load page, my Category dropdown is automaticly filled with data from database, then I want select value from that dropdown and on button click post data to given url. On page load, dropdown is filled correctly without any error, but when I select any value in dropdown I get this error:
ERROR Error: Error trying to diff 'c'. Only arrays and iterables are allowed
How can I resolve this error?
My add-form.component.ts
import { Component, OnInit } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { FormGroup, NgForm } from '#angular/forms';
interface LoginFormModel{
productName?: string;
retailPrice?: string;
wholesalePrice?: string;
category?: Category;
type?: string;
productionStart?: string;
productionEnd?: string;
}
interface Category{
id?: number;
name?: string;
}
#Component({
selector: 'app-add-form',
templateUrl: './add-form.component.html',
styleUrls: ['./add-form.component.scss']
})
export class AddFormComponent implements OnInit {
model: LoginFormModel= {};
category: Category = {};
form?: FormGroup;
constructor(private httpClient: HttpClient) { }
ngOnInit() {
this.httpClient.get('http://localhost:8090/api/category/')
.subscribe(data => {
this.model.category = data;
console.log(this.model.category);
}, err => {
console.log('Error: ', err);
})
}
eventSubmit(form: NgForm){
if(form.invalid){
return;
}else{
this.onSubmit();
}
}
onSubmit() {
console.log(this.model);
this.httpClient.post('http://localhost:8090/api/product/',this.model)
.subscribe(data => {
console.log(data);
})
}
}
Dropdown:
<div class="form-group">
<label class="col-md-3 control-label" for="category">Category:</label>
<div class="col-md-9">
<select class="form-control" required id="sel2" name="category" class="form-control" #formInput="ngModel"
[(ngModel)]="model.category">
<option *ngFor="let c of model.category" value="c">{{c.name}}</option>
</select>
<div class="invalid-feedback">
Category is required!
</div>
</div>
</div>
I think there is a mistake on this line,
<option *ngFor="let c of model.category" value="c">{{c.name}}</option>
I think that value="c" should be something like [value]="c.value" or value="{{c.value}}"
If not change it to this,
[value]="c.name"
I'm new to angular and wanted to know how can i manipulate a dom element, select tag specifically, when a user clicks a button.
This is the code i'm using:
parent component:
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-add-recipe',
templateUrl: './add-recipe.component.html',
styleUrls: ['./add-recipe.component.css']
})
export class AddRecipeComponent implements OnInit {
units = [
{ id: 1, name: "test" },
{ id: 2, name: "test1" },
{ id: 3, name: "test2" },
{ id: 4, name: "test3" }
];
constructor() {}
ngOnInit() {
}
addIngredient(object) {
// doing stuff
}
}
parent view:
<input #ingredientName type="text" class="form-control" placeholder="name">
<input #ingredientQty type="text" class="form-control" placeholder="qty">
<app-select-units [units]="units"></app-select-units>
<button type="button" class="btn btn-outline-primary" (click)="addIngredient({ name: ingredientName.value, quantity: ingredientQty.value, unit: chosenUnit }); ingredientName.value=''; ingredientQty.value=''; ingredientUnit.value=''">add</button>
child component:
import { Component, OnInit, Input, ViewChild, ElementRef } from '#angular/core';
#Component({
selector: 'app-select-units',
templateUrl: './select-units.component.html',
styleUrls: ['./select-units.component.css']
})
export class SelectUnitsComponent implements OnInit {
#Input() units: string[];
#Input() selectedUnit: string;
constructor() { }
ngOnInit() {
}
}
child view:
<select [(ngModel)]="chosenUnit" #ingredientUnit class="form-control" name="selectUnit">
<option value="" [attr.selected]="!selectedUnit ? true : null" disabled>select</option>
<option *ngFor="let unit of units" value="{{ unit.id }}" [attr.selected]="selectedUnit == unit.id ? true : null">{{ unit.name }}
</option>
</select>
when the user clicks the button on the parent component, it calls it's "addIngredient" method, and clearing the two inputs.
i also try to clear the select to the first option (i know it's not possible this way).
Is there any way to bind the select to the parent component and clear it once the button click?
I have worked on angular 4 project, In this project, I have a requirement to set the first option as selected where all options are created dynamically by loop.
html code:
<select [(ngModel)]="selectedServiceType" [ngModelOptions]="{standalone: true}" (ngModelChange)="getServiceType($event)">
<ng-container *ngFor="let service of services">
<option [ngValue]="service">{{service.name}}</option>
</ng-container>
</select>
If anyone know about let me know. Thanks in advance!
Try like this :
<select class="form-control" (change)="onChange($event)">
<option *ngFor="let service of services; let itemIndex = index" [selected]="itemIndex == 0" [ngValue]="service.value">{{service.name}}</option>
</select>
component.ts
export class HomeComponent implements OnInit {
private selectedServiceType: any;
private services: Array<any> = [];
constructor() {
this.services = [{
name: "Harish",
value: 5000
}, {
name: "Chandru",
value: 5001
}]
}
onChange(e) {
this.selectedServiceType = e.target.value;
}
}
Just in your ts, inside ngOnInit
selectedServiceType : any;
ngOnInit() {
//make sure you have values for **`services`**
this.selectedServiceType = services[0];
}
add this code
<select (change)="onChange($event.target.value)" value={{selectedService}}>
<ng-container>
<option *ngFor="let service of services" >{{service.name}}</option>
</ng-container>
</select>
and you component.ts should be
export class YourClass implements OnInit {
selectedService: any;
services:any = [];
--your API call code set values to services array
this.services=this.service.APImethod()
onChange(newValue) {
this.selectedService=newValue;
}
}