Guy E
Guy E

Reputation: 1927

Best way to reference an html element in a js function located in an angular 2 component

Newbie in angular 2. I have a table where every tr is bind to an object (we'll call it worker). I attached an mouseover event to that tr and I want to display this object instance property (lets say worker.firstname) in another input field on the form. I manage to make a simple alert of this property when I reach the js function, but I would like to set the input field text with that value. So, I thought of passing the element as a parameter in the function, like that (using jquery selector which I'm not sure is included):

<tr *ngFor = 'let worker of Workers' (mouseover)="showAdditionalData(worker, 
$('#txtWorkerAdditionalData'))" >

or maybe using the old getElementByID. What is the best way of doing it ? Attached a code block: This is the html element I want to populate with the worker firstname:

<input type="text" id="txtWorkerAdditionalData" />

This is the js function:

showAdditionalData(worker: IWorker, element: any) : void{
element.text = worker.FirstName;
alert (worker.FirstName);
}

Upvotes: 0

Views: 2412

Answers (2)

Joe Clay
Joe Clay

Reputation: 35807

As I mentioned in the comments - DOM manipulation is rarely the way to go when you're using a library like Angular or React. Half of their appeal is that they handle that stuff for you!

Here's how I'd implement this kind of functionality. Drop the element parameter from showAdditionalData and just pass in the worker:

<tr *ngFor="let worker of Workers" (mouseover)="showAdditionalData(worker)">
    ...
</tr>

Then, grab the first name from the worker and assign it to a field on your component:

public currentWorkerName: string = "";

showAdditionalData(worker: IWorker): void {
     this.currentWorkerName = worker.FirstName;
}

Now you can bind currentWorkerName to your input:

<input type="text" (value)="currentWorkerName" />

Done! And without a DOM element in sight :)

This answer assumes that both the table and the input are in the same component, but you're not out of luck if that isn't the case - either use @Input and @Output to pass data/events through the component tree, or pull out currentWorkerName into a service and inject it in both components.

Upvotes: 2

mikias
mikias

Reputation: 446

If you want to reference elements in a template you can use tempate variables and the ViewChild decorator to get the element ref.

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

@Component({
  selector: 'example',
  template: `
    <tr #templateVariable
      *ngFor = 'let worker of Workers'
      (mouseover)="showAdditionalData(worker, $('#txtWorkerAdditionalData'))">
  `
})
export class ExampleComponent implements OnInit {
  @ViewChild('templateVariable') element: ElementRef;

  constructor(
  ) { }

  ngOnInit() {
  }


  ngAfterViewInit() {
    console.log('element: ', this.element.nativeElement.value);
  }

}

You should never access the dom directly as it is against convention and apparently breaks a lot Angular 2 features.

You can read more about ViewChild and ViewChildren here..

Also note that you can use these decorators to get any kind of element even without template variables. Check the above link for examples.

Good luck!

Upvotes: 0

Related Questions