Angular 订阅基于条件的可观测数据

Angular 订阅基于条件的可观测数据,angular,observable,subscription,Angular,Observable,Subscription,背景 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 => {

背景

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
Im使用的是反应式表单,它可以扩展到两个选项卡(页面的前半部分就有选项卡),然后是一个底部有Submit按钮的长页面。我在点击提交按钮时进行验证

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

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

问题

  • 滚动发生在加载选项卡之前
  • 为了解决第1点,我订阅了animationDone事件,然后滚动到其中的点
  • 在这之前一切都很好

  • 单击“批准”按钮后,订阅将订阅,每当选择新选项卡时,页面将滚动至错误。我想取消订阅这个可观察的,然后在再次单击提交按钮时重新订阅

  • 我试图退订,但我无法再次订阅。这有时会破坏subscribe函数并引发错误

  • 我想我错过了什么,正在寻求帮助。提前谢谢

    需要更多代码

    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
    
    取消订阅(或类似功能)是必需的,因为只有在单击提交按钮时才能订阅。如果未取消订阅(或暂停),则每次更改选项卡时都会调用subscribe函数,并且页面会根据错误不断上下滚动

    页面视图

    这只是为了示范。

    编辑下面的第2条

    这是你的电话号码。这只是一个示例页面,与此相比,我的页面有更多的字段和表单组

    重新创建问题

    情景1

  • 填写字段-名称、选项卡1、详细信息1
  • 保持tab1处于选中状态,然后单击Submit
  • 这将向上滚动并显示选项卡2。工作如预期!耽搁是可以接受的
  • 现在手动切换到Tab1
  • 您可以看到页面滚动到Details 2字段
  • 切换选项卡时会出现此滚动。如何停止此操作
  • 我可以通过取消app.component.ts文件中第38行的注释来实现这一点。-取消订阅命令。
    • 在这种情况下,当我多次单击Submit按钮时出现错误
    • 当我第二次单击时,订阅不起作用

  • 很抱歉反应太晚。我有点忙

    我没有查看您尝试的
    动画部分,而是关注基本内容,因为如果元素
    无效
    ,我们只需要关注元素

    delay(ms: number) {
        return new Promise( resolve => setTimeout(resolve, ms) );
      }
    

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

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


    还有一件事,由于在DOM中为
    选项卡2
    创建
    input
    元素需要纳秒的时间,如果
    选项卡1
    2
    中的任何一个
    无效,您必须在关注
    无效的
    元素之前稍微延迟一下时间

    delay(ms: number) {
        return new Promise( resolve => setTimeout(resolve, ms) );
      }
    
    只需在
    focus()

    await this.delay(1);
    
    如果您不想设置
    延迟
    ,只需在
    animationDone
    事件上再次设置
    focus()
    ,并将
    animationDuration
    时间设置为最小值,这样您就不会实时看到
    细节1
    上的
    focus


    按照
    方法
    链接查看完整流程,如果您遇到任何问题,请告诉我。

    您可以在此处粘贴更多代码吗。我不确定这是否是实现你想要做的事情的正确方法。但是你可以使用
    行为主体
    而不是
    可观察的
    ,并在一定时间后执行
    下一步
    。@SuyashGupta,我已经用更多细节更新了我的问题。你也可以共享你的html吗?您所说的
    在加载选项卡之前发生滚动是什么意思?
    “批准”按钮附带了哪些所有事件?它在页面上的什么位置?我将在stackBlitz中重新创建我的问题,并在此处共享链接。谢谢您的回答。我使用延迟的方法有一个小问题。这有多愚蠢?如果加载该选项卡需要更多的时间怎么办?在我的场景中,选项卡本身是一个独立的复杂组件,它是延迟加载的。为了确保这一点,我必须订阅动画完成观察员。为了确定标签是否已加载,以下是可能的:1。动画制作;2.选择TAB改变;这两个都是可观察的。谢谢你的建议,把注意力集中在输入字段上,而不仅仅是滚动。我当然会使用它。你可以在这里验证同样的情况-因为我已经将
    动画持续时间设置为
    800 ms
    ,但是延迟只有
    1 ms
    ,但仍然
    focus()
    工作正常,所以使用
    延迟
    解决方案没有任何伤害。谢谢Suyash。我将使用延迟方法和焦点(而不是scrollIntoView)。但我仍然不相信使用延迟;但我会使用,因为我没有更好的解决方案。