Bright
Bright

Reputation: 1067

Only allow number input in flutter text field Flutter

I have created my text field which should only allow number input for the purpose of some computing i will later do after the value has been input. Its almost working fine but there is one issue though.

Here is the code for the field

var numberInputFormatters = [new FilteringTextInputFormatter.allow(RegExp("[0-9]")),];


  String _tip='2';
  Widget _buildOtherTipInput() {
    return TextFormField(
      style: inputTextStyle,
      inputFormatters: numberInputFormatters,
      keyboardType: TextInputType.number,
      decoration: formInputDecoration.copyWith(
          prefix: Text('\$'),
          labelText: 'Enter Custom Tip Amount ',
          hintStyle: TextStyle(fontWeight: FontWeight.w600)
      ),
      onChanged: (val){
       setState(() {
         val!=null?_tip=val:_tip='0';
       });
      },

    );
  }

So when you input a number then try to input a non number character, it will not take the input but if i try to input a character that is not a number as the first, i get this error thrown

Invalid double

I do know that it comes from this code below that converts the string input to a double. What i don't understand is why it receives the invalid double in the first place yet i have set blockers for invalid(non number) input in my text field.

  String getTotal(){
    String theTip=_tip??'0';
     double  newTip = double.parse(theTip).truncateToDouble();
    return newTip.toStringAsFixed(2);
  }

Upvotes: 1

Views: 11367

Answers (2)

Thierry
Thierry

Reputation: 8383

Quick answer

Your problem is that val is never null.

After inputting a wrong character, val is ''. You should check if it is empty:

onChanged: (val){
  setState(() {
    val.isNotEmpty ? _tip=val : _tip='0';
  });
},

Longer answer

enter image description here

Instead of defining your own numberInputFormatters, you should use FilteringTextInputFormatter.digitsOnly.

Also, your _tip is not a String, you could store its value as an int instead.

The, your onChanged callback becomes:

onChanged: (val) => setState(() => _tip = int.tryParse(val) ?? 0),

Full source code:

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() {
  runApp(
    MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Flutter Demo',
      home: MyWidget(price: 9.99),
    ),
  );
}

class MyWidget extends StatefulWidget {
  final double price;

  const MyWidget({Key key, this.price}) : super(key: key);

  @override
  _MyWidgetState createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  int _tip = 2;

  String get _total => (widget.price + _tip).toStringAsFixed(2);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        alignment: Alignment.center,
        padding: EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text('Do you want to tip the waiter?'),
            const SizedBox(height: 16.0),
            TextFormField(
              initialValue: _tip.toString(),
              inputFormatters: [FilteringTextInputFormatter.digitsOnly],
              keyboardType: TextInputType.number,
              decoration: InputDecoration(
                  prefix: Text('\$'),
                  labelText: 'Enter Custom Tip Amount ',
                  hintStyle: TextStyle(fontWeight: FontWeight.w600)),
              onChanged: (val) => setState(() => _tip = int.tryParse(val) ?? 0),
            ),
            const SizedBox(height: 16.0),
            Text('TOTAL: $_total'),
          ],
        ),
      ),
    );
  }
}

Upvotes: 3

TDN
TDN

Reputation: 236

Consider using String Validator it is easy and simple to use

https://pub.dev/packages/string_validator

Upvotes: 1

Related Questions