我正在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检查更改还没有机会运行。有一种聪明而干净的方法吗?
答案 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
隐藏的元素,这可以解决您的问题。
答案 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;
}