How to change button label on click? - html

When I click on this button,I want label to change. HTML:
<button pButton type="button" label="Edit" (click) = "foo()" style="width:auto"></button>
For example : before - "Edit", click, after - "Save".

You can simply bind it to your component variable inside your <button> tag.
<button pButton type="button" (click)="foo()"> style="width:auto">
{{myLabel}}
</button>
and in your component class:
#Component({
templateUrl:'./mytemplate'
})
export class MyComponent implements OnInit {
myLabel:string;
ngOnInit() {
this.myLabel = 'Edit';
}
foo() {
this.myLabel = 'Save';
}
}
Here is a working plunker: https://plnkr.co/edit/8TOn8oN63pgJ7eA7h7tY?p=preview

In your component class
#Component({
templateUrl:'./mytemplate'
})
export class MyComponent implements OnInit {
myLabel:string;
ngOnInit() {
this.myLabel = 'Edit';
}
foo() {
this.myLabel = 'Save';
}
}
In your html
<button pButton type="button" [attr.label]="myLabel" (click)="foo()" style="width:auto"></button>
Note that the html syntax has changed to start using property binding, where the "label" attribute of the node associated with the button element is being updated with the value of the myLabel variable in the component.
Read more about template and property bindings in this guide
https://angular.io/guide/template-syntax#property-binding
As a side note, if your requirement is to change the text displayed on the button, I would use interpolation as below
<button pButton type="button" (click)="foo()" style="width:auto">{{myLabel}}</button>
See this plunkr for a working example https://plnkr.co/edit/wEXKxP88kcsLKuBcUUxZ?p=preview

You can bind attributes via [attr.myAttribute] directive and as in your case you have to use [attr.label] to bind a value to the label attribute.
Inside your component you can define a label property which gets toggled on click:
class MyComponent {
private labelStates = ['Edit', 'Save'];
public label: string = this.labelStates[0];
public toggleLabel() {
let index = +(this.label === this.labelStates[0]);
this.label = this.labelStates[index];
}
}
And use it for your button:
<button [attr.label]="label" (click)="toggleLabel()"></button>
In case you want to change the button text use this:
<button (click)="toggleLabel()">{{ label }}</button>

Related

Results not displayed with click event (Angular)

I'm new to Stackoverflow and to Angular. I'm writing a frontend app (an ecommerce) in Angular. I binded a click event to a button of a mat-menu in order to have the following behavior: when I click on the button I want to display the products of the category that has been clicked. For example, if I click the button "Make-up" I want that all the products with category "Make-up" will be displayed. The problem is that when I click on the button nothing is displayed on the browser, but I suppose that the logic of the app works because if I open the console of the browser the producs of the selected category are printed out.
product.component.html:
<mat-menu #menu="matMenu">
<button mat-menu-item (click)="categoryFilter('Make-up')"> Make-up</button>
...
</mat-menu>
product.component.ts:
#Component({
selector: 'app-product',
templateUrl: './product.component.html',
styleUrls: ['./product.component.css'] })
export class ProductComponent implements OnInit {
public products: Product[] = [];
public product!: Product;
constructor(private productService: ProductService) { }
ngOnInit() {
this.getProducts();
}
public getProducts(): void{
this.productService.getProducts().subscribe(
(response: Product[]) => {
this.products= response;
},
(error: HttpErrorResponse) => {
alert(error.message);
}
);
}
public categoryFilter(category: string): void{
this.productService.getProductsByCategory(category).subscribe(
(response: void) => {
console.log(response);
},
(error. HttpErrorResponse)=>{
alert(error.message);
}
)
} }
I think you have missed binding the response to a property, and then using that property to display the data on your browser.
I don't know the response type, for demo purposes let's say it's a string.
First, you'll need to create a property just like you created public product!: Product; we'll call it categoryName: string
In the click event, you'll have to bind this property with your response, hence it should look something like this:
public categoryFilter(category: string): void{
this.productService.getProductsByCategory(category).subscribe(
(response: string) => {
this.categoryName = response;
console.log(response);
},
(error. HttpErrorResponse)=>{
alert(error.message);
}
)
}
Now You'll have to bind that categoryName in your HTML so that it can be displayed. You can use Angular's text interpolation which uses curly brackets {{}} to display string values in the HTML.
Hence your HTML will look like this:
<mat-menu #menu="matMenu">
<button mat-menu-item (click)="categoryFilter('Make-up')"> {{ categoryName }} </button>
...
</mat-menu>
I advise you to read Angular's Guide as you proceed further.
Angular's text interpolation: https://angular.io/guide/interpolation

Angular material Modal dialog not able to pass event to parent?

I have a component which has one child component. Child component has a button which will open a material dialog Box.
In dialog we have form, username and passwrod and submit button. When I submit i am calling backend REST api.
this is getting called in child component:
dialogRef.afterClosed().subscribe(result => {
console.log("result", result);
this.onModalClosePassData.emit(result);//emit to parent
});
which is sending event to parent. updateComment() is getting called and I can see the data in console.
But when I fill the form and click on submit. It calls submitForm method which is asynchronus call and I am closing dialog after successful login.But then event is not emmiting. updateComment() is not getting called.
See the full code:
parent component.html
<ng-template #showTextOnly>
<child-component [branch]="releaseBranch" [date]="dateString"
(onModalClosePassData)="updateComment($event)">
</child-component>
</ng-template>
parent component.ts
//This method is getting called when i click on backDrop,
but If i logged in successfully this is not getting called
updateComment(event:any){
consile.log(event);
}
child-component.html
<button class="btn btn-default" (click)="openDialog()">Login</button>
child-component.ts
export class ChildComponent implements OnInit {
#Output() onModalClosePassData = new EventEmitter();
constructor(public dialog: MatDialog) { }
openDialog(): void {
const dialogConfig = new MatDialogConfig();
dialogConfig.disableClose = false;
dialogConfig.autoFocus = false;
dialogConfig.hasBackdrop= true;
dialogConfig.width = '300px';
dialogConfig.autoFocus=true;
dialogConfig.data = {branch: this.branch, date: this.date};
const dialogRef = this.dialog.open(LoginDialog, dialogConfig);
dialogRef.afterClosed().subscribe(result => {
console.log("result", result); //result is getting called in both cases
this.onModalClosePassData.emit(result);
});
}
}
LoginDialog.component.ts
import {MatDialogRef, MAT_DIALOG_DATA} from '#angular/material/dialog';
export class LoginDialog implements OnInit{
constructor(private loginService: LoginService, public dialogRef: MatDialogRef<LoginDialog>,
#Inject(MAT_DIALOG_DATA) public data: any) {}
public submitForm = (formValue: any) => {
if (this.noteForm.valid) {
let encryptData = btoa(`${formValue.username}:${formValue.password}`);
this.loginService.login(encryptData)
.subscribe((response:any)=>{
if(response.STATUS === "FAILED"){
} else {
this.dialogRef.close(this.noteDetail);
}
})
}
}
}
LoginDialog.component.html
<form [formGroup]="noteForm" autocomplete="off" novalidate (ngSubmit)="submitForm(noteForm.value)">
<mat-dialog-content class="mat-typography">
<mat-form-field>
<mat-label>User Name</mat-label>
<input matInput type="text" formControlName="username" id="username">
</mat-form-field>
<mat-form-field>
<mat-label>Password</mat-label>
<input matInput type="password" formControlName="password">
</mat-form-field>
</mat-dialog-content>
<mat-dialog-actions align="center">
<button mat-raised-button color="primary" [disabled]="!noteForm.valid">Submit</button>
</mat-dialog-actions>
</form>
I have faced same issue and figured it out, may be this is usefull for others.
We will get this issue when we used custom component on modal. For example, we have formComponent on pop up modal and on submit we need to close the modal and emit the form value, this should work but we can face the issue when our formComponent is destroyed before emitting the value.
This is because we opened our formComponent on Modal later on form submit we closed the modal which contains formComponent and opened success modal then trying to emit the value.
Solution is: Don't close modal which contains formComponent before emmiting the value or else use a service to trigger.

Trigger button click from another component button in angular 4

I have component A button which displays form on click and component B button to show name. I want to trigger ComponentA button and display form when componentB button is clicked
componentA HTML
<section>
<button (click)="toggle()">Click Here To Search</button>
<div *ngIf="!showInput">
<input type="text"/><br/>
<button type="submit">Submit</button>
<button>Cancel</button>
</div>
</section>
componentA TS
showInput = true;
//...
toggle() {
this.showInput = !this.showInput;
}
componentB HTML
<button (click)="toggleText()">Add Fruit</button>
<div *ngIf="showText">Apple</div>
I have created an example.Please use this link
Example Link
Well in that case make use of rxjs BehaviorSubject in a service, so that your entire application can make use of the variable and will update accordingly, like below
import { Injectable } from '#angular/core';
import { BehaviorSubject } from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class Service {
toggle: BehaviorSubject<boolean> = new BehaviorSubject(false);
toggle$ = this.toggle.asObservable();
}
and in your my text component
toggleText() {
this.showText = !this.showText;
this.service.toggle.next(this.showText)
}
and in your FormsComponent
showInput;
ngOnInit() {
this.service.toggle$.subscribe(
toggle => this.showInput = toggle
)
}
Working demo

How to dynamically change attribute name in Angular template?

How to dynamically change which property is set on an HTML element in the template?
I have an anchor wrapper component, which accepts both href and routerLink properties. Only one of them needs to be set. I want to write it's template, so that I'm setting only one of href and routerLink attributes on <a> element, whichever is defined.
Is it possible without separately defining both cases with *ngIf?
anchor.component.ts
import { Component, Input, OnInit } from '#angular/core';
#Component({
selector: 'my-anchor',
templateUrl: './anchor.component.html',
styleUrls: ['./anchor.component.scss'],
})
export class AnchorComponent implements OnInit {
#Input() public label: string;
// Only one of href and routerLink must be specified
#Input() public href?: string;
#Input() public routerLink?: string;
ngOnInit() {
this.ensureEactlyLinkTargetDefined();
}
private ensureEactlyLinkTargetDefined(): void {
if (!((this.href && !this.routerLink) || (!this.href && this.routerLink))) {
throw new Error("Exactly one of the properties 'href' and 'routerLink' must be defined");
}
}
}
anchor.component.html
<a
<!--
Here lies the problem. I only want to set one of those
attributes, not both simultaneously, as then href is not
respected, as routerLink directive overwrites it
-->
[href]="href"
[routerLink]="routerLink"
<!--
Something like [attr]="setAttribute(attributeName, attributeValue)"
-->
>
{{ label }}
</a>
Well instead of binding an attribute/directive, you should bind an event :
<a (click)="doSomething($event)">My link</a>
doSomething(event: MouseEvent) {
if (condition) this.router.navigate(url); // [routerLink]
else window.location.href = url; // href
}
EDIT If you want to achieve that, simply put this code into a directive
#Directive({ selector: 'navigator' })
export class NavigatorDirective {
#Input('navigator.condition') condition: boolean;
constructor(private router: Router) {}
#HostBinding('click', ['$event'])
doSomething(event: MouseEvent) {
if (this.condition) this.router.navigate(url); // [routerLink]
else window.location.href = url; // href
}
}
<a [navigator]="url" [navigator.condition]="myCondition">My link</a>

Cant create dynamic textboxes using Renderer2 in angular4

i'm working on Angular 4 and creating textboxes dynamically by clicking on a button using Renderer2. I had tried it on a dummy project first and it works well but when i put the code in my real project it won't work and there is no error on console and i had checked that the function is triggering or not by putting console.log in it and function is triggering and message is showing in the console but textbox creating code is not working. Can anyone help me in this?
Type script function
constructor(private renderer:Renderer2, private el: ElementRef ) { }
addfield() {
console.log('function triggered');
const div = this.renderer.createElement('div');
const input = this.renderer.createElement('input');
this.renderer.appendChild(div, input);
this.renderer.addClass(div, 'col-md-6');
this.renderer.addClass(div, 'col-sm-6');
this.renderer.addClass(div, 'col-xs-12');
console.log('cross passes the code');
this.renderer.addClass(input, 'form-control');
this.renderer.addClass(input, 'col-md-7');
this.renderer.addClass(input, 'col-xs-12');
}
Html code
<button class="btn btn-success" (click)="addfield()" >Add New Fiels +</button>
<div id="textboxes"></div>
<button class="btn btn-success" (click)="addfield()" >Add New Fiels +</button>
//
constructor(private renderer: Renderer2) {
}
addfield() {
....
const textboxes = document.querySelector('#textboxes'); //to get element
this.renderer.addClass(textboxes , "col-md-6"); //this is for add class
let divel= this.renderer.createElement('div'); //this is for create an element
this.renderer.appendChild(textboxes, divel); //this is for append a child element
}
Your code is absolutely fine, only issue is you are not appending dynamically created
elements to the ui
Component :
constructor(private renderer:Renderer2, private el: ElementRef ) {}
addfield() {
....
const textboxes = document.getElementById('textboxes');
this.renderer.appendChild(textboxes, div);
}
Template :
<div id="textboxes"></div>
<button class="btn btn-success" (click)="addfield()" >Add New Fiels +</button>
Here is the link to working demo :
https://stackblitz.com/edit/angular-dynamic-textbox
Try like this :
missing the following line to add dynamic textboxes this.renderer.appendChild(this.el.nativeElement, div);
addfield() {
const div = this.renderer.createElement('div');
const input = this.renderer.createElement('input');
this.renderer.appendChild(div, input);
this.renderer.addClass(div, 'col-md-6');
this.renderer.addClass(div, 'col-sm-6');
this.renderer.addClass(div, 'col-xs-12');
this.renderer.addClass(input, 'form-control');
this.renderer.addClass(input, 'col-md-7');
this.renderer.addClass(input, 'col-xs-12');
this.renderer.appendChild(this.el.nativeElement, div);
}