反应形式,检查用户名是否存在
Reactive Form , check if username exists
我在 Ionic/Firebase 中遇到一个问题,验证器的值是反应式的。特别是我在下面有这 2 个函数,用于检查 firebase 实时数据库中的用户名是否存在。 2 个函数 return 一个 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)
}
}
然后,我 class 在其中定义了一个 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 时也是如此。我该如何解决这个问题?
你很接近,但你在尝试解决导致混淆的问题时混合了不同的语法。
另一件让您陷入麻烦的事情是混淆了 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);
}
我在 Ionic/Firebase 中遇到一个问题,验证器的值是反应式的。特别是我在下面有这 2 个函数,用于检查 firebase 实时数据库中的用户名是否存在。 2 个函数 return 一个 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)
}
}
然后,我 class 在其中定义了一个 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 时也是如此。我该如何解决这个问题?
你很接近,但你在尝试解决导致混淆的问题时混合了不同的语法。
另一件让您陷入麻烦的事情是混淆了 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);
}