Home > other >  Flutter Firestore: check if a username is taken
Flutter Firestore: check if a username is taken

Time:07-26

I have a firestore collection, 'users', that I have a String field 'handle' defined for each document. Id like to be able to query the collection and return a boolean value if the handle is currently used or not.

Im trying to use something like the following:

Future<bool> userExists(String handle) async =>
      (await userCollection.where("handle", isEqualTo: handle).get()).docs.length > 0;

However, since this is a future, can i use it to react in the ui following an onChanged call in the textfield? Or do i need to write it as a Stream?

Actual screen code:

import 'package:hero/screens/onboarding/widgets/widgets.dart';
import 'package:flutter/material.dart';
import 'package:step_progress_indicator/step_progress_indicator.dart';

import '../../../models/models.dart';
import '../widgets/custom_onbaording_buttons.dart';

class Handle extends StatefulWidget {
  final TabController tabController;
  final User user;
  const Handle({
    Key? key,
    required this.tabController,
    required this.user,
  }) : super(key: key);

  @override
  State<Handle> createState() => _HandleState();
}

class _HandleState extends State<Handle> {
  initState() {
    super.initState();
  }

  String handle = '@';
  bool isValid = false;

  @override
  Widget build(BuildContext context) {
    final controller = TextEditingController();
    return Padding(
      padding: const EdgeInsets.symmetric(horizontal: 30.0, vertical: 30),
      child: Column(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: [
          Column(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  CustomTextHeader(
                    tabController: widget.tabController,
                    text: 'What do you want your handle to be?',
                  ),

                  SizedBox(height: 10),
                  CustomTextField(
                    hint: handle,
                    initialValue: '@',
                    onChanged: (val) => setState(() => handle = val),
                  ),
                  // CustomCheckbox(
                ],
              ),
            ],
          ),
          Column(
            children: [
              StepProgressIndicator(
                totalSteps: 4,
                currentStep: 1,
                selectedColor: Theme.of(context).primaryColor,
                unselectedColor: Theme.of(context).scaffoldBackgroundColor,
              ),
              SizedBox(height: 10),
              CustomOnboardingButton(
                tabController: widget.tabController,
                text: 'NEXT STEP',
                id: widget.user.id,
              ),
            ],
          ),
        ],
      ),
    );
  }
}

Thanks!

CodePudding user response:

you can make a method that checks if the handle is valid or not every time the handle value is upgraded and changes the isValid value accordingly,

  Future<bool> userExists() async {
    bool exist = (await userCollection.where("handle", isEqualTo: handle).get())
            .docs
            .length >
        0;
    if (!exist) {
      setState(() => isValid = true);
    }
  }

after that you can use the isValid value in the textfield to show error

decoration: InputDecoration(
                errorText: isValid ? null : "Handle already taken",
              )

here is the full code(its just a rough idea implement it according to this plan)

import 'package:hero/screens/onboarding/widgets/widgets.dart';
import 'package:flutter/material.dart';
import 'package:step_progress_indicator/step_progress_indicator.dart';

import '../../../models/models.dart';
import '../widgets/custom_onbaording_buttons.dart';

class Handle extends StatefulWidget {
  final TabController tabController;
  final User user;
  const Handle({
    Key? key,
    required this.tabController,
    required this.user,
  }) : super(key: key);

  @override
  State<Handle> createState() => _HandleState();
}

class _HandleState extends State<Handle> {
  initState() {
    super.initState();
  }

  String handle = '@';
  bool isValid = false;

  Future<bool> userExists() async {
    bool exist = (await userCollection.where("handle", isEqualTo: handle).get())
            .docs
            .length >
        0;
    if (!exist) {
      setState(() => isValid = true);
    }
  }

  @override
  Widget build(BuildContext context) {
    final controller = TextEditingController();
    return Padding(
      padding: const EdgeInsets.symmetric(horizontal: 30.0, vertical: 30),
      child: Column(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: [
          Column(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  CustomTextHeader(
                    tabController: widget.tabController,
                    text: 'What do you want your handle to be?',
                  ),

                  SizedBox(height: 10),
                  CustomTextField(
                    hint: handle,
                    initialValue: '@',
                    decoration: InputDecoration(
                      errorText: isValid ? null : "Handle already taken",
                    ),
                    onChanged: (val) {
                      setState(() => handle = val);
                      userExists();
                    },
                  ),
                  // CustomCheckbox(
                ],
              ),
            ],
          ),
          Column(
            children: [
              StepProgressIndicator(
                totalSteps: 4,
                currentStep: 1,
                selectedColor: Theme.of(context).primaryColor,
                unselectedColor: Theme.of(context).scaffoldBackgroundColor,
              ),
              SizedBox(height: 10),
              CustomOnboardingButton(
                tabController: widget.tabController,
                text: 'NEXT STEP',
                id: widget.user.id,
              ),
            ],
          ),
        ],
      ),
    );
  }
}
  • Related