If a HTML element has been added to the DOM(for example after click on button), How can we access this element? viewChild can't see that.
Update 1: More description
I've used jquery datatable (jquery.dataTables definitelyTyped version). Base on this link, I can add new column and define html inside that. I wrote this code :
columnDefs: [
{
render: function (data, type, row) {
return `
<a href="admin/edituser/` + row.UserId+ `" class="btn btn-outline btn-circle btn-sm green"><i class="fa fa-edit" > </i> Edit </a>`+
`<a [routerLink]="['Delete']" class="btn btn-outline btn-circle btn-sm red"><i class="fa fa-trash-o" > </i> Delete </a>
`;
},
targets: 5
},
],
With Chrome Developer tools I see this :
First anchor tag works but with href, not routerLink.
Second anchor tag doesn't work because angular directives didn't complie to href.
I tried to use DynamicComponentLoader to compile it, and changed code like this:
But I can't access #target element with viewChild.(I want to change it with another component by loadNextToLocation). I think this isn't optimize way to get good result.
I want to use routerLink with commands buttons inside jquery datatable.
Could you please help me in the right direction to solve this?
Thank you in advance.
If you want to add HTML to DOM with javascript or some callback function first determine a tag from template that can be a parent for those element(s) in future.
Add template variable to this parent element.(#target for example)
<th> Email</th>
<th> Date </th>
<th> Phone </th>
<th> Commands</th>
</tr>
</thead>
<tbody #target></tbody>
<tfoot>
<tr>
<th> </th>
<th> </th>
<th> </th>
<th> </th>
</tr>
</tfoot>
</table>
Then add a simple class and a simple attribute to your html code(This code is generated after page compiled with angular,Also you can write some code with typescript or javascript to generate html).
columnDefs: [
{
render: function (data, type, row) {
return `
`<a date-id="` + row.UserId + `" class="editbtn btn btn-outline btn-circle btn-sm red"> Edit</a>
`;
},
targets: 5
},
],
Now import and inject these sources to your component:
import {ViewChild, Renderer} from '@angular/core';
and :
constructor(private renderer: Renderer, private router: Router)
Define a viewChild variable in your component class:
@ViewChild('target') target;
Write a function like this :
public AfterEverything() {
var el: HTMLElement = this.target.nativeElement;//Make an Element Object
console.log(el);
var commands: NodeListOf<Element> = el.getElementsByClassName('editbtn');//Find Element Object to get all elements with a specefic class
console.log(commands);
for (var i = 0; i < commands.length; i++) {
//Loop for add event or style
console.log(commands[i]);
//Sample event(Click for routing)
this.renderer.listen(commands[i], 'click', (event: Event) => {
var thisid = event.srcElement.getAttribute("date-id");//Get value from element
console.log(thisid);
this.router.parent.navigate(['EditUser', { id: thisid }]);//Use value to make routeLink
console.log(event.srcElement.innerHTML);
});
this.renderer.setElementStyle(commands[i], 'backgroundColor', 'yellow');//for change color(just sample)
}
}
You must find best place to call this function,for example, ajax data callback is one choice and call AfterEverything() inside that. You can call this function inside ngAfterViewInit().
Note that sometimes a delay of several seconds is necessary to ensure that all new elements are created.
If you add HTML dynamically (like [innerHTML]="someHtml"
), then you can use direct DOM access (frowned upon in Angular2) by injecting ElementRef
and using ElementRef.nativeElement.querySelector...
If the HTML is generated using *ngFor
you can add template variables and query for these elements like
<div *ngFor="let x of y" #someVar></div>
and then in the component class
@ViewChildren('someVar') elements;
ngAfterViewInit() {
console.log(this.elements);
}