L.K.M Ranudipura
L.K.M Ranudipura

Reputation: 3

Flutter: How to assign other value (object) as Text Editing Controller in Another Field?

I'm building a form that has contact name and phone number fields. User will be able to choose (tap) contact from previously saved contact list, and this should display name and phone numbers at their respective fields.

To achieve that I'm using TypeAheadFormField from Flutter_Form_Builder Package version: 3.14.0 to build my form.

I successfully assign _nameController from local database in the default TypeAheadFormField controller. But I can't assign _mobileController from the same choice I tapped to FormBuilderTextField.

I managed to get "name'-value with TypeAheadFormField, but everytime I switch the choices from suggestions, the _mobileController.text didn't update on FormBuilderTextField

My code as follow:

    import 'package:myApp/customer.dart';
    import 'package:myApp/db_helper.dart';
    import 'package:flutter/material.dart';
    import 'package:flutter_form_builder/flutter_form_builder.dart';
    
    class MyForm extends StatefulWidget {
      @override
      _MyFormState createState() => _MyFormState();
    }
    
    class _MyFormState extends State<MyForm> {
      DatabaseHelper _dbHelper;
    
      Customer _customer = Customer();
      List<Customer> _customerList = [];
    
      final _formKey = GlobalKey<FormBuilderState>();
      final _cfKey = GlobalKey<FormBuilderState>();
    
      final _nameController = TextEditingController();
      final _inputContactNameController = TextEditingController();
      final _inputContactPhoneController = TextEditingController();
      var _mobileController = TextEditingController();
    
      @override
      void initState() {
        super.initState();
        _refreshBikeSellerList();
        setState(() {
          _dbHelper = DatabaseHelper.instance;
        });
        _mobileController = TextEditingController();
        _mobileController.addListener(() {
          setState(() {});
        });
      }
    
      @override
      void dispose() {
        _mobileController.dispose();
        _nameController.dispose();
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        return Container(
          child: FormBuilder(
            key: _formKey,
            child: Column(
              children: [
                FormBuilderTypeAhead(
                  attribute: 'contact_person',
                  initialValue: _customer,
                  controller: _nameController,
                  onChanged: (val) {},
                  itemBuilder: (context, Customer _customer) {
                    return ListTile(
                      title: Text(_customer.name),
                      subtitle: Text(_customer.mobile),
                    );
                  },
                  selectionToTextTransformer: (Customer c) => c.name,
                  suggestionsCallback: (query) {
                    if (query.isNotEmpty) {
                      var lowercaseQuery = query.toLowerCase();
                      return _customerList.where((_customer) {
                        return _customer.name
                            .toLowerCase()
                            .contains(lowercaseQuery);
                      }).toList(growable: false)
                        ..sort((a, b) => a.name
                            .toLowerCase()
                            .indexOf(lowercaseQuery)
                            .compareTo(
                                b.name.toLowerCase().indexOf(lowercaseQuery)));
                    } else {
                      return _customerList;
                    }
                  },
                  textFieldConfiguration: TextFieldConfiguration(
                    autofocus: true,
                    style: DefaultTextStyle.of(context).style.copyWith(
                          fontSize: 17,
                          letterSpacing: 1.2,
                          color: Colors.black,
                          fontWeight: FontWeight.w300,
                        ),
                    // controller: guessMotor1,
                  ),
                  onSuggestionSelected: (val) {
                    if (val != null) {
                      return _customerList.map((_customer) {
                        setState(() {
                          _mobileController.text = _customer.mobile;
                        });
                      }).toList();
                    } else {
                      return _customerList;
                    }
                  },
                ),
                FormBuilderTextField(
                  controller: _mobileController,
                  attribute: 'mobile',
                  readOnly: true,
                  style: TextStyle(fontSize: 17),
                  decoration: InputDecoration(
                    hintText: 'mobile',
                  ),
                ),
 SizedBox(height: 40),
            Container(
              child: RaisedButton(
                onPressed: () async {
                  await manageContact(context);
                },
                child: Text('Manage Contact'),
              ),
            ),
              ],
            ),
          ),
        );
      }
    
      manageContact(BuildContext context) async {
        showDialog(
          context: context,
          builder: (context) => AlertDialog(
            title: Text(
              'Manage Contact',
              textAlign: TextAlign.center,
            ),
            titleTextStyle: TextStyle(
                fontWeight: FontWeight.w500,
                fontSize: 17,
                color: Colors.black45,
                letterSpacing: 0.8),
            shape: RoundedRectangleBorder(
                borderRadius: BorderRadius.all(Radius.circular(12))),
            content: FormBuilder(
              key: _cfKey,
              child: Column(
                mainAxisSize: MainAxisSize.min,
                children: [
                  // SizedBox(height: 10),
                  InkResponse(
                    onTap: () {},
                    child: CircleAvatar(
                      radius: 30,
                      child: Icon(
                        Icons.person_add,
                        color: Colors.grey[100],
                      ),
                      backgroundColor: Colors.grey[500],
                    ),
                  ),
                  SizedBox(height: 10),
                  Container(
                    width: MediaQuery.of(context).size.width * 0.5,
                    margin: EdgeInsets.symmetric(horizontal: 15),
                    child: FormBuilderTextField(
                      maxLength: 20,
                      controller: _inputContactNameController,
                      textAlign: TextAlign.start,
                      keyboardType: TextInputType.text,
                      textCapitalization: TextCapitalization.words,
                      attribute: 'contact_person',
                      decoration: InputDecoration(
                          prefixIcon: Icon(
                        Icons.person_outline,
                        size: 22,
                      )),
                      onChanged: (val) {
                        setState(() {
                          _customer.name = val;
                          _formKey
                              .currentState.fields['contact_person'].currentState
                              .validate();
                        });
                      },
                      autovalidateMode: AutovalidateMode.always,
                      validators: [
                        FormBuilderValidators.required(),
                        FormBuilderValidators.maxLength(20),
                        FormBuilderValidators.minLength(2),
                      ],
                    ),
                  ),
                  Container(
                    width: MediaQuery.of(context).size.width * 0.5,
                    margin: EdgeInsets.symmetric(horizontal: 15),
                    child: FormBuilderTextField(
                      attribute: 'phone_number',
                      controller: _inputContactPhoneController,
                      textAlign: TextAlign.start,
                      keyboardType: TextInputType.number,
                      decoration: InputDecoration(
                          prefixIcon: Icon(
                        Icons.phone_android,
                        size: 22,
                      )),
                      onChanged: (val) {
                        setState(() {
                          _customer.mobile = val;
                          _formKey.currentState.fields['phone_number'].currentState
                              .validate();
                        });
                      },
                      validators: [
                        FormBuilderValidators.required(),
                        FormBuilderValidators.numeric(),
                      ],
                      valueTransformer: (text) {
                        return text == null ? null : num.tryParse(text);
                      },
                    ),
                  ),
                  SizedBox(height: 20),
                  Row(
                    mainAxisAlignment: MainAxisAlignment.spaceAround,
                    children: [
                      RaisedButton(
                          color: Colors.white,
                          child: Text('Cancel'),
                          onPressed: () {
                            Navigator.of(context).pop();
                          }),
                      RaisedButton(
                        color: Colors.grey[400],
                        child: Text(
                          'Save',
                          style: TextStyle(color: Colors.white),
                        ),
                        onPressed: () async {
                          try {
                            if (_formKey.currentState.validate()) {
                              _formKey.currentState.save();
                              if (_customer.id == null)
                                await _dbHelper.insertBikeContact(_customer);
                              else
                                await _dbHelper.updateCustomer(_customer);
                              _refreshBikeSellerList();
                              _formKey.currentState.reset();
                              _inputContactNameController.clear();
                              _inputContactPhoneController.clear();
                              Navigator.of(context).pop();
                            }
                          } catch (e) {
                            print(e);
                          }
                        },
                      )
                    ],
                  ),
                ],
              ),
            ),
          ),
        );
      }
    
      _refreshBikeSellerList() async {
        List<Customer> x = await _dbHelper.getCustomer();
        setState(() {
          _customerList = x;
        });
      }
    }

Is there any possible way to update _mobileController as I tap?

Any help would be much appreciated. Thank you in advance.

EDITED:

class where I save the customer data:

class Customer {
  int id;
  String name;
  String mobile;

  static const tblCustomer = 'Customer';
  static const colId = 'id';
  static const colName = 'name';
  static const colMobile = 'mobile';

  Customer({
    this.id,
    this.name,
    this.mobile,
  });

  Map<String, dynamic> toMap() {
    var map = <String, dynamic>{colName: name, colMobile: mobile};
    if (id != null) map[colId] = id;
    return map;
  }

  Customer.fromMap(Map<String, dynamic> map) {
    id = map[colId];
    name = map[colName];
    mobile = map[colMobile];
  }

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is Customer &&
          runtimeType == other.runtimeType &&
          name == other.name;

  @override
  int get hashCode => name.hashCode;

  @override
  String toString() {
    return name;
  }
}

Here is my database:

import 'dart:async';
import 'dart:io';

import 'package:path_provider/path_provider.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';

import 'customer.dart';

class DatabaseHelper {
  static const _databaseVersion = 1;
  static const _databaseName = 'Kiloin.db';

  DatabaseHelper._();
  static final DatabaseHelper instance = DatabaseHelper._();

  Database _database;
  Future<Database> get database async {
    if (_database != null) return _database;
    _database = await _initDatabase();
    return _database;
  }

  _initDatabase() async {
    Directory dataDirectory = await getApplicationDocumentsDirectory();
    String dbPath = join(dataDirectory.path, _databaseName);
    return await openDatabase(
      dbPath,
      version: _databaseVersion,
      onCreate: _onCreateDB,
    );
  }

  _onCreateDB(Database db, int version) async {
    await db.execute('''
    CREATE TABLE ${Customer.tblCustomer}(
      ${Customer.colId} INTEGER PRIMARY KEY AUTOINCREMENT,
      ${Customer.colName} TEXT NOT NULL,
      ${Customer.colMobile} TEXT NOT NULL
    ) 
    ''');
  }

  Future<int> insertBikeContact(Customer customer) async {
    Database db = await database;
    return await db.insert(Customer.tblCustomer, customer.toMap());
  }

  Future<List<Customer>> getCustomer() async {
    Database db = await database;
    List<Map> contact = await db.query(Customer.tblCustomer);
    return contact.length == 0
        ? []
        : contact.map((e) => Customer.fromMap(e)).toList();
  }

  Future<int> updateCustomer(Customer customer) async {
    Database db = await database;
    return await db.update(Customer.tblCustomer, customer.toMap(),
        where: '${Customer.colId}=?', whereArgs: [customer.id]);
  }

  Future<int> deleteContact(int id) async {
    Database db = await database;
    return await db.delete(Customer.tblCustomer,
        where: '${Customer.colId}=?', whereArgs: [id]);
  }
}

Upvotes: 0

Views: 1913

Answers (1)

Lee3
Lee3

Reputation: 3067

The value that you get from onSuggestionSelected is the customer. Use that value to update _mobileController.text.

onSuggestionSelected: (customer) {
       if (customer != null) {
          setState(() {
             _mobileController.text = customer.mobile;
          });
       }
    }

Upvotes: 2

Related Questions