I am using angular 6. I have a dynamically created HTML file. Which may have errors like:
self closing tags
closing tags missing
mathematical equations
custom attributes
errors like Template parse errors:
There is no directive with "exportAs" set to "aff" (
Is there any way to skip all errors and simply load HTML content in angular?
Try like this. I haven't test this code.
import { Pipe, PipeTransform } from '#angular/core';
import { DomSanitizer } from '#angular/platform-browser';
#Pipe({ name: 'keepHtml', pure: false })
export class EscapeHtmlPipe implements PipeTransform {
constructor(private sanitizer: DomSanitizer) {
}
transform(content) {
return this.sanitizer.bypassSecurityTrustHtml(content);
}
}
Ref link
I would first encourage to use nglint in your code .
From my viewpoint, it is a very bad idea to generate HTML from angular, and I seriously think it will not work at all ! That's is angular job. You have to generate dynamic components . Then, angular will render these components in html.
Use an html validator after generating the html page, that will permit to fix it.
Related
So I have a FAQ page which I have developed in angular and I have hardcoded all the data in a html file .I just wanted to know is there a better way of displaying the data like storing it in a XML/JSON/TXT file and read the file and display it or store the XML/JSON/TXT file in angular and read form it**(if storing it where to store it)**.
.Browsed for a few articles didn't find anything helpful ,any guidance will be appreciated. I am new to angular so just looking for some advice ,thanks in advance.
If your data is static I recommend storing it in a JSON file inside your angular application under the assets folder.
You can then use Angular HttpClient to retrieve the content of the file.
In this example, the file is called 'data.json' and is stored under the 'assets' folder:
import { HttpClient } from '#angular/common/http';
#Component({
selector: 'my-component',
templateUrl: './my-component.html',
styleUrls: ['./my-component.css']
})
export class MyComponent implements OnInit {
constructor(private http: HttpClient) { }
ngOnInit() {
this.http.get('/assets/data.json').subscribe().then(data => console.log(data));
}
}
You can find more information here.
I need to put a loading in multiple components of my project. So instead of putting the same HTML over and over again across the components, I need to know what's the best way to not repeat code, but I don't know if this is correct thing to do. I have created a component called loading-graphic, which I bind it in every HTML file of the respective components. I read about ngTemplateOutlet and ngContent, but to be honest it doesn't make sense in my head to use it for this case (and I don't get it too... I'm a beginner on it). So, on what should I bet? Thanks.
Base on your question, I think creating Reusable Components with NgTemplateOutlet would be the best solution to avoid repeating HTML in different component Templates. It allows you to pass parameters base on your host component and makes your Angular app easier to test and develop since it sllows easily modified reusable component for various use cases without having to modify individual components itself.
Since you are a begginer I am going to Illustrate simple way of using NgTemplateOutlet, however dive deep later on Templates and Stamps.
Imaging you have a reusable Search component where you want to hide a check box base on the parent component. Your Template will look like below.
we pass data from the parent component to the child/Search component using #Input and property binding, so we define which checkboxes to hide base on Parent component.
here is the code sample for Search Component
search.component.ts
======================
import { Component, OnInit, Output, EventEmitter, Input } from '#angular/core';
#Component({
selector: 'app-search',
templateUrl: './app-search.component.html',
styleUrls: ['./app-search.component.css']
})
export class AppSearchComponent implements OnInit {
accountName: string = '';
#Output() accountSearchChange = new EventEmitter<string>(); //1. Event Binding to pass data from Child to Parent Component ->Int
#Input() searchMode: 'account' | 'holder' | 'distribution' = 'account'; //Use NgTemplateOutlet for reusable componenet
constructor() { }
ngOnInit() {
}
//2. Event Binding to pass data from Child to Parent Component ->Invoke Emit
doSearchFilter(searchText: string) {
console.log('Search Child: doSearchFilter -> ' + searchText);
this.accountSearchChange.emit(searchText);
}
clearFilters() {
console.log('Account Search: Clear Filter is called');
this.accountName = '';
}
}
search.component.html
=====================
<ng-container [ngSwitch]="searchMode">
<div class="input-full-width" *ngSwitchCase="'account'">
<mat-checkbox class="example-container check-full-width">Show active and pending only</mat-checkbox>
</div>
<div class="input-full-width" *ngSwitchCase="'holder'">
<mat-checkbox class="example-container check-full-width">View only holders with missing requirements</mat-checkbox>
</div>
<div class="input-full-width" *ngSwitchCase="'holder'">
<mat-checkbox class="example-container check-full-width">View only active Holders</mat-checkbox>
</div>
</ng-container>
I am using Search component inside Account component and below is the code sample.
in HTML file i am referring app-search css selector and pass the search Mode defined in ts.
import { Component, OnInit, ViewChild, AfterViewInit } from '#angular/core';
import { MatSort, MatTableDataSource, MatPaginator } from '#angular/material';
import { Router } from "#angular/router";
import { Observable } from 'rxjs';
import { AccountService } from 'src/app/core/services/account.service';
import { Deal } from 'src/app/core/models/deal';
#Component({
selector: 'app-account',
templateUrl: './account.component.html',
styleUrls: ['./account.component.css']
})
export class AccountsComponent implements OnInit, AfterViewInit {
displayedColumns: string[] = ['accountId', 'accountShortName', 'accountType'];
public dealDataSource = new MatTableDataSource<Deal>();
dealsObservable: Observable<Deal[]>;
searchMode = 'distribution';
isLoadingResults = true;
#ViewChild(MatSort) sort: MatSort;
#ViewChild(MatPaginator) paginator: MatPaginator;
constructor(private router: Router, private api: AccountService) { }
......................................................
<app-search (accountSearchChange)='doFilter($event)' [searchMode]="searchMode"></app-search>
Hope this is clear.
i think loading component is not a bad Idee. Use loading component in your app-root component. You can use a loading.service and interceptor to display or hide the component. You will get automatically a Loading Indicator for each API call.
sample: https://medium.com/#zeljkoradic/loader-bar-on-every-http-request-in-angular-6-60d8572a21a9
My problem is the following, I get as a response from a service an entire HTML page that I should display back t the user. Now this is an issue for Angular since it thinks I might be a victim of cross site scripting if I do that. The source I get the HTML from is trusted so I wanted to white list it or bypass the sanitizer in some way and render the view to the user.
The problem I ran into is that the file I get also contains 'style' and 'script' tags for manipulating the dom, and no matter how I place the bypass function calls something gets caught and the entire thing doesn't render properly. Is there any way I could maybe separate the HTML file clear it and then put it back together or something else?
Try this:
import { DomSanitizer } from '#angular/platform-browser';
constructor(private sanitizer: DomSanitizer) { }
//where you want to use the unsafe html
const sanitizedHtml = this.sanitizer.bypassSecurityTrustResourceUrl(html);
What you can do, but goes against the Angular principle, is to append the html markup to the innerhtml of your component or the DOM using ElementRef from
#angular/core.
Sample appcomponent:
import { Component, ElementRef } from '#angular/core';
#Component({
selector: 'my-app',
template: ``,
})
export class AppComponent {
private htmlTemplate = `
<div>Loading template</div>
<script type="text/javascript">
console.log('loaded');
</script>
`;
constructor(private elementRef: ElementRef) { }
ngAfterViewInit() {
let elem: Element = this.elementRef.nativeElement;
elem.innerHTML = this.htmlTemplate;
}
}
I want to display a component's code in a Html template, Not the value generated by the code but the actual code.
like this
import { Injectable } from '#angular/core';
import { Resolve, ActivatedRouteSnapshot } from '#angular/router';
import {CompetitionService} from "../shared/competition.service";
import {Observable} from "rxjs";
#Injectable()
export class TableResolve implements Resolve<any> {
constructor(private competitionService:CompetitionService) {}
resolve(route: ActivatedRouteSnapshot):Observable<> {
return this.competitionService.getTeams(route.params['id']);
}
}
This whole code like they show in stackoverflow in the question section.I tried using <pre> and <code> but none seem to work ,i am getting this error in console.
Error: Template parse errors: Unexpected character "EOF" (Do you have an unescaped "{" in your template? Use "{{ '{' }}") to escape it.)
But if i have to escape it for all { it is problematic please help ?
Use a variable in your ts file that contains all the code and display it in html using this {{stringThatContainsAllTheCode}}
I think the simplest way is to use [innerHTML]="varContainingCode" and hold the code in the components class
<pre>
<code [innerHTML]="code"></code>
</pre>
export class AppComponent {
code = ` //type script code`
}
Or if you don't want to use this library call ng2-prism can be useful.
This is a Angular2 codeblock highlighting component library.
Styles like
<div [style.background-image]="\'url(\' + image + \')\'">Background</div>
<div [style.transform]="rotate(7deg)"
are not added anymore
update (2.0.0 final)
import { Pipe, PipeTransform } from '#angular/core';
import { DomSanitizer } from '#angular/platform-browser';
#Pipe({name: 'safeHtml'})
export class SafeHtml implements PipeTransform {
constructor(private sanitizer:DomSanitizer){}
transform(html) {
return this.sanitizer.bypassSecurityTrustStyle(html);
// return this.sanitizer.bypassSecurityTrustHtml(html);
// return this.sanitizer.bypassSecurityTrustScript(html);
// return this.sanitizer.bypassSecurityTrustUrl(html);
// return this.sanitizer.bypassSecurityTrustResourceUrl(html);
}
}
See also https://angular.io/api/platform-browser/DomSanitizer
<div [innerHTML]="someHtml | safeHtml"
update
DomSanitizationService is going to be renamed to DomSanitizer in RC.6
original
This should be fixed in RC.2
See also Angular2 Developer Guide - Security
Angular2 intruduced sanitization of CSS values and property binding like [innerHTML]=... and [src]="..." in RC.1
See also https://github.com/angular/angular/issues/8491#issuecomment-217467582
The values can be marked as trusted by using DomSanitizer.bypassSecurityTrustStyle(...)
import {DomSanitizer} from '#angular/platform-browser';
...
constructor(sanitizer: DomSanitizationService) {
this.backgroundImageStyle = sanitizer.bypassSecurityTrustStyle('url(' + this.image + ')');
// for HTML
// this.backgroundImageStyle = sanitizer.bypassSecurityTrustHtml(...);
}
and binding to this value instead the untrusted plain string.
This can also be wrapped in a pipe like
#Pipe({name: 'safeStyle'})
export class Safe {
constructor(private sanitizer:Sanitizer){}
transform(style) {
return this.sanitizer.bypassSecurityTrustStyle(style);
// return this.sanitizer.bypassSecurityTrustHtml(style);
// return this.sanitizer.bypassSecurityTrustScript(value);
// return this.sanitizer.bypassSecurityTrustUrl(value);
// return this.sanitizer.bypassSecurityTrustResourceUrl(value);
}
}
<div [ngStyle]="someStyle | safeStyle"></div>
with
someHtml = `click to see the awesome`;
is still working though :-[ (it's work in progress)
Plunker example (Angular 2.0.0-rc-1)
See also Angular 2 Security Tracking Issue
and https://angular.io/docs/ts/latest/api/platform-browser/index/DomSanitizer-class.html
Hint about {{...}}
Sanitized content can't be bound using prop="{{sanitizedContent}}" because {{}} stringyfies the value before it is assigned which breaks sanitization.
Bypassing sanitizer to trust any content can be a security concern. Since Angular is not a dedicated sanitizing library, it is overzealous towards suspicious content to not take any risks. It removes almost all attributes, for example. You can delegate sanitizing to a dedicated library — DOMPurify. Here's a wrapper library I've made to easily use DOMPurify with Angular.
https://github.com/TinkoffCreditSystems/ng-dompurify
It also has a pipe to declaratively sanitize HTML:
<div [innerHtml]="value | dompurify"></div>
One thing to keep in mind is DOMPurify is great for sanitizing HTML/SVG, but not CSS. So you can provider Angular's CSS sanitizer to handle CSS:
import {NgModule, ɵ_sanitizeStyle} from '#angular/core';
import {SANITIZE_STYLE} from '#tinkoff/ng-dompurify';
#NgModule({
// ...
providers: [
{
provide: SANITIZE_STYLE,
useValue: ɵ_sanitizeStyle,
},
],
// ...
})
export class AppModule {}
It's internal — hense ɵ prefix, but this is how Angular team use it across their own packages as well anyway.