根据条件订阅可观察对象

时间:2019-09-30 19:04:49

标签: angular observable subscription

背景

我使用的是“反应式表单”,该表单扩展了两个选项卡(仅页面的前半部分具有选项卡),然后是一个较长的页面,底部带有“提交”按钮。我单击“提交”按钮进行验证。

单击“提交”按钮时,验证失败时,页面需要滚动到错误表单字段。

我还能够根据FormGroups中的错误来加载选项卡。

问题

  1. 滚动发生在选项卡加载之前。
  2. 要解决第1点,我订阅了animationDone事件,然后滚动到其中的点。
submit(){
   //code to select the desired tab
   this.selectedTab.animationDone.subscribe(res => {
   this.myElement.nativeElement.ownerDocument.getElementsByClassName('ng-invalid mat-form-field')[0].scrollIntoView({ behavior: 'smooth' });
          });
}

一切正常,直到现在!!!

  1. 单击“批准”按钮后,将订阅该订阅,并且每当选择一个新的选项卡时,页面就会滚动到错误。我想取消订阅此可观察项,以后每当再次单击“提交”按钮时就订阅。

  2. 我尝试取消订阅,但无法再次订阅。有时这会破坏订阅功能并引发错误

我认为我缺少了一些东西,正在寻求帮助。在此先感谢!!

根据要求提供更多代码

submit()
{
    if(this.bookingForm.valid){
    // do some actions ....
     }
    else {
    this.bookingForm.markAllAsTouched();
    //subscribing to the event before selecting the tab

    this.selectedTab.animationDone.subscribe(res => {

     this.myElement.nativeElement.ownerDocument.getElementsByClassName('ng-invalid mat-form-field')[0].scrollIntoView({ behavior: 'smooth' });

          });

    // code to select the Tab where the error occurs .....
     this.selectedTab.selectedIndex = this.errorIndex;

    //unsubscribe
    this.selectedTab.animationDone.unsubscribe()

    } // close of else block
}// close of submit Function

取消订阅(或类似功能)是必需的,因为只有在单击“提交”按钮时才应订阅。如果未取消订阅(或暂停),则每次更改选项卡时都会调用订阅功能,并且页面会根据错误不断向上和向下滚动。

浏览量

这仅用于演示。 Page view

  

下面的编辑2

这里是StackBlitz Link。这只是一个示例页面,与此相比,“我的页面”具有更多的字段和表单组。

重新创建问题

场景1

  1. 填写字段-名称,Tab1,Details1
  2. 保持选中tab1,然后单击“提交”。
  3. 这应该向上滚动并显示 Tab2 。可以正常工作!延迟是可以接受的。
  4. 现在手动切换到Tab1。
  5. 您可以看到页面滚动到“详细信息2”字段。
  6. 每当切换选项卡时都会发生此滚动。我该如何停止?
  7. 我可以通过取消注释app.component.ts文件中的第38行来实现此目的。 -取消订阅命令。
    • 在此情况下,当我多次单击“提交”按钮时出现错误。
    • 当我第二次单击时,订阅无效。

1 个答案:

答案 0 :(得分:1)

对不起,您的回复很晚。我有点忙。

我没有研究您尝试的animation部分,而是专注于基础知识,因为我们只需要关注invalid元素。

Method 1

submit() {
  if(this.testForm.valid) {
    //Code to Submit
  } else {
    ((document.getElementsByClassName('mat-input-element ng-invalid')[0]) as HTMLElement).focus();
  }
}

Method 2

I came across this very cool way to do this.

import { MatInput } from '@angular/material';
import { QueryList, ViewChildren } from '@angular/core';

@ViewChildren(MatInput) inputs: QueryList <MatInput>;

submit() {
  if(this.testForm.valid) {
    //Code to Submit
  } else {
    this.inputs.find(input => !input.ngControl.valid).focus();
  }
}

此外,如果您始终希望首先选择Tab 1,如果它是invalid,则将其他条件放在else/ else if部分-

if(this.testForm.get('tab1').errors) {
  this.tabControl.selectedIndex = 0;
} else if(this.testForm.get('tab2').errors) {
  this.tabControl.selectedIndex = 1;
}

还有一件事,您必须稍加延迟,然后再专注于invalid元素,因为在DOM中为input创建Tab 2元素需要花费纳秒的时间,而专注于{如果Details 1Tab 1中的任何一个为2,则为{1}}。

invalid

只需在delay(ms: number) { return new Promise( resolve => setTimeout(resolve, ms) ); } 之前和focus()之后调用它

switching tabs check

如果您不想设置await this.delay(1); ,只需在delay事件上再次设置focus()并将animationDone时间设置为最短时间,这样您就不会看到{实时{1}上的{1}}。

遵循animationDuration链接以获取完整的流程,如果您遇到任何问题,请告诉我。