I'm having trouble finding the best way to inject static html from a file into the middle of my view. I have a component called eula-dialog in which the component doesn't do anything yet but the view looks like this:
eula-dialog.component.html
<h1 md-dialog-title>Sign EULA</h1>
<mat-dialog-content>
<!-- HOW TO INJECT A FILE HERE -->
<div> REPLACE ME WITH CONTENTS OF FILE</div>
</mat-dialog-content>
<mat-dialog-actions>
<mat-checkbox [(ngModel)]="agreeCheckbox">I have read and agree to the eula</mat-checkbox>
<button md-raised-button color="primary" mat-dialog-close [disabled]="!agreeCheckbox">
I Agree
</button>
</mat-dialog-actions>
I have a folder structure that looks like this:
eula-dialog
eula-dialog.component.html
eula-dialog.component.scss
eula-dialog.component.spec.ts
eula-dialog.component.ts
very-long-readonly-eula-template.html
I can't modify the contents of the eula HTML, which has mostly text and some html elements but is not a complete page, it looks like this:
<p>Title</p>
<div> LOTS OF TEXT </div>
What's the best way to do this?
Also it would be best that this eula html file/template doesn't load with the app all the time but only gets sent to the client when needed.
Put static files in assets folder else tell angular to mark it as asset in angular.json.
Then use
<h1 md-dialog-title>Sign EULA</h1>
<mat-dialog-content>
<!-- HOW TO INJECT A FILE HERE -->
<div [innerHTML]="eulaContent">...</div>
</mat-dialog-content>
<mat-dialog-actions>
<mat-checkbox [(ngModel)]="agreeCheckbox">I have read and agree to the eula</mat-checkbox>
<button md-raised-button color="primary" mat-dialog-close [disabled]="!agreeCheckbox">
I Agree
</button>
</mat-dialog-actions>
// In .ts file
import { DomSanitizer} from '#angular/platform-browser';
eulaContent = '';
constructor(private sanitizer: DomSanitizer)
ngOnInit(){
fetch('/assets/yourlocation.html').then(res => res.text()).then(data => {
this.eulaContent = this.sanitizer.bypassSecurityTrustHtml(data);
})
}
Related
I have this button, I need to add Pendo Data that is dynamically working based on which button we chose. Mostly this is making the Button unique. When I have a button that is not changing I add like this:
<button mat-button
data-pendo="pendo-prospects-send-application"
class='round-button'
color='primary'
type='button'
.....>
</button>
But sometime I need to add this data to one button that is changing based on CSS class. I am not sure how check for that.
For example I need to add to a button when :
if [class.fa-pencil] then data-pendo "Something"
if [class.fa-plus] then data-pendo "Something else"
This is the button that changes base on class:
<button mat-button
class='round-button'
type='button'
[class.disabled-button]='GuidId'
color='primary'
(click)='onAssignLoanOfficer()'>
<i class='fal'
[class.fa-pencil]='GuidId'
[class.fa-plus]='!GuidId'></i>
</button>
How I can do that?
Based on your comments I think this is what you want to do:
<button
(click)="onAssignLoanOfficer()"
[class.disabled-button]="GuidId"
[attr.data-pendo]="GuidId ? 'pendo-edit-loan' : 'pendo-add-loan'"
class="round-button"
color="primary"
type="button">
<i [class.fa-pencil]="GuidId"
[class.fa-plus]="!GuidId"
class="fall">
</i>
</button>
ALTERNATIVE:
As a more sophisticated alternative (I really don't know how you intend to use what you're asking for), you can build a directive to add the attribute you want based on a map of class-to-pendo-data conversion information:
#Directive({
selector: '[addPendoData]'
})
export class AddPendoDataDirective implements AfterViewInit {
constructor(private _el: ElementRef, private _renderer: Renderer2) {}
ngAfterViewInit() {
const pendoData: string | null | undefined = this._getPendoValue();
if (!pendoData) { return;}
const $button: HTMLElement = this._el.nativeElement;
this._renderer.setAttribute($button, 'data-pendo', pendoData);
}
private _getPendoValue() {
const $child: HTMLElement = this._el.nativeElement;
if(!$child) { return null; }
const $i: HTMLElement = $child.querySelector('i');
if(!$i) { return null; }
const listOfClasses: string[] = $i.className.split(' ');
if (!(listOfClasses && listOfClasses.length)) { return null; }
for(const className of listOfClasses) {
if(PENDO_MAP[className]) { return PENDO_MAP[className]; }
}
return null;
}
}
const PENDO_MAP: { [className: string]: string } = {
'fa-pencil': 'pendo-edit-loan',
'fa-plus': 'pendo-add-loan'
// add other mappings here...
};
and you can use it like this:
<button
(click)="onAssignLoanOfficer()"
[class.disabled-button]="GuidId"
addPendoData
class="round-button"
color="primary"
type="button">
<i [class.fa-pencil]="GuidId"
[class.fa-plus]="!GuidId"
class="fall">
</i>
</button>
I've put together this stackblitz demo.
You could define a directive, as julianobrasil suggests.
I want to point a different way to achieve this using Angular templates.
Define two buttons, addition and edition, separately.
Put a default where you want to be rendered
<div class="action-button" *ngIf="GuidId">
<!-- Add button -->
<button mat-button
data-pendo="pendo-add-loan"
(click)="add(...)"
class="round-button"
color="primary">
<i class="fal fa-plus"></i>
</button>
</div>
Then, define a ng-template tag with the other button definition. A completely fresh new.
<ng-template #edit-button>
<div class="action-button">
<!-- Edit button -->
<button mat-button
(click)="edit(...)"
data-pendo="pendo-edit-loan"
class="round-button"
color="primary">
<i class="fal fa-pencil"></i>
</button>
</div>
</ng-template>
Finally, just change the *ngIf statement to render either an addition button or an edition one.
<div class="action-button" *ngIf="!GuidId else edit-button">
<!-- Add button here -->
</div>
This is a way that scales in order to keep components isolated. The buttons are not related anymore, so you can implement w/o having to condition every style, action, etc.
Hope it helps.
I want to submit the form on the button click as well as navigate to the next page, but it shows an error : "Form submission canceled because the form is not connected".
Can anyone help me with this problem ?? I am using nebular.
This is the html code
<nb-step [label]="labelOne" [stepControl]="formOne">
<ng-template #labelOne>Device type</ng-template>
<form class="form-inline" #formOne="ngForm" >
// Code goes here...
<div class="buttonHolder">
<button nbButton routerLink="/dashboard" nbStepperNext>Cancel</button>
<button nbButton outline status="primary" (ngSubmit)="onSubmit(formOne)"
nbStepperNext [disabled]="!formOne.valid">Next</button>
</div>
</form>
</nb-step>`
This is the .ts code
onSubmit(form: NgForm) { console.log(form.value); form.reset(); }
To change page after submitting the form try to import Router and register it in constructor(private _router: Router) in your .ts file.
At the end of onSubmit() method add this._router.navigateByUrl('/pathOfYourNextPage'); and in this way you'll make redirect throught your .ts file.
Hope that will help!
You can try to below way
ts file
onSubmit(formOne: NgForm) {
console.log(formOne.value);
this._router.navigate(['/navigation page link']); // navigation url link
formOne.reset();
}
constructor(){
private _router: Router,
}
HTML file
<nb-step [label]="labelOne" [stepControl]="formOne">
<ng-template #labelOne>Device type</ng-template>
<form class="form-inline" #formOne="ngForm" (ngSubmit)="onSubmit(formOne)" >
// Code goes here...
<div class="buttonHolder">
<button nbButton routerLink="/dashboard" nbStepperNext>Cancel</button>
<button nbButton type= "submit" outline status="primary"
nbStepperNext [disabled]="!formOne.valid">Next</button>
</div>
</form>
In below sample, I have used ng-template like below and it is working fine.
Sample link: click here
<ng-template #template let-dataSource="">
<span *ngIf="dataSource.iconCss" class="e-menu-icon {{dataSource.iconCss}}"></span> {{dataSource.header}} {{dataSource.text}}
<span *ngIf="dataSource.templateHeader" class="e-login-content">
<button ejs-button cssClass="e-info">Sign In</button>
</span>
</ng-template>
But I want to create a new file for ng-template content and I want to use it in another file. I have tried like below but not working. Please help me find a solution for this case.
template.html
<ng-template #template let-dataSource="">
<span *ngIf="dataSource.iconCss" class="e-menu-icon {{dataSource.iconCss}}"></span>
{{dataSource.header}} {{dataSource.text}}
<span *ngIf="dataSource.templateHeader" class="e-login-content">
<button ejs-button cssClass="e-info">Sign In</button>
</span>
</ng-template>
default.html
<div class="control-section">
<ejs-menu #menu [items]='dataSource' [fields]='menuFields'>
<ng-container *ngTemplateOutlet="template;"></ng-container>
</ejs-menu>
</div>
Sample 2: sample 2
ref stackoverflow question: angular2 ng-template in a separate file
i got an answer for this question from github angular
please check this https://github.com/angular/angular/issues/27503
Answer:
step1:
i have initialized my template as a new component as like below
template.component.ts
import { Component, Input } from '#angular/core';
#Component({
selector: 'app-device',
template: `
<span *ngIf="dataSource.iconCss" class="e-menu-icon {{dataSource.iconCss}}"></span>
{{dataSource.header}} {{dataSource.text}}
<span *ngIf="dataSource.templateHeader" class="e-login-content">
<button ejs-button cssClass="e-info">Sign In</button>
</span>
`
})
export class DeviceComponent {
#Input()
dataSource: any;
}
Then i have used that component template in my parent component as like below
default.html
<div class="control-section">
<ejs-menu #menu [items]='dataSource' [fields]='menuFields'>
<ng-template #template let-dataSource>
<app-device [dataSource]="dataSource"></app-device>
</ng-template>
</ejs-menu>
</div>
sample link sample click me
You can have a component for your templates (name it tplComponent) and inside that, create as many templates as you want. Then in other components, get an instance of tplComponent and get the template from that. Here is a question that has an example of this approach (I haven't tried that though).
Please let me know if that works.
You can use *ngTemplateOutlet to archive the same
Please refer the link below
ngTemplateOutlet
I don't think you're supposed templates like that. Simply create a classic component and if you need a template reference, wrap it in ng-template.
I have used angular-materialize theme. I am beginner for Angular framework.
But I don't find a right way to export table as pdf.
I have created demo sample from
https://material.angular.io/components/table/overview
this official site.
My requirement is select date and then allow user to print in pdf.
if anyone has an idea or example, It would be very helpful.
Demo:
https://stackblitz.com/angular/xbprlqrqjyq?file=app%2Ftable-basic-example.html
HTML:
Blockquote
<button mat-button color="accent" (click)="print()">
<mat-icon class="mat-24" aria-label="Example icon-button with a heart icon">print</mat-icon>
Print
Blockquote
Javascript/typescript:
import jsPDF from 'jspdf';
import 'jspdf-autotable';
print = () => {
let doc = new jsPDF();
doc.autoTable({
head: [['Log','', 'Amount']],
body: this.getLiveData() //returning [["log1", "$100"], ["log2", "$200"]]
});
doc.save('table.pdf')
}
This answer update might be too late , but still might be useful for someone.
mat-table-exporter - this npm package allows to download the mat-table in various formats.
Package Link: https://www.npmjs.com/package/mat-table-exporter
Demo: https://stackblitz.com/edit/mte-demo
Sample code :
<button mat-raised-button (click)="exporter.exportTable('json')">Json</button>
<button mat-raised-button (click)="exporter.exportTable('txt')">Txt</button>
in angular 2 I need to create a large html-template with redundant parts.
Therefore I want to create multiple html-templates and put them together by including them in the main html-file (like ng-include in angular1)
But how can I include sub-templates in the main-template?
example:
<!-- test.html -->
<div>
this is my Sub-Item
<!-- include sub1.html here-->
</div>
<div>
this is second Sub-Item
<!-- include sub2.html here-->
</div>
-
<!-- sub1.html -->
<div>
<button>I'am sub1</button>
</div>
-
<!-- sub2.html -->
<div>
<div>I'am sub2</div>
</div>
You can create components like sub1 sub2 etc. And On those child components add these html files as template .
On main html call the component selectors respectively. It will work
Let me tell you first of all that ng-include from Angular1.x is not supported by Angular2 so obviously $Compile is not present in Angular2. So, you can go ahead with CRF-ComponentFactoryResolver as shown here to add HTML dynamically with angular context.
DEMO--(CFR) : https://plnkr.co/edit/YdRlULhWQR3L3akAr2eb?p=preview
If your HTML piece has angular context, you should use CFR-ComponentFactoryResolver.
As in sub1.html, you have button, you might want to click it and fire its click event. This can be achieved with CFR as shown below,
You can do lot with CRF. This is probably the easiest example.
#Component({
selector: 'my-app',
template: `
<button (click)="addComponents()">Add HTML (dynamically using CRF)</button>
<h1>Angular2 AppComponent</h1>
<hr>
<div>
<h5>sub1.html goes here</h5>
<div class="container">
<template #subContainer1></template>
</div>
</div>
<hr>
<h5>sub2.html goes here</h5>
<div class="container">
<template #subContainer2></template>
</div>
`,
})
export class App {
name:string;
#ViewChild('subContainer1', {read: ViewContainerRef}) subContainer1: ViewContainerRef;
#ViewChild('subContainer2', {read: ViewContainerRef}) subContainer2: ViewContainerRef;
constructor(
private compFactoryResolver: ComponentFactoryResolver
) {
this.name = 'Angular2'
}
addComponents() {
let compFactory: ComponentFactory;
compFactory = this.compFactoryResolver.resolveComponentFactory(Part1Component);
this.subContainer1.createComponent(compFactory);
compFactory = this.compFactoryResolver.resolveComponentFactory(Part2Component);
this.subContainer2.createComponent(compFactory);
}
}
}