【问题标题】:Angular2: Autofocus does not work on view 'refresh' (angular)Angular2:自动对焦不适用于视图“刷新”(角度)
【发布时间】:2017-03-09 12:23:57
【问题描述】:

我正在构建一个本质上类似于 Duolingo (SPA-ish) 的 QuizTool/LMS。

tldr: 点击 plnkr,“Check Answers”,“Do Another”,注意第一个输入元素不再具有输入焦点——即使 'autofocus' 属性似乎是正确设置。我可以解决这个问题吗?

https://embed.plnkr.co/DU8opUuquP5MXlcfdHIe/

长版:当我第一次呈现测验时,我可以将输入焦点(使用绑定的 autofocus 属性)设置到屏幕上的第一个输入区域(一个 TEXTAREA,其中用户将回答第一个问题)——这样用户就可以开始打字了。太棒了。

但是,一旦用户提交了第一组问题(第一个测验),用户就可以选择“做另一个”测验——我/Angular 能够重新绘制一个新的测验/UI(现在,恰好是完全相同的问题),只有“自动对焦”属性似乎不起作用——即第一个输入/文本区域没有获得焦点。

但是,似乎确实设置了绑定的autofocus 属性。

这意味着: 1)我以某种方式错误地读取了属性 2)这是 Chrome 中的一个错误(Mac OSX 上的版本 56.0.2924.87(64 位)) 3)正确设置该字段的自动对焦后,某些东西正在获取/窃取焦点 4) 等等。

我在ngFor 循环中设置了“firstQuestion”和“lastQuestion”本地变量,以帮助证明自动对焦属性是确定性设置的(只需将[autofocus]="firstQuestion" 更改为[autofocus]="lastQuestion")。

我愿意解决这个问题,但我需要。整个“无控制器”对我来说很新鲜,所以我很可能在整个设置中做了一些愚蠢的事情。

我尝试过使用 Angular 表单/ngForm,但似乎没有什么不同。

我也很想知道在哪里可以找到有关 Angular2 转换/“控制器”内容的基本教程——即我如何重绘屏幕,或切换到新视图等——没有什么可能被视为“传统”控制器。我认为您对 VB 说过类似的话:

oldForm.hide(); newForm.show();

如果这些都不起作用,我想手动设置焦点/jqLit​​e/pre-HTML5/whatever -- 在那里也没有取得太大成功 -- 因此这个问题。

谢谢。


不确定这有多大用处,但似乎我的应用程序(使用 ng cli 工具设置)与 plunkr 生成的应用程序有很大不同。

我发现:

  1. 即使 'document.activeElement' 设置为正确的文本区域(根据查询 DOM),它可能仍然无法激活用户开始输入文本(我设置了一个红色的 bg 以使其非常直观) , 和
  2. 如下所示的外部/托管 index.html 页面在我的组件完成加载后获得焦点。我添加了一个 hack javascript 函数来手动将焦点推回我想要的元素,但这实际上只是为了测试。

    <script>
         setInterval(function(){ 
            if(document.activeElement!=null){
                if(document.activeElement.id!='textarea-0'){ // find first input element on the page
                    document.getElementById('textarea-0').focus(); // set the focus
                }
            } 
        },
        5000);                
    </script>
    

更新:

已修复。再次感谢@mickdev。

这是第一个解决方案的一个小转折。我将其描述为“在您正在渲染的组件上使用带有 ngAfterViewChecked() 生命周期方法的模板引用变量”。


将这些东西添加到你正在渲染的组件中:

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

@ViewChild('focusThis') focusThis;

// to keep track of which element in our loop we are in
id:number=0 

//wait for viewchild to update then focus
ngAfterViewChecked(){
    // only focus the 0th (i.e. first) element of our loop
    if(this.id == 0){
        this.focusThis.nativeElement.focus();
        this.id++
    }
}

然后添加模板引用变量,'#focusThis':

<textarea   #focusThis
            [(ngModel)]="question.useranswer" 
            [disabled]="quiz.wasEvaluated"...

【问题讨论】:

  • autofocus 属性的 firstQuestion 和 firstQuestion 的值为 first。但我没有找到 first 的价值。
  • 'first' 由angular's *ngFor directive 自动创建。我给它起了另一个名字firstQuestion,试图更明确地说明我使用它的目的。如果它是ngFor 指令的第一个元素,那么'first' 将是一个布尔值true

标签: angular


【解决方案1】:

这是一个(丑陋的)解决方法,但它有效 :) 一、导入ViewChild

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

@ViewChild('test') test;

doAnother() {
    this.quiz = new Quiz();

    this.test.nativeElement.focus(); 
}

然后更新视图:

<div><textarea [autofocus]="firstQuestion" #test></textarea></div>

这是一个有效的 plunker: https://plnkr.co/edit/S6wRn3tUTxZcOQdojzr6?p=preview

更新:这里有一个更优雅的方式来实现这个ElementRef

//component
import {Component, NgModule, ElementRef} from '@angular/core'

this.element.nativeElement.querySelector('#textarea-1').focus()

//template
<div><textarea id="textarea-{{ question.id }}" [autofocus]="firstQuestion"></textarea></div>

现在,您可以定位 DOM 中的任何文本区域。这是一个工作 plunker : https://plnkr.co/edit/izH61uVHBreEwdVQNoSf?p=preview

【讨论】:

  • 哇,似乎确实有效。但如何?我看到template reference variable docs,但是......我的问题列表中的每个问题/文本区域不会声明并绑定该值吗?即,this.test.nativeElement 引用的模板引用变量是否只绑定一次,第一次通过*ngFor
  • Dom 一次只能聚焦一个元素。所以它将专注于第一个。如果需要,您还可以定位第一个 &lt;textarea&gt;
  • 查看我的更新答案,以更优雅的方式实现您想要的:)
  • 谢谢,这看起来也很酷。我通常总是想要用户可以实际输入的第一个输入字段——因此,非禁用、非隐藏等,当我在ngFor 循环中列出问题时,我会知道这些事情,所以我应该能够在您的第二个解决方案中使用循环计数器代替{{question.id}}。我想我有这一切权利。再次感谢,很棒的东西。
  • 我实际上又在看这个了。尽管 plunker 都可以工作,而且 plunker 几乎与我的设置相同,但一定不是,因为没有一个解决方案在我笔记本电脑上的实际代码中起作用。我尝试禁用所有 chrome 扩展无济于事。如果我最终发现发生了什么,我会回帖。我一直在尝试各种生命周期方法,但那里也发生了一些奇怪的事情。几乎就像有一些监控进程不断调整 UI,即使没有任何用户输入。
【解决方案2】:
<input type="text" #myInput />
{{ myInput.focus() }}

只需在模板内输入后添加 {{ myInput.focus() }}

【讨论】:

  • 这种工作,但它永远将焦点放在那个输入上。如果您单击其他输入,焦点不会转移到新输入,至少对我来说不是。
  • 没错。此方法对于只有一个输入的表单很有用。
猜你喜欢
  • 2022-01-19
  • 1970-01-01
  • 1970-01-01
  • 2015-11-16
  • 2018-01-23
  • 2021-05-03
  • 2013-11-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多