Angular 2 component inherit with onClick - html

I would like to inerit from component and add onClick method, how can I do it?
I want to have only one html file.
Here is a basic example -
I have a temple file with this html code-
<h1>h1</h1>
<h2>h2</h2>
I want to inherit this component and add OnClick method on h1.
Thanks in advance.

You can just add that component with function and a variable that sets to true on click.
<button (click)="toggleComponent()"></button>
<app-example-component *ngIf="variable">
ts:
variable = false;
toggleComponent() {
this.variable = !this.variable;
}

You can extend component like I did as below:
Plunker Link
https://plnkr.co/edit/azixm9?p=preview
//our root app component
import {Component, NgModule, VERSION} from '#angular/core'
import {BrowserModule} from '#angular/platform-browser'
#Component({
selector: 'my-app',
template: `
<div>
<h2 (click)="callMe()">Hello {{name}}</h2>
<comp-one></comp-one>
</div>
`,
})
export class App {
name:string;
constructor() {
this.name = `Angular! v${VERSION.full}`
}
public callMe(compName: any): void {
alert("App Component will handle this functionality")
}
}
#Component({
selector: 'comp-one',
template: `<h2 (click)="callMe()">Click Me</h2>`,
})
export class ComponentOne extends App {
}
#NgModule({
imports: [ BrowserModule ],
declarations: [ App, ComponentOne ],
bootstrap: [ App ]
})
export class AppModule {}

Related

Angular: sanitizer.bypassSecurityTrustHtml does not render attribute (click)

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

Angular 5 generate HTML without rendering

Is it possible to generate a html file from a component by bypassing all the data it needs without actually rendering it in the browser viewport?
I would like to just generate some html code to send it to the backend that generates a PDF from this html.
I don't think you can, since rendering of angular's components relies heavily on it's lifecycle hooks.
I can think of one way to fake it, though, by:
instantiating an invisible component from code
add it to the DOM, so it behaves like any regular component
retrieve it's HTML
and finally destroy it
Here's a working code example.
app.module.ts
Notice that i've added PdfContentComponent to the entryComponents of the module.
This is required for any component that you want to instantiate from code.
#NgModule({
imports: [ BrowserModule, FormsModule ],
declarations: [ AppComponent, PdfContentComponent ],
bootstrap: [ AppComponent ],
entryComponents : [ PdfContentComponent ]
})
export class AppModule { }
pdf-content.component.html
<span>Hello, {{ name }}</span>
pdf-content.component.ts
Notice the host: {style: 'display: none'}, this renders the component effectivly invisible
#Component({
selector: 'my-pdf-content',
templateUrl: './pdf-content.component.html',
host: {
style: 'display: none'
}
})
export class PdfContentComponent implements OnInit {
#Input() name: string;
#Output() loaded: EventEmitter<void> = new EventEmitter<void>();
constructor(public element:ElementRef) {
}
ngOnInit() {
this.loaded.emit();
}
}
app.component.html
<button (click)='printPdf()'>Hit me!</button>
<ng-container #pdfContainer>
</ng-container>
app.component.ts
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
// the pdf content will be briefly added to this container
#ViewChild("pdfContainer", { read: ViewContainerRef }) container;
constructor(
private resolver: ComponentFactoryResolver
) {}
printPdf() {
// get the PdfContentComponent factory
const factory: ComponentFactory<any> = this.resolver.resolveComponentFactory(PdfContentComponent);
// instantiate a PdfContentComponent
const pdfContentRef = this.container.createComponent(factory);
// get the actual instance from the reference
const pdfContent = pdfContentRef.instance;
// change some input properties of the component
pdfContent.name = 'John Doe';
// wait for the component to finish initialization
// and delay the event listener briefly,
// so we don't run the clean up in the middle of angulars lifecycle pass
const sub = pdfContent.loaded
.pipe(delay(1))
.subscribe(() => {
// stop listening to the loaded event
sub.unsubscribe();
// send the html to the backend here
window.alert(pdfContent.element.nativeElement.innerHTML);
// remove the component from the DOM
this.container.remove(this.container.indexOf(pdfContentRef));
})
}
}
You can use Renderer2 class provided by angular. Try this sample code;
import { Component, Renderer2, OnInit } from '#angular/core';
....
constructor(private renderer: Renderer2){
}
ngOnInit(){
const div: HTMLDivElement = this.renderer.createElement('div');
const text = this.renderer.createText('Hello world!');
this.renderer.appendChild(div, text);
console.log(div.outerHTML);
}

Display raw html - Angular 6

I am looking to display the raw HTML code (example.component.html) below 'example works!'. The page should display the following:
example works!
<p>
example works!
</p>
I can find various resources showing how this can be done using AngularJS but not Angular 6.
I have tried to use [innerHTML] but this didn't work.
<p>
example works!
</p>
example.component.ts
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'rt-example',
templateUrl: './example.component.html',
styleUrls: ['./example.component.css']
})
export class ExampleComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}
app.component.html
<div style="text-align:center">
<rt-example></rt-example>
</div>
OUTPUT . . link to image
You can use the ViewContainerRef to get the nativeElement, and get its innerHTML.
Just a warning : this won't be your HTML code, but the compiled code.
Here is an example : stackblitz
export class AppComponent {
htmlContent: string;
constructor(private view: ViewContainerRef) {
setTimeout(() => this.htmlContent = (view.element.nativeElement as HTMLElement).innerHTML);
}
}
EDIT If you want the uncompiled code, you should use this notation : stackblitz
import { Component, ViewContainerRef } from '#angular/core';
import * as template from "./app.component.html";
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
htmlContent: string = template.default;
constructor(private view: ViewContainerRef) {
}
}
But I suggest you use the latest versions of typescript & Angular, since I'm not sure when it has been introduced.
Get a reference pointing to that component using ViewChild, like
export class AppComponent {
#ViewChild(ExampleComponent, { read: ElementRef }) exampleComponent;
}
Then you can access its HTML with nativeElement.innerHTML.
So you could change your app.component.html to this:
<div style="text-align:center">
<rt-example></rt-example>
</div>
{{exampleComponent.nativeElement.innerHTML}}
In HTML, you need to use entities to show the reserved characters.
<p>example works!</p>
<code><p>example works!</p></code>
For example:
& is equivalent to &
< is equivalent to <
> is equivalent to >
However solution using angular would be:
Component:
export class SomeComponent {
code :string = `<p>example</p>`
}
HTML:
<code>{{this.code}}</code>
OR Use InnerText instead of InnerHTML
<p [innerText]="code"></p>
https://stackblitz.com/edit/angular-5cpmcr

how to navigate(redirect) to another page in Angular?

I'm trying to redirect to another page(Page-II) when a button clicked but unfortunately that another page component loads on the same page(Page-I). Here what I tried so far :
app.component.html
<button (click)="register()"
mat-raised-button class="searchButton" type="button">Register</button>
<button (click)="profile()"
mat-raised-button class="searchButton" type="button">Profile</button>
<router-outlet></router-outlet>
app-routing.module.ts
const routes: Routes = [{
path : 'register',
component : RegisterComponent
},
{
path : 'profile',
component : ProfileComponent
}];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
app.component.ts
import { Component , OnInit } from '#angular/core';
import { Router } from '#angular/router';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
title = 'app';
constructor(private router: Router ) {}
register = function () {
location.pathname = ('/register');
};
profile = function(){
this.router.navigateByUrl('/profile');
};
ngOnInit() {
}
}
Note: I know that profile loads on same page but trying to redirect register.html when register button clicks on another page.
Can you try this:
register() {
this.router.navigate(['/register']);
}

Can't I use a component defined in a file other than app.component.ts in HTML directly?

I am facing difficulty in using a component defined in a file named navigation.component.ts directly on HTML Page.
The same component works fine if I use it under template of a component defined on app.component.ts.
Contents of app.module.ts
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { AppComponent } from './app.component';
import { NavigationComponent} from './shared/navigation.component';
#NgModule({
imports: [BrowserModule],
declarations: [AppComponent, NavigationComponent],
bootstrap: [ AppComponent ]
})
export class AppModule { }
Contents of navigation.component.ts
import { Component } from '#angular/core';
#Component({
selector: 'navigation',
templateUrl: '/views/shared/navigation.html'
})
export class NavigationComponent {
userName: string = 'Anonymous';
}
Contents of app.component.ts
import { Component } from '#angular/core';
#Component({
selector: 'main-app',
template: '<navigation></navigation><h1>{{pageTitle}}</h1>'
})
export class AppComponent {
pageTitle: string = 'Portal 2.0';
}
Contents of index.html
<body>
<main-app></main-app>
</body>
The above works and renders menus on top but when I try to use <navigation> directly (given below) it doesn't render it, doesn't show any errors either.
<body>
<navigation></navigation>
</body>
Am I doing something wrong?
And the bigger question is how I go debugging issues like this?
Yes you can use web components. Add all the components that you want to load to entrycomponents.
Using createCustomElement you can create elements and use their selector anywhere.
import { BrowserModule } from '#angular/platform-browser';
import { NgModule, Injector } from '#angular/core';
import { createCustomElement } from '#angular/elements';
import { AppComponent } from './app.component';
#NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule
],
providers: [],
entryComponents: [AppComponent]
})
export class AppModule {
constructor(private injector: Injector) {
console.log('Elements is loaded: Activation');
this.registerComponent('metro-activation-loader', AppComponent);
}
public ngDoBootstrap(): void {
console.log('Elements is loaded: Activation ngDoBootstrap');
}
// tslint:disable-next-line:no-any
private registerComponent(name: string, component: any): void {
const injector = this.injector;
const customElement = createCustomElement(component, { injector });
customElements.define(name, customElement);
}
}