【问题标题】:Reactive Form , check if username exists反应表单,检查用户名是否存在
【发布时间】:2021-07-22 01:24:17
【问题描述】:

我在 Ionic/Firebase 中遇到了一个问题,验证器的值为反应形式。特别是,我在下面有这 2 个函数,用于检查 firebase 实时数据库中的用户名是否存在。这两个函数返回一个 Promise 布尔值:

export class UsernameValidator {
  static async getSnapshot(fc: FormControl){
    let isPresent:boolean = false;
    await firebase.database().ref().child("users").orderByChild("username")
    .equalTo(fc.value)
    .once("value", snapshot => {          
    }).then((data)=> {
      if(data.exists())
        isPresent = true;
      else
        isPresent = false;
    });
    console.log(isPresent);
    return isPresent; 
  }

  static async validUsername(fc: FormControl){
    try{
      let present:boolean =await UsernameValidator.getSnapshot(fc)
      if(present==true)
      return  (null);         
   else{
      return ({validUsername: true}); 
    } 
      }catch(e){
        console.log(e)
      }         
  }

然后,我有一个类,我在其中定义了一个 FormGroup 和验证器:

constructor(private route: ActivatedRoute, private router: Router, 
              public pfService: ProfileService, public fb: FormBuilder,
              public authService: AuthenticationService) 
  {
    this.id = this.authService.userData.uid;
    //Underscore and dot can't be next to each other (e.g user_.name).
    //Underscore or dot can't be used multiple times in a row (e.g user__name / user..name).
    this.validPattern = "^(?=.{6,20}$)(?!.*[_.]{2})[a-z0-9._]+$"; 
    this.validPatternName = "^[a-z]{3,10}$";
    this.userForm = fb.group({
      txtUsername:  ["",[Validators.required,Validators.pattern(this.validPattern),
                                                  UsernameValidator.validUsername]],
      txtName:     ["",[Validators.required,Validators.pattern(this.validPatternName)]],
    });
    this.userForm .valueChanges.subscribe(()=> {
      console.log(this.userForm.getError('validUsername'))
      })
  };

问题是无论 isPresent 的值如何,控制台中的 validUsername 始终为 null,当 isPresent 为 false 时也是如此。我该如何解决这个问题?

【问题讨论】:

    标签: javascript ionic-framework firebase-realtime-database async-await customvalidator


    【解决方案1】:

    您很接近,但您在尝试解决导致混乱的问题时混合了不同的语法。

    另一件让你陷入困境的事情是混淆了两种不同类型的DataSnapshot

    • 对于直接参考(例如database().ref("path/to/data")),您可以使用exists()val() 获取有关该位置数据的信息。
    • 对于查询引用(例如database().ref("path/to/group").orderByChild("name").equalTo("Tim's Group")),数据以列表形式返回,您可以使用numChildren()获取匹配结果的数量,hasChildren()查看是否有是任何结果(类似于exists()),您可以使用forEach() 遍历结果。
    static async isUsernameTaken(fc: FormControl) { // renamed from getSnapshot()
      return firebase.database().ref() // note the return here
        .child("users")
        .orderByChild("username")
        .equalTo(fc.value)
        .once("value")
        .then((querySnapshot) => querySnapshot.hasChildren());
    }
    

    但是,我不建议在 /users 中仅搜索用户名,因为这意味着您的用户数据是全球可读的,而且效率也很低。相反,您应该在数据库中创建一个仅包含用户名的索引。

    "/usernames": {
      "bob": "userId1",
      "frank": "userId2",
      "c00lguy": "userId3"
    }
    

    如果您使用这些Realtime Database Security Rules 来保护它,您还可以使用以下简单功能。

    {
      "usernames": {
        "$username": {
          // world readable
          ".read": true,
    
          // must be logged in to edit, you can only claim free usernames OR delete owned usernames
          ".write": "auth != null && (!newData.exists() || auth.uid == newData.val()) && (!data.exists() || data.val() == auth.uid)",
    
          // strings only
          ".validate": "newData.isString()",
        }
      }
    }
    

    检查用户名是否可用:

    static async isUsernameTaken(fc: FormControl) {
      return firebase.database().ref()
        .child("usernames")
        .child(fc.value)
        .once("value")
        .then((dataSnapshot) => dataSnapshot.exists());
    }
    

    声明用户名(如果写入失败,假设用户名被占用):

    static async claimUsername(fc: FormControl) {
      const user = firebase.auth().currentUser;
      if (!user) {
        throw new Error("You need to login first!")
      }
     
      return firebase.database().ref()
        .child("usernames")
        .child(fc.value)
        .set(user.uid);
    }
    

    【讨论】:

    • 哇很好的答案@samthecodingman,我是firebase的新手,有些事情我还不知道。非常感谢您的解决方案,有关数据快照的解释以及有关用户名的建议,我会这样做。
    猜你喜欢
    • 1970-01-01
    • 2011-08-05
    • 2019-08-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-29
    相关资源
    最近更新 更多