Angular2滚动到具有* ngIf的元素

时间:2017-03-15 19:59:20

标签: angular

我正在Angular 2中编写一个表单,用户提交表单,验证表单,如果输入有任何错误,我想将用户的浏览器滚动到第一个元素& #34;错误"

问题是,我的所有错误都使用* ngIf:

<input type="text" [(ngModel)]="model.first_name">
<div class="error" *ngIf="errors.first_name">
    {{errors.first_name}}
</div>

在我的提交功能

submit(){
   this.errors = this.validate();
   if(this.errors.any()){
      var errorDivs = document.getElementsByClassName("error");
      if(errorDivs.length > 0){
         errorDivs[0].scrollIntoView();
      }
   }
}

我意识到这是因为* ngIf完全从DOM中删除了div,并且Angular检查更改还没有机会运行。有一种聪明而干净的方法吗?

5 个答案:

答案 0 :(得分:16)

不确定我完全理解你的问题。

errors.first_name变得真实时,使用如下的指令会使元素滚动到视图中:

<div class="error" *ngIf="errors.first_name" scrollTo>
    {{errors.first_name}}
</div>
@Directive({ selector: '[scrollTo]'})
class ScrollToDirective implements AfterViewInit {
  constructor(private elRef:ElementRef) {}
  ngAfterViewInit() {
    this.elRef.nativeElement.scrollIntoView();
  }
}

答案 1 :(得分:9)

这是我想出的一种方式:

创建一个帮助类

export class ScrollHelper {
    private classToScrollTo: string = null;

    scrollToFirst(className: string) {
        this.classToScrollTo = className;
    }

    doScroll() {
        if (!this.classToScrollTo) {
            return;
        }
        try {
            var elements = document.getElementsByClassName(this.classToScrollTo);
            if (elements.length == 0) {
                return;
            }
            elements[0].scrollIntoView();
        }
        finally{
            this.classToScrollTo = null;
        }
    }
}

然后在

中要在其中使用它的组件中创建一个
private scrollHelper : ScrollHelper = new ScrollHelper();

然后当你发现自己有错误时

submit(){
   this.errors = this.validate();
   if(this.errors.any()){
        this.scrollHelper.scrollToFirst("error");
   }
}

然后推迟实际滚动,直到评估ngAfterViewChecked后的*ngIf

ngAfterViewChecked(){
    this.scrollHelper.doScroll();
}

答案 2 :(得分:2)

这可能不是最优雅的解决方案,但您可以尝试将错误聚焦代码包装在setTimeout中

submit(){
   this.erroors = this.validate();
   setTimeout(() => {
     if(this.errors.any()){
        var errorDivs = document.getElementsByClassName("error");
        if(errorDivs.length > 0){
          errorDivs[0].scrollIntoView();
        }
     }
   }, 50);
}

关键不在于延迟聚焦代码,而在于确保代码在事件循环的滴答之后运行。这将使更改检测时间运行,从而确保您的错误div有时间由Angular添加回DOM。

答案 3 :(得分:2)

我已经创建了一个包,用于处理 Angular 4 + 中的元素滚动。如果你正在使用Angular Universal,一切都适用于 AoT 和服务器端渲染。

NPM
@nicky-lenaers/ngx-scroll-to

的GitHub
@nicky-lenaers/ngx-scroll-to

此外,我最近创建了一个Plunker,显示滚动到最初由*ngIf隐藏的元素,这可以解决您的问题。

Check out the Plunker for a working ngIf example

答案 4 :(得分:0)

我的解决方案,很简单。

步骤

创建一个成员

scrollAnchor: string;

创建一个方法,如果设置了锚点,它将滚动到锚点。

ngAfterViewChecked(){
  if (this.scrollAnchor) {
    this.scrollToAnchor(this.scrollAnchor);
    this.scrollAnchor = null;
  }
}

,然后当您要滚动到div中具有ngIf的某个位置时, 只需设置scrollAnchor

this.scrollAnchor = "results";

非常简单! 请注意,您必须自己编写滚动条来锚定方法... 或滚动到element或其他内容 这是我的

 private scrollToAnchor(anchor: string): boolean {
    const element = document.querySelector("#" + anchor);
    if (element) {
      element.scrollIntoView({block: "start", behavior: "smooth"});
      return true;
    }
    return false;
  }