(click) event don't work in string angular 4 - html

My function don't call when i clicked in tag a
i have the next code in my component
public htmlstr: string;
public idUser:number;
this.idUser = 1;
this.htmlstr = `<a (click)="delete(idUser)">${idUser}</a>`;
public delete(idUser){
alert("id " + idUser);
}
my html
<div [innerHTML]="htmlstr"></div>
but the function delete don't call and not show the alert

Angular string interpolation braces won't work in a variable like this.
You could use template literals (note the backticks, not single quotes):
this.iduser = `<a style="font-weight: bold;"> id: ${idperson} </a>`
Or String.format:
this.iduser = '<a style="font-weight: bold;"> id: {} </a>'.format(idperson)

You are using Angular 4 so why not simply use interpolation?
Your code would thus look something like this:
idLabel = 'id: ';
id: number;
And then your template would look like this:
<span>
<a style="font-weight:bold;" href="#">{{idLabel + id}}</a>
</span>
Ideally, if you are using a router for this link you could attach the routerLink diractive to the anchor tag like so:
<a style="font-weight:bold;" [routerLink]="'/user/' + id"></a>
...or whatever your route configuration looks like.

Try this:
this.idperson = 1;
this.iduser = `<a style='font-weight: bold;'> id: ${idperson} </a>`;
Note that i'm using backquote, no simple quote. The result will be:
id: 1

if you're using AOT it might be as simple as making the function public?
also check your browser's console for errors

Related

Angular add different style to a JSON

From BE it returns a json and I show it, but I would like, for example, "type, includeDeactive, code etc..." be bold and the (other) value, after the colons (:) in italics.
Example:
body: { "**type**: { **includeDeactive**: *false*, **code**: *null*, **address**: *null*, **name**: *null*, }
I've already formatted the json with the <pre> tag and I pass it data with the data binding {{detail.body | json }}. This is my html:
<mat-label style="font-family: Roboto">
<strong>Body</strong>:
<span style="font-family: Roboto">
<pre id="formatJson"> {{detail.body | json }} </pre>
</span>
</mat-label>
This is my function in ts:
objBody: any;
parsedObj: any;
constructor(
private dialogRef: MatDialogRef<DettaglioAuditComponent>,
#Inject(MAT_DIALOG_DATA) public data,
private auditService: AuditService,
) { }
ngOnInit(): void {
this.detail = {};
this.auditService.getDetails(this.data.element).then(
(value) => {
this.detail = value;
var objBody = JSON.stringify(this.detail.body);
var parsedObj = JSON.parse(objBody);
//objBody = objBody.replace('{"', '{"<b>'); - already tried but doesn't work!
//objBody = objBody.replace('":', '</b>":');
this.loading = false;
},
(error) =>
});
}
Any idea? Thanks in advance!
If you need it for professional purpose and "just want it to work", use Highlightjs or an equivalent library. The output will be fancy and very readable :
If you want to do it with Highlightjs
You need highlightJs of course. You can use the npm dependency ngx-highlight-js which will enable you to use HighlightJs in an Angular project.
In the Angular project, you can include the content like this :
<textarea highlight-js ngNonBindable lang="javascript">
// include your content here
</textarea>
You MUST include the content in a <textarea> tag (for indentation preservation)
highlight-js is of course the directive that will tell HighlightJs to do its work
ngNonBindable prevents Angular from trying to interpret the content of the textArea as Angular code
lang="javascript" : you can optionally specify the language for accurate coloration
Also, don't forget to import the HighlightJsModule module where necessary
If you want to do it by yourself
(or understand how things work under the hood)
You can JSON.parse() the content of your string, recursively iterate on the given object keys and generate HTML out of it.
Indentations and newlines can be rendered by placing the generated html in a <pre> pr <textarea> tag
Colors can be achieved by placing colored elements in dedicated <span class="[...]"> tags
On the previous example, the HTML code generated by HighlightJS is :
<pre><code class="language-json hljs">[
{
<span class="hljs-attr">"title"</span>: <span class="hljs-string">"apples"</span>,
<span class="hljs-attr">"count"</span>: [<span class="hljs-number">12000</span>, <span class="hljs-number">20000</span>],
<span class="hljs-attr">"description"</span>: {<span class="hljs-attr">"text"</span>: <span class="hljs-string">"..."</span>, <span class="hljs-attr">"sensitive"</span>: <span class="hljs-literal">false</span>}
},
{
<span class="hljs-attr">"title"</span>: <span class="hljs-string">"oranges"</span>,
<span class="hljs-attr">"count"</span>: [<span class="hljs-number">17500</span>, <span class="hljs-literal">null</span>],
<span class="hljs-attr">"description"</span>: {<span class="hljs-attr">"text"</span>: <span class="hljs-string">"..."</span>, <span class="hljs-attr">"sensitive"</span>: <span class="hljs-literal">false</span>}
}
]
</code></pre>
Relevant pieces of code :
Convert the content to an object with JSON.parse(contentAsString)
Check if a given property is an array with Array.isArray(obj)
Iterate on object keys with Object.keys(obj)

Angular 6 - bind HTML created after compilation to click event

Im adding HTML elements at run-time when the user clicks a button.
I do this by setting the inner html of a div to a built up string then using DOMSanitizer.
Visually this look fine but the click events in the new HTML are not bound so nothing works, I guess because the HTML is generated after compilation.
Here is the code called when the user clicks to add a new component (it get populated with the correct data), can anyone suggest how I should hook it up to the click event in the delete image?
html on the page:
<div class="col-sm-9" >
<div [innerHtml]="contentHtml"></div>
</div>
code:
async AddText(contentText: string) {
this.htmlToAdd = this.htmlToAdd + ( '<br> <div class="card text-left">' +
'<div class="card-header text-secondary">Attraction Text' +
'<img align="right" class="image-hover pull-right table-header-padding" src="assets/images/LockLineIcon.png" />' +
'<img #delete class="image-hover float-right text-danger icon-pad draft-icon-indent" src="assets/images/DeleteIcon.png" (click)="this.delete(0)"/>' +
'</div>' +
'<div class="card-body" >' +
'<textarea id="text" name="text" type="text" class="form-control" required maxlength="2048" >' + contentText + '</textarea>' +
'</div>' +
'<div class="card-footer">' +
'<img align="right" class="pull-right table-header-padding" src="assets/images/DragUpDownIcon.png" />' +
'</div>' +
'</div>');
this.contentHtml = this.sanitizer.bypassSecurityTrustHtml(this.htmlToAdd);
}
Your DOM may be sanitized, but it's not part of Angular's DOM. If you want Angular to see the DOM, you have to let Angular make the DOM - and that means dynamic components. Something like this would work:
#Component({
selector: 'my-component',
template: `<h2>Stuff bellow will get dynamically created and injected<h2>
<div #vc></div>`
})
export class MyComponent {
#ViewChild('vc', {read: ViewContainerRef}) vc: ViewContainerRef;
private cmpRef: ComponentRef<any>;
constructor(private compiler: Compiler,
private injector: Injector,
private moduleRef: NgModuleRef<any>,
private backendService: backendService,
) {}
ngAfterViewInit() {
// Here, get your HTML from wherever.
this.someService.getThatAsyncHTMLOfYours.subscribe(rawHTML => this.createComponentFromRaw(rawHTML));
}
// Here we create the component.
private createComponentFromRaw(template: string) {
// Let's say your template looks like `<h2><some-component [data]="data"></some-component>`
// As you see, it has an (existing) angular component `some-component` and it injects it [data]
// Now we create a new component. It has that template, and we can even give it data.
const tmpCmp = Component({ template, styles })(class {
// the class is anonymous. But it's a quite regular angular class. You could add #Inputs,
// #Outputs, inject stuff etc.
data: { some: 'data'};
ngOnInit() {
/**
* HERE'S YOUR STUFF
* do stuff here in the dynamic component, like binding to locally available variables and services.
*/
}
});

Strip html in Angular template binding

I have a list displaying data that can sometimes contain HTML
<li *ngFor="let result of results">
<span [innerHTML]="result.question.title">
</span>
</li>
The problem with using innerHTML is that the HTML gets parsed and rendered, so things like <p> tags will add margins and ruin the list's alignment.
I would like to strip all html tags and just output plain text.
An approach like this:
<li *ngFor="let result of results">
<span>
{{result.question.title}}
</span>
</li>
does not strip the HTML, it just outputs the HTML as plain text.
How can I strip the HTML and leave plain text the 'Angular' way?
I guess there is no direct way to strip HTML tags from string, you can use Pipe, write a "Pipe" like this:
import { Pipe, PipeTransform } from '#angular/core';
#Pipe({
name: 'striphtml'
})
export class StripHtmlPipe implements PipeTransform {
transform(value: string): any {
return value.replace(/<.*?>/g, ''); // replace tags
}
}
then add "StripHtmlPipe" to your module "declarations", after these steps you can use this pipe in your HTML:
<li *ngFor="let result of results">
<span>
{{result.question.title | striphtml}}
</span>
</li>
please note that the code above is not fully tested.
I wouldn't recommend using a regex to parse html as suggested by
kite.js.org. Use the browsers textContent / innerText function instead:
htmlToText(html: string) {
const tmp = document.createElement('DIV');
tmp.innerHTML = html;
return tmp.textContent || tmp.innerText || '';
}
This should be much more reliable. You can still use a pipe if you like, just don't use regex to parse html!

ng-bind-html not working with my $scope.variable

I am trying to add something like dynamic HTML using ng-bind-html but its not working with $scope variable
Here is my Angular code
1)My controller
$scope.name = "Parshuram"
$scope.thisCanBeusedInsideNgBindHtml = $sce.trustAsHtml("<div>{{name}}</div>");
Also that my string is dynamic
"<div><table class=" + "\"table table - bordered table - responsive table - hover add - lineheight table_scroll\"" + "><thead><tr><td>Name</td><td>Age</td></tr></thead><tbody><tr ng-repeat=" + "\"tr in dyna\"" + "><td>{{tr.name}}</td><td>{{tr.age}}</td></tr></tbody></table></div>"
So i cant replace every variable with $scope
2)- My HTML
<div ng-app="mymodule" ng-controller="myModuleController">
<div ng-bind-html="thisCanBeusedInsideNgBindHtml"></div>
</div>
I got this output
{{name}}
My expected output is
Parshuram
Please can anyone help i am stuck at this point,does that $sce does not bind scope variable?? ..
I've created a working plnkr here: https://plnkr.co/edit/uOdbHjv1B7fr0Ra1kXI3?p=preview
the problem is that ng-bind-html is not bound to the scope.
you should manually compile the content.
a valid and reusable solution should be creating a directive, whitout using any external modules.
function compileTemplate($compile, $parse){
return {
link: function(scope, element, attr){
var parsed = $parse(attr.ngBindHtml);
function getStringValue() { return (parsed(scope) || '').toString(); }
scope.$watch(getStringValue, function() {
$compile(element, null, -9999)(scope);
});
}
}
}
<div ng-app="mymodule" ng-controller="myModuleController">
<div ng-bind-html="thisCanBeusedInsideNgBindHtml" compile-template></div>
</div>
ng-bind-html does what it says on the tin: it binds html. It doesn't bind angular template code into your dom.
You need to do this instead:
$scope.thisCanBeusedInsideNgBindHtml =
$sce.trustAsHtml("<div>"+$sanitize(name)+"</div>");
To do this you'll want to include the module ngSanitize from the javascript angular-sanitize.js. See https://docs.angularjs.org/api/ngSanitize
If you want to insert some html that includes angular directives then you should write your own custom directive to do it.
In your html just use
{{name}}
The {{var}} notation is to be used in the HTML code to evaluate that variable.
You can do :
$scope.thisCanBeusedInsideNgBindHtml = $sce.trustAsHtml('<div ng-bind="name"></div>');
Sorry I make another answer.
If you have
$scope.thisCanBeusedInsideNgBindHtml = $sce.trustAsHtml("<div>{{name}}</div>");
Then you can do
var str = "<div>{{name}}</div>";
var output = str.replace('{{name}}', $scope.name);
It seems to be the only option.

How to create href link inside controller in Angularjs?

I am showing a flash error message if a mobile number is not validated.
Flash message as "Mobile number not validated. click here to validate".
But I want to display the same error message with "click here" as the hyper link which will redirect me to the top of the page.
if (res.json.response.mobilevalidated == false) {
FlashService.Error("Mobile number not validated." + ( click here ) +" to validate", false);
$scope.disabled = function() {
$scope.model.disabled = true;
$scope.title = "Cannot access until mobile number is validated.";
}
} else {
$scope.model.disabled = false;
}
How can I use html tags inside the controller? As my error message is a dynamic one.
Use ng-include.
Js add
$scope.includePath = function () {
`templateUrl="..../your template path"`
};
HTML
<div ng-include="includePath" > New html is here </div>
Here in this case you can use <button> if you want to give click event.
HTML
<div ng-class="{ 'alert': flash, 'alert-success': flash.type === 'success', 'alert-danger': flash.type === 'error', 'selected': hlink}" ng-click = "linking()" ng-if="flash" ng-bind="flash.message" style="margin-top: 20px; ">
</div>
My Controller
if (res.json.response.mobilevalidated == false) {
$scope.linking = function(){
$location.path('/otp');
}
$scope.hlink =" click here";
FlashService.Error("Mobile number not validated." + $scope.hlink +" to validate" , false);
}
What you are looking for can be achieved using $sce that is included in Angular. Take a look at the Documentation here: https://docs.angularjs.org/api/ng/service/$sce
You basically define your HTML string as trusted in the Controller like this: $sce.trustAsHtml(Stackoverflow") and bind it in the template using ng-bind-html like <span ng-bind-html="mySuperCoolLink"></span>.
There is an example in the documentation liked above.
Edit:
Your function FlashService.Error receives an invalid string. You use string concatenation to include your HTML link, however, that only works if your HTML link is stored in a variable. So you have to do one of the following:
A)
FlashService.Error("Mobile number not validated. click here ) to validate", false);
or B)
var link = "( click here )";
FlashService.Error("Mobile number not validated." + link + " to validate", false);
In your provided code, the JS engine will recognise the round brackets as they are valid JS, but not the pointy brackets (I forgot their name...).
Edit 2:
Plunkr: https://plnkr.co/edit/WzzWtnJW98u3e7eTLn2q?p=preview