TextField on change, call api - how to throttle this?
Asked Answered
E

2

5

If I have a textfield, and on change in that textfield, I call a function, which calls an API, how can I throttle that, so it calls that function only if user has not typed anything for 1 second?

Im lost here.. any help is more than welcome.

Ericson answered 19/2, 2019 at 11:30 Comment(0)
A
2

You need to make use of a class named CancelableOperation from the async package.

You can declare it in your stateful widget, outside the build() method:

CancelableOperation cancelableOperation;

And use it like so within your onChanged callback:

cancelableOperation?.cancel();

cancelableOperation = CancelableOperation.fromFuture(Future.delayed(Duration(seconds: 1), () {
  // API call here
}));
Apprise answered 19/2, 2019 at 12:1 Comment(1)
Note that with this approach, after one second is elapsed, the API call is invoked multiple times. This is because cancel method is asynchronous.Heartwood
H
19

Use a Timer.

If a key is pressed before one second cancel the old timer and reschedule with a new Timer, otherwise make the API call:

import 'dart:async';

class _MyHomePageState extends State<MyHomePage> {
  String textValue;
  Timer timeHandle;

  void textChanged(String val) {
    textValue = val;
    if (timeHandle != null) {
      timeHandle.cancel();
    }  
    timeHandle = Timer(Duration(seconds: 1), () {
      print("Calling now the API: $textValue");
    });
  }

  @override
  void dispose() {
      super.dispose();
      timeHandle.cancel();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Container(
              padding: EdgeInsets.all(20),
              alignment: Alignment.center,
              child: TextField(
                onChanged: textChanged,
                  decoration: InputDecoration(
                      border: InputBorder.none,
                      hintText: 'Please enter a search term')),
            ),
          ],
        ),
      ),
    );
  }
}
Heartwood answered 19/2, 2019 at 13:37 Comment(1)
You forgot null check in dispose(), if onChanged() not called. Anyway works like charm! Thanks.Vanden
A
2

You need to make use of a class named CancelableOperation from the async package.

You can declare it in your stateful widget, outside the build() method:

CancelableOperation cancelableOperation;

And use it like so within your onChanged callback:

cancelableOperation?.cancel();

cancelableOperation = CancelableOperation.fromFuture(Future.delayed(Duration(seconds: 1), () {
  // API call here
}));
Apprise answered 19/2, 2019 at 12:1 Comment(1)
Note that with this approach, after one second is elapsed, the API call is invoked multiple times. This is because cancel method is asynchronous.Heartwood

© 2022 - 2024 — McMap. All rights reserved.