I insert a textarea component into my template like so:
<div class="card-body" *ngIf="isEditing">
<app-text-area input-id="body" input-value="This is my default input value"></app-text-area>
</div>
The template of app-text-area is like so:
<textarea
placeholder="This is my placeholder"
[name]="inputID"
(input)="onInputChanged($event)"
ngModel>
{{ inputValue }}
</textarea>
The subsequent rendered HTML is like so:
<textarea _ngcontent-owj-c62="" placeholder="This is my placeholder" ngmodel="" ng-reflect-model="" ng-reflect-name="body" class="ng-pristine ng-valid ng-touched">
This is my default input value
</textarea>
However on the actual page, the inputValue text doesn't show up anywhere, the textarea acts as though it is empty, even showing the placeholder text. I can see the value in the html, though when I start typing in the box it replaces it as if it weren't there. The console shows no errors.
If I remove ngModel from the textarea, it fixes it
My app-text-area component ts is:
import { Component, EventEmitter, Input, OnInit, Output } from '#angular/core';
import { ControlContainer, NgForm } from '#angular/forms';
#Component({
selector: 'app-text-area',
templateUrl: './text-area.component.html',
viewProviders: [ { provide: ControlContainer, useExisting: NgForm } ],
styleUrls: ['./text-area.component.scss']
})
export class TextAreaComponent implements OnInit {
#Input("input-id") public inputID: string = "text";
#Input("input-value") public inputValue: string;
constructor() { }
ngOnInit(): void {
}
public onInputChanged(event: Event):void {
let newValue = (event.target as HTMLTextAreaElement).value;
this.inputValue = newValue;
}
}
Hard to help without seeing the component.ts file
But a solution would be something in the lines of the following:
HTML template:
<textarea
[name]="inputID"
(input)="onInputChanged($event)"
[value]="inputValue">
</textarea>
<p>{{inputValue}}</p>
And the component.ts:
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-text-area',
templateUrl: './text-area.component.html',
styleUrls: ['./text-area.component.css']
})
export class TextAreaComponent implements OnInit {
inputID:number=1;
inputValue:string="This is my placeholder";
constructor() { }
ngOnInit(): void {
}
onInputChanged(event:any){
this.inputValue=event.target.value;
}
}
This would set the initial value as "This is my placeholder" and would update the value on each change in the input displayed inside the p tag
I managed to fix this by setting [ngModel]="inputValue" instead of the defaultValue, value, or placing inputValue inside the textarea itself.
Related
I try to render a button and it works fine, but when I click the button it doesn't execute alertWindow function, help!:
app.component.ts:
import {
Component,
ElementRef,
OnInit,
ViewEncapsulation } from '#angular/core';
import { DomSanitizer, SafeHtml } from "#angular/platform-browser";
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
encapsulation: ViewEncapsulation.ShadowDom,
})
export class AppComponent implements OnInit {
public content: SafeHtml;
constructor(private sanitizer: DomSanitizer) {}
async ngOnInit() { this.renderButton(); }
alertWindow() { alert("don't work"); }
renderButton() {
this.content =
this.sanitizer.bypassSecurityTrustHtml(`
<button (click)='connectWallet()' class="button">
Connect your wallet
</button>`);
}
app.component.ts;
<div [innerHTML]="content"></div>
Solution
Based on what I understand you wanted to display HTML dynamically at runtime? then solution is to use
ComponentFactoryResolver
and ViewContainerRef
It will be better if you can provide more details, what you are trying to achieve, so that people can guide you
Why it didn't work?
It doesn't work because it is outside of angular, when you use innerHTML then whatever you passed to it is pure vanilla HTML and JavaScript
Try this example
(window as any).alertWindow = function () {
alert("don't works");
};
#Component({...})
export class AppComponent {
...
renderButton() {
this.content = this.sanitizer.bypassSecurityTrustHtml(`
<button onclick='alertWindow()' class="button">Connect your wallet</button>
`);
}
}
It works right?
As you can see I have moved alrertWindow function outside of component's class and added to window variable and also changed (click) to onclick
How to prevent duplicate values during insert record into an array using angular6+
PARENTCOMPONENT.HTML:
<div class="form-group" style="margin-left:30px;margin-top:30px;">
<input type="text" class="form-control" placeholder="Posts" name="post" [(ngModel)]="post" #clearText>
</div>
<button type="submit" class="btn btn-sm btn-primary" (click)="AddServer(post)"
style="margin-left:30px;margin-top:10px;" (blur) = "clearText.value = ''">Click</button>
<app-child [childPost]="parentPosts"></app-child>
PARENTCOMPONENT.TS:
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-parent',
templateUrl: './parent.component.html',
styleUrls: ['./parent.component.css']
})
export class ParentComponent implements OnInit {
post = '';
parentPosts: any[] = [];
constructor() { }
ngOnInit() {
}
AddServer(post)
{
this.parentPosts.push(post);
console.log(post);
}
}
CHILDCOMPONENT.HTML:
<div style="margin-left: 30px; margin-top:10px;" *ngFor="let p of childPost">
<p>{{p}}</p>
</div>
CHILDCOMPONENT.TS:
import { Component, OnInit, Input } from '#angular/core';
#Component({
selector: 'app-child',
templateUrl: './child.component.html',
styleUrls: ['./child.component.css']
})
export class ChildComponent implements OnInit {
#Input() childPost: any[] = [];
constructor() { }
ngOnInit() {
}
}
Hi guys the above code was insert data from parent component to child component using textbox values and button in that PARENCOMPONENT.TS code what i need is during the time of pushing value into an array the values must be unique if i post repeated value it throws an alert or error message the value was already inserted like that so please kindly help me to resolve this....
You could use Set data structure that will omit duplicate Insertions which is better then having an extra loop to verify if it's already in the array and then omit it.
parentPosts: Set = new Set();
// then use it like
this.parentPosts.add(post); // if post already exists it'll just not add it
Test if it contains it first
if (!this.parentPosts.includes(post)) {
this.parentPosts.push(post);
}
I have a web page that uses angular form. This page is basically a user data so it shows the name, phone, mail, etc of the user.The data are obtained using a mongoDB database. I want it to show by default the value already set in placeholder and I want for the user to be possible to change it as well. If they don't type anything in the field then the value that should be passed is the placeholder. For example the value {{this.cliente.nome}} when it is in a different field than the input one but when I try to use it as default value of input it doesn't work. It says "Cannot read property 'nome' of undefined" when the other one works. The data comes correct from the mongoDB but it isn't working. This is my code:
import { Component, OnInit } from '#angular/core';
import { UserService } from '../user.service';
import { User } from 'src/user';
import { FormGroup, FormControl, FormArray, FormBuilder } from "#angular/forms";
import { Router } from '#angular/router';
#Component({
selector: 'app-cliente-dados',
templateUrl: './cliente-dados.component.html',
styleUrls: ['./cliente-dados.component.css']
})
export class ClienteDadosComponent implements OnInit {
cliente: User;
updateForm: FormGroup;
constructor(
private userService: UserService,
private formBuilder: FormBuilder,
public router: Router
) {
this.updateForm = this.formBuilder.group({
nomeUpdate: this.formBuilder.control("")
})
}
ngOnInit(): void {
this.getCliente();
}
getCliente(){
this.userService.getUser(localStorage.getItem('userAtual')).subscribe(user => {
this.cliente = user[0];
});
}
updateCliente(updateData){
console.log("update");
}
}
<form [formGroup]="updateForm" (ngSubmit)="updateCliente(updateForm.value)">
<div class="data">
<img id="iconePerfil" src="assets/Imagens/Icones/perfil.png">
<div id="informacaoRegisto">
<div class="container">
<label id="nome"><strong>{{this.cliente.nome}} <!--This one shows the value--></strong></label>
<input class="input" type=" text " [(value)]="this.cliente.nome" formControlName="nomeUpdate"> <!--Here the value isn't shown-->
<span class="border"></span>
</div>
</div>
</div>
<button type="submit" class="submit">Atualizar Dados</button>
</form>
Representation of the issue: top and bottom values are shown(not input field)
Middle one not shown(input field with default value)
You are using FormBuilder and as such the value property of input is not used. The initial value is initialized by the FormControl
Remove the following from the constructor
this.updateForm = this.formBuilder.group({
nomeUpdate: this.formBuilder.control("")
})
Modify getCliente()
getCliente(){
this.userService.getUser(localStorage.getItem('userAtual'))
.pipe(first()).subscribe(user => {
this.cliente = user[0];
this.updateForm = this.formBuilder.group({
nomeUpdate: this.formBuilder.control(this.cliente.nome)
})
});
}
Have added .pipe(first()) so only first value received is used.
Hope it helps!
I have created a parent component as follows:
<form [formGroup] = "cardForm">
<app-inputvalidator [controls] = "cardForm.get('name')"></app-inputvalidator>
</form>
Parent ts file
import { Component, OnInit } from '#angular/core';
import { FormGroup, FormControl,Validators } from '#angular/forms';
#Component({
selector: 'app-card-form',
templateUrl: './card-form.component.html',
styleUrls: ['./card-form.component.css']
})
export class CardFormComponent implements OnInit {
nameFormControl ;
cardForm = new FormGroup({
name: new FormControl('', [Validators.minLength(5),Validators.maxLength(25)])
});
constructor() {
}
ngOnInit(): void {
this.nameFormControl = this.cardForm.get('name');
}
}
I am passing the nameFormControls to the child component and accessing it in the template as well as class as follows:
InputValidator.ts
import { Component, OnInit, Input } from '#angular/core';
import { FormControl} from '#angular/forms';
#Component({
selector: 'app-inputvalidator',
templateUrl: './inputvalidator.component.html',
styleUrls: ['./inputvalidator.component.css']
})
export class InputvalidatorComponent implements OnInit {
#Input() controls: FormControl;
constructor() {
}
ngOnInit(): void {
}
}
Input Validator.html
<input [formControlName] = "controls"
<br>
<div>{{ controls.errors | json}}</div>
The project is compiled successfully with no errors.
I am getting the value of controls.errors to always null.
Why can I not print the object controls.errors using string interpolation as the value in the name input box changes?
you get null becuase you don't put required validator the min,maxLength validators will return an error if there is value and the value is not valid , if the value is null or empty string this will consider a valid
check the validator 👉 source
After searching for like two hours for a solution I decided to ask some pros suspecting the solution could be quite simple.
It is an Angular7 project.
I would like to have a "goal" in my goals component with a button "+". When you click that button I want to have annother goal being added to the page. So I want to click a button of the goal component to create a new goal, which is something like recursive to me.
goals.component.html:
<input type="text" value="Ich brauche einen Laptop für maximal 1000 Euro.">
<br/>
<br/>
<app-goal id="{{lastGivenId+1}}"></app-goal>
goals.component.ts:
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-goals',
templateUrl: './goals.component.html',
styleUrls: ['./goals.component.scss']
})
export class GoalsComponent implements OnInit {
lastGivenId: number = 0;
constructor() { }
ngOnInit() {
}
}
goal.component.ts and goal.component.html:
//Typescript code
import { Component, OnInit, Input } from '#angular/core';
#Component({
selector: 'app-goal',
templateUrl: './goal.component.html',
styleUrls: ['./goal.component.scss']
})
export class GoalComponent implements OnInit {
#Input() id : number;
constructor() { }
ngOnInit() {
}
onAddLowerGoal(currentGoalID:number){
// var goalElement = document.registerElement('app-goal');
// document.body.appendChild(new goalElement());
let newGoal = document.createElement("app-goal");
newGoal.setAttribute("id", "999");
let currentGoal = document.getElementById(currentGoalID.toString());
document.body.insertBefore(newGoal, currentGoal);
}
}
<html>
<div id="{{id}}" class="goal">goal{{id}}</div>
<button id="AddLowerGoal1" (click)="onAddLowerGoal(999)">+</button>
</html>
This way, it creates an app-goal element, but the div and button elements within the app-goal element is missing.
How can this problem be solved? Any help is welcome. Thanks in advance.
First glance: delete the html tags from your goal.component.html file.
Next: you can recursively add app-goal using angular. Inserting app-goal element the javascript way only adds the <app-goal></app-goal> object. It doesn't create an angular component. It doesn't bind your data.
Also if you're using Angular's #Input, you need to assign a component input with square braces. Do not use tags.
goals.component.html:
<input type="text" value="Ich brauche einen Laptop für maximal 1000 Euro.">
<br/>
<br/>
<app-goal [id]="lastGivenId+1"></app-goal>
goal.component.html:
<div id="{{id}}" class="goal">goal{{id}}</div>
<button id="AddLowerGoal1" (click)="onAddLowerGoal(999)">+</button>
<div *ngFor="let subGoal of subGoals">
<app-goal [id]="subGoal.id"></app-goal>
</div>
goal.component.ts:
import { Component, OnInit, Input } from '#angular/core';
#Component({
selector: 'app-goal',
templateUrl: './goal.component.html',
styleUrls: ['./goal.component.scss']
})
export class GoalComponent implements OnInit {
#Input() id : number;
subGoals: Array<any> = [];
constructor() { }
ngOnInit() { }
onAddLowerGoal(currentGoalID: number){
this.subGoals.push({id: currentGoalID});
}
}
You can also use a service to store your goals and subgoals to access them later.
I think what you're looking for is a Reactive Form with FormArray with dynamically added form controls.
Take a look at this for eg:
import { Component } from '#angular/core';
import { FormControl, FormGroup, FormArray, FormBuilder } from '#angular/forms';
#Component({...})
export class GoalsComponent {
goalsForm: FormGroup;
constructor(private fb: FormBuilder) {}
ngOnInit() {
this.goalsForm = this.fb.group({
goals: this.fb.array([])
});
}
onFormSubmit() {
console.log('Form Value: ', this.goalsForm.value);
}
get goals() {
return (<FormArray>this.goalsForm.get('goals')).controls;
}
addGoal() {
(<FormArray>this.goalsForm.get('goals')).push(this.fb.control(null));
}
}
And here's the template for this:
<h2>Goals:</h2>
<form [formGroup]="goalsForm" (submit)="onFormSubmit()">
<button type="button" (click)="addGoal()">Add Goal</button>
<hr>
<div *ngFor="let goal of goals; let i = index;" formArrayName="goals">
<div>
<label for="goal">Goal {{ i + 1 }}: </label>
<input type="text" id="goal" [formControlName]="i">
</div>
<br>
</div>
<hr>
<button>Submit Form</button>
</form>
Here's a Sample StackBlitz for your ref.