How viewChild can get elements that added with js in angular2?

筅森魡賤 提交于 2019-12-09 13:37:10

问题


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.

solution :

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.

  1. 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>
    
  2. 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
                    },
                ],
    
  3. Now import and inject these sources to your component:

        import {ViewChild, Renderer} from '@angular/core';
    

    and :

        constructor(private renderer: Renderer, private router: Router)
    
  4. Define a viewChild variable in your component class:

        @ViewChild('target') target;
    
  5. 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)
           }
    

    }

  6. 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.


回答1:


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);
}


来源:https://stackoverflow.com/questions/37421007/how-viewchild-can-get-elements-that-added-with-js-in-angular2

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!