2016-08-14 94 views
53

我有一个组件,其中包含p元素。其onClick事件将将其更改为textarea,以便用户可以编辑数据。我的问题是:如何在角度2中获得dom元素

  • 我如何才能把重点放在textarea上?
  • 如何才能触及元素,以便我可以在其上应用.focus()?
  • 我可以避免使用document.getElemenntById()吗?

我曾尝试使用 “ElementRef” 和 “@ViewChild()”,然而我似乎失去了一些东西:

// ------ THE CLASS 
 
@ViewChild('tasknoteId') taskNoteRef:ElementRef; 
 

 
    noteEditMode: boolean = false; 
 

 
get isShowNote(){ 
 
    return !this.noteEditMode && this.todo.note ? true : false; 
 
    } 
 
    taskNote: string; 
 
    toggleNoteEditMode() { 
 
    this.noteEditMode = !this.noteEditMode; 
 
     this.renderer.invokeElementMethod(this.taskNoteRef.nativeElement,'focus'); 
 
    } 
 

 
// ------ THE COMPONENT 
 
<span class="the-insert"> 
 
     <form [hidden]="!noteEditMode && todo.note"> 
 
     <textarea #tasknoteId id="tasknote" 
 
        name="tasknote" 
 
        [(ngModel)]="todo.note" 
 
        placeholder="{{ notePlaceholder }}" 
 
        style="background-color:pink" 
 
        (blur)="updateNote()" (click)="toggleNoteEditMode()" 
 
        [autofocus]="noteEditMode" 
 
        [innerHTML]="todo.note"> 
 
     </textarea> 
 
     </form> 
 
    </span>

+0

参见http://stackoverflow.com/questions/34522306/angular-2-focus-on-newly-added-input-element –

回答

94

使用ViewChild#localvariable如此处所示,

<textarea #someVar id="tasknote" 
        name="tasknote" 
        [(ngModel)]="taskNote" 
        placeholder="{{ notePlaceholder }}" 
        style="background-color: pink" 
        (blur)="updateNote() ; noteEditMode = false " (click)="noteEditMode = false"> {{ todo.note }} 

</textarea> 

在成分,

OLDEST路

import {ElementRef} from '@angular/core'; 
@ViewChild('someVar') el:ElementRef; 

ngAfterViewInit() 
{ 
    this.el.nativeElement.focus(); 
} 


旧方式

import {ElementRef} from '@angular/core'; 
@ViewChild('someVar') el:ElementRef; 

constructor(private rd: Renderer) {} 
ngAfterViewInit() { 
    this.rd.invokeElementMethod(this.el.nativeElement,'focus'); 
} 


更新于22/03(三月)/ 2017

新途径

请注意,从角V4.0.0-rc.3(2017年3月10日)几件事情已经改变。 由于Angular团队会弃用invokeElementMethod,以上代码不再可以使用。

重大更改

自4.0 RC.1:

命名RendererV2到Renderer2
命名RendererTypeV2到RendererType2
重命名RendererFactoryV2到RendererFactory2

import {ElementRef,Renderer2} from '@angular/core'; 
@ViewChild('someVar') el:ElementRef; 

constructor(private rd: Renderer2) {} 

ngAfterViewInit() { 
     console.log(this.rd); 
     this.el.nativeElement.focus();  //<<<=====same as oldest way 
} 

console.log(this.rd)会给你以下方法,你现在可以看到invokeElementMethod不存在。 附加img,但尚未记录。

注:您可以使用Rendere2与/以下方法不ViewChild变量做这么多事情。

enter image description here

+0

它仅适用于第一次,你有什么想法? –

+0

是的,它只会工作一次。你要什么? – micronyks

+0

@CoffeeCode你可以移动this.rd.invokeElementMethod(this.el.nativeElement, '专注');到另一个函数,并调用它要再次使其成为焦点 – Nico

32

更新(2017年9月10日):

注意,原来的渲染服务现已在 青睐Renderer2的弃用

Renderer2 official doc.

此外,如所指出@GünterZöchbauer:

实际使用ElementRef就好了。还使用 带有Renderer2的ElementRef.nativeElement很好。不鼓励 直接访问ElementRef.nativeElement.xxx的属性。


您可以通过使用elementRef以及由ViewChild实现这一目标。然而,这不是推荐使用elementRef由于:

  • 安全问题
  • 紧耦合

official ng2 documentation指出。

使用elementRef(直接访问):

export class MyComponent {  
constructor (private _elementRef : elementRef) { 
this._elementRef.nativeElement.querySelector('textarea').focus(); 
} 
} 

使用ViewChild更好的方法):

<textarea #tasknote name="tasknote" [(ngModel)]="taskNote" placeholder="{{ notePlaceholder }}" 
style="background-color: pink" (blur)="updateNote() ; noteEditMode = false " (click)="noteEditMode = false"> {{ todo.note }} </textarea> // <-- changes id to local var 


export class MyComponent implements AfterViewInit { 
    @ViewChild('tasknote') input: ElementRef; 

    constructor(private renderer: Renderer2) {} //<-- changed to Renderer2 

    ngAfterViewInit() { 
    this.input.nativeElement.focus(); 

    } 
} 
+2

当我做你的方法,我得到无法读取性能nativeElement PF未定义 –

+3

你在哪里使用'renderer'?刚刚注入构造函数 – M98

+0

同样的错误在这里,当我尝试在上执行此方法时,我得到“无法读取属性'nativeElement'的未定义..” 我使用的是Angular 5,我试图导入Elevant Zoom脚本。 – Torai

11

角2.0.0决赛:

我发现,使用一个ViewChild setter是设置的最可靠的方法初始形式控制焦点:

@ViewChild("myInput") 
set myInput(_input: ElementRef | undefined) { 
    if (_input !== undefined) { 
     setTimeout(() => { 
      this._renderer.invokeElementMethod(_input.nativeElement, "focus"); 
     }, 0); 
    } 
} 

设定器首先被调用与undefined值随后与初始化ElementRef的呼叫。

工作实施例和完整的源位置:http://plnkr.co/edit/u0sLLi?p=preview

使用打字稿2.0.3最终/ RTM,角2.0.0最终/ RTM和Chrome 53.0.2785.116米(64位)。对角4+

Renderer

更新已被弃用,取而代之的Renderer2,但Renderer2does not haveinvokeElementMethod。您需要直接访问DOM才能设置焦点,如input.nativeElement.focus()

我仍然发现ViewChild设置器的方法效果最好。当使用AfterViewInit时,我有时会得到read property 'nativeElement' of undefined错误。

@ViewChild("myInput") 
set myInput(_input: ElementRef | undefined) { 
    if (_input !== undefined) { 
     setTimeout(() => { //This setTimeout call may not be necessary anymore. 
      _input.nativeElement.focus(); 
     }, 0); 
    } 
} 
+0

用'setTimeout'封装焦点的丑陋的黑客在我的代码中做了魔术。这次真是万分感谢。 –