2

I am trying to implement the feature to add a list of emails input but the user. This is what i have so far

  List<String> _notificationEmails =[];
  var _notificationEmailsController = TextEditingController();
  Widget _buildNotificationEmailsInput() {
    return TextFormField(
      controller: _notificationEmailsController,
      style: inputTextStyle,
      maxLines: null,
      validator: (String value) {
        print(value);
        if (value.isEmpty) {
          return 'Emails Required';
        }
        return null;
      },
      onChanged: (String value){
        if(value.substring(value.length-1)==','){
          print('here');
            setState(() {
              _notificationEmails.add(value.substring(0,value.length-1));
            });
          _notificationEmailsController.clear();
        }
        print(_notificationEmails);
      },
    );
  }

My intended outcome is that when the user enters an email then adds a comma after it, the email is appended o the list and the input field cleared but i get a loop of the action resulting to this _notificationEmails.add(value.substring(0,value.length-1)); running to infinity.

Here are the logs

[   +3 ms] flutter: [[email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], je@gm<…>

This goes on and on. What have I done wrong?

Update

Incase it helps, i have realised the issue is brought about because every time the _notificationEmailsController.clear(); is called, it triggers onChange() thus the loop.

9
  • Try to call clear before setState. I think the onChange is called due to setState. Commented Feb 5, 2021 at 10:03
  • @danypata The problem still persists. Commented Feb 5, 2021 at 10:10
  • You got to do 2 things here. First check if the email is a valid you can use regex to check that and Second check if the email is already existing in the list and then proceed to add it Commented Feb 5, 2021 at 10:36
  • @DannyRufus Validation is not my issue Commented Feb 5, 2021 at 10:45
  • 1
    @Bright I updated my answer to only use same instance of TextEditingController. Commented Feb 5, 2021 at 13:47

2 Answers 2

2

Update: Please call TextEditingController.clear inside a Future.delayed. Because based from the description of clear...

this method should only be called between frames, e.g. in response to user actions, not during the build, layout, or paint phases.

import 'package:flutter/material.dart';

void main() {
  runApp(MaterialApp(
    home: MyApp(),
  ));
}

class MyApp extends StatefulWidget {
  @override
  _MyApp createState() => _MyApp();
}

class _MyApp extends State<MyApp> {
  final List<String> _notificationEmails = <String>[];
  final TextEditingController _controller = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Column(
          children: [
            _buildNotificationEmailsInput(),
            Expanded(
              child: ListView.builder(
                itemCount: _notificationEmails.length,
                itemBuilder: (_, int idx) => ListTile(
                  title: Text(_notificationEmails[idx]),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildNotificationEmailsInput() {
    return TextFormField(
      controller: _controller,
      validator: (String value) {
        print('VALIDATOR: $value');
        if (value.isEmpty) {
          return 'Emails Required';
        }
        return null;
      },
      onChanged: (String value) {
        if (value.substring(value.length - 1) == ',') {
          print('>>>>>> value = $value : controller = ${_controller.hashCode}');
          setState(() {
            _notificationEmails.add(value.substring(0, value.length - 1));
          });
          Future<void>.delayed(
            const Duration(milliseconds: 10),
            _controller.clear,
          );
          print(_notificationEmails);
        }
      },
    );
  }
}
Sign up to request clarification or add additional context in comments.

Comments

1
**You have to add a list of *TextEditingController* and need to add the contoller text to that list and parse it as you need.**     
     
      List<String> selection = [];  
     List<Product> productList = []; 

     //---------Adding contoller to list   
      
     productProvider.getAll(user.guid).forEach((element) {//---List<Product>
     final TextEditingController quantityController = 
     TextEditingController(text: element.quantity);
     quantityControllers.add(quantityController);
     });

       //-------Adding list of products to list
      List<Map<String, dynamic>> productItems = [];
       List<Product> productOriginalList = 
       productProvider.getAll(user.guid);
       for (int i = 0; i < productOriginalList.length; i++) {
       final Product product = productOriginalList[i];
       if (selection.contains(product.equipmentId)) {
                   
       productItems.add(product.toJson(quantityControllers[i].text));
                  }

     /* Map<String, dynamic> toJson(String quan) => {
    'ProductId': id,
    'Quantity': quan,
     };     
    TextField(
    controller: quantityControllers[index],*/
     

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.