2016-08-14 25 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'封裝焦點的醜陋的黑客在我的代碼中做了魔術。這次真是萬分感謝。 –