Reputation: 125
I need to add a button with the Material Angular 2 style. So I have a button that does this:
<button mat-button (click)="addElement($event, 'button')">Add button</button>
Where addElement is defined:
addElement(ev, tag) {
const htmlElem = ev.currentTarget;
const el = this.renderer.createElement(tag);
this.renderer.setAttribute(el, 'mat-button', '');
el.textContent = 'New Button';
htmlElem.parentNode.insertBefore(el, null);
}
Clicking on the button then creates a new element in my HTML, shown as:
<button mat-button">Add button</button>
The function code correctly generates the button, however it doesn't apply all children as shown in the original button code from the material code
So do I have a way to "refresh" the button so that the everything from the standard Mat-button applies to the button added via the JS code?
Upvotes: 2
Views: 1046
Reputation: 2674
You are right that you have added the mat-button attribute but since you are creating a button dynamically you did not be able to achieve to generate the whole structure of mat-button.
Below is the whole style and structure of mat-button
<button class="mat-button" mat-button="">
<span class="mat-button-wrapper">Add button</span>
<div class="mat-button-ripple mat-ripple"></div>
<div class="mat-button-focus-overlay"></div>
</button>
As you can see there are other html elements in the mat-button which includes ripple effects and focus overlay.
We are going to use Angular Renderer to create html element, set the attribute to the element and to append it on an element.
create the button that will trigger the append
<button id="clickBtn" (click)="onClick()">Click here to add Button</button>
import the import Directive, ElementRef, Renderer2
in the component.
{ Component, Directive, ElementRef, Renderer2 } from '@angular/core';
add a directive that will target the html element where the button will get appended (#clickBtn [is the id tag of the button that we created)
@Directive({
selector: '#clickBtn'
})
create a constructor to inject renderer and elementref
constructor(private renderer: Renderer2,private elRef: ElementRef) {
}
trigger the click event to append the button
onClick() {
const btn = this.renderer.createElement('button');
const span = this.renderer.createElement('span');
const div1 = this.renderer.createElement('div');
const div2 = this.renderer.createElement('div');
const text = this.renderer.createText('I am a Generated Button');
const attrBtn = this.renderer.setAttribute(btn, 'class', 'mat-button');
const attrSpan = this.renderer.setAttribute(span, 'class', 'mat-button-wrapper');
const attrDiv1 = this.renderer.setAttribute(div1, 'class', 'mat-button-ripple mat-ripple');
const attrDiv2 = this.renderer.setAttribute(div2, 'class', 'mat-button-focus-overlay');
this.renderer.appendChild(span, text);
this.renderer.appendChild(btn, span);
this.renderer.appendChild(btn, div1);
this.renderer.appendChild(btn, div2);
this.renderer.appendChild(this.elRef.nativeElement, btn);
}
Woah so what going on here. as you can see we generate here all the structure of the mat-button
To know more about Renderer2 Please visit this link.
https://alligator.io/angular/using-renderer2/
Please see the link of live code on stackblitz
https://stackblitz.com/edit/dmgrave-ng-so-answer-dom?file=app%2Fapp.component.ts
Hope this helps.
Upvotes: 2
Reputation: 3418
I'm not sure why you want to generate the buttons dynamically but I would do it something like this
In your template:
<button mat-raised-button (click)="addNewButton()">Add new </button>
<div *ngFor="let btn of buttonsList">
<button mat-raised-button color="primary">
{{btn+1}}
</button>
</div>
In your component:
export class AppComponent {
buttonsList = [];
addNewButton():void{
const newId = this.buttonsList.length;
this.buttonsList.push(newId);
}
}
You just have to loop through your array and display the buttons. Every time you add a new button, you just have to push a new value to your array and let the framework do the heavy lifting.
Here's the stackblitz demo : https://stackblitz.com/edit/angular-7rfwrx?file=app%2Fapp.component.ts
Hope this helps.
Upvotes: 1