布尔值未在订阅范围之外定义?

时间:2019-03-06 12:33:44

标签: angular typescript observable subscribe

我有一个以布尔检查结束的API调用。 我想创建新用户,但是如果数据库中存在电子邮件,我想设置 canAddUser = false 。 我执行以下操作:

  canAddUser: boolean;

  setNewUserValues() {
    if (this.formUser.email) {
      this.checkExistingEmail();
    }
  }

  checkExistingEmail() {
    this.userService.findPrivilegedUsersUsingGET().subscribe(users => {
      const mailIndex = users.findIndex(user => user.email === this.formUser.email);
      mailIndex !== -1 ? this.canAddUser = false : this.canAddUser = true;
      console.log(this.canAddUser);
    });
  }

如果将布尔值记录到当前正在执行的控制台中,则将获得正确的值。但是,如果我在其他地方记录它,则它首先是未定义的!然后,如果我触发触发 setNewUserValues()的按钮,它将再次获得正确的值。 我好想念什么?

编辑

某种程度上解决了我的问题。

  setNewUserValues() {
    if (this.formUser.email) {
      this.checkExistingEmail();
    }
  }

  checkExistingEmail() {
    this.userService.findPrivilegedUsersUsingGET().subscribe(users => {
      this.mailIndex = users.findIndex(user => user.email === this.formUser.email);
    });
    this.validateEmail(this.mailIndex);
    console.log(this.canAddUser);
  }

  private validateEmail(index: number) {
    index !== -1 ? this.canAddUser = false : this.canAddUser = true;
  }

如果我通过现有的电子邮件,我将获得正确的值,但是如果我通过不在数据库中的电子邮件但我将首先获得错误的值,那么如果再次触发它,则该值将再次可用。

4 个答案:

答案 0 :(得分:1)

如果您不订阅异步操作,则不能保证已将标志分配给代码中的任何地方。

我要做的是将布尔值标志更改为Subject:

canAddUser$: Subject<boolean>;

在需要时发出值:

mailIndex !== -1 ? this.canAddUser$.next(false): this.canAddUser$.next(true);
// this.canAddUser$.next(mailIndex === -1);

然后在需要时订阅它:

someFunction() {
    this.canAddUser$.subscribe(canAdd => {
        // Here *canAdd* is a boolean
    })
}

答案 1 :(得分:0)

您的findPrivilegedUsersUsingGET函数是异步的。这意味着可能需要几秒钟甚至几分钟才能完成。 canAddUser仅在异步调用结束时为true或false。

canAddUser: boolean; // undefined 


// this can take a while to complete.
this.userService.findPrivilegedUsersUsingGET().subscribe(users => {
      const mailIndex = users.findIndex(user => user.email === this.formUser.email);
      mailIndex !== -1 ? this.canAddUser = false : this.canAddUser = true;

      // do work here          
      console.log(this.canAddUser);
      this.doWork();
});

doWork() {
     console.log(this.canAddUser);
}

答案 2 :(得分:0)

基本答案,但是您可以将canAddUser初始化为默认值。

canAddUser = false;

答案 3 :(得分:0)

您可以急切地加载用户列表,然后通过模板将用户传递给组件的功能。

在您的组件中:

public users$: Observable<any[]>;

public ngOnInit() {
    this.users$ = this.userService.findPrivilegedUsersUsingGET().pipe(share());
}

setNewUserValues(users: any[]) {
    if (this.formUser.email) {
        this.checkExistingEmail(users);
    }
}

checkExistingEmail(users: any[]) {
   this.mailIndex = users.findIndex(user => user.email === this.formUser.email);
   this.validateEmail(this.mailIndex);
   console.log(this.canAddUser);
}

private validateEmail(index: number) {
   index !== -1 ? this.canAddUser = false : this.canAddUser = true;
}

在您的模板中:

<ng-container *ngIf="users$ | async as users">
    <button (click)="setNewUserValues(users)">Example</button>
</ng-container>
<ng-container *ngIf"!(users$ | async">
    Loading users...
</ng-container>

这是消除混合程序编程和反应式编程副作用的一种方法。

另一种方法是使checkExistingEmail()返回一个可观察的(或一个Promise)。

public constructor(private _change: ChangeDetectorRef) {}

setNewUserValues() {
  if (this.formUser.email) {
     this.checkExistingEmail(this.formUser.email).subscribe(canAddUser => {
         console.log("canAddUser:", canAddUser);
         this.canAddUser = canAddUser;
         this._change.markForCheck();
     });
  }
}

public checkExistingEmail(email): Observable<boolean> {
   return this.userService.findPrivilegedUsersUsingGET().pipe(
      map(users => users.findIndex(user => user.email === email) !== -1)
   );
}

上面的命令会将布尔结果打印到控制台,但我不知道您想对这个结果做什么。该操作已异步完成,我们需要告诉Angular组件的状态已更改,并且视图应该更新,所以我调用“ markForCheck()”,但是如果您不使用OnPush更改检测,则这可能不是必需的。

作为一般规则。如果您在组件内部时在异步回调中编写类似this.XXXX = YYYY;的代码。您将遇到副作用,因为您将过程编程与反应式编程混合在一起。

通常人们会问“如何从异步函数返回值”这个问题。当我看到他们的示例源代码时,经常使用this参考来屈服

进一步了解反应式编程可能会有所帮助:

https://gist.github.com/staltz/868e7e9bc2a7b8c1f754

https://egghead.io/courses/introduction-to-reactive-programming

最好重新学习Angular中的反应式主题:

https://angular.io/guide/reactive-forms