Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

onSuggestionTap onsubmit are invoked both #165

Open
hpp0hpp opened this issue Aug 29, 2024 · 18 comments
Open

onSuggestionTap onsubmit are invoked both #165

hpp0hpp opened this issue Aug 29, 2024 · 18 comments
Labels
bug Something isn't working P3 Low Priority: A bug or a feature request we plan to work on in near future (default)

Comments

@hpp0hpp
Copy link

hpp0hpp commented Aug 29, 2024

Describe the bug
when I input something in the searchfield, and I use key to select one suggestion, when I press Enter, onSuggestionTap and onsubmit are invoked the same time, while only onSuggestionTap is expect to be invoked

To Reproduce
Steps to reproduce the behavior:
when I input something in the searchfield, and I use key to select one suggestion, when I press Enter, onSuggestionTap and onsubmit are invoked the same time, while only onSuggestionTap is expect to be invoked

[.] By clicking this checkbox, I confirm I am using the latest version of the package found on pub.dev/searchfield

Expected behavior
A clear and concise description of what you expected to happen.

Actual behavior
What you actually saw instead of the expected behavior.

Screenshots
If applicable, add screenshots to help explain your problem.

Code sample

Show code sample
Paste minimal and complete code sample here to investigate the issue. 

Additional context
Add any other context about the problem here.

@hpp0hpp
Copy link
Author

hpp0hpp commented Aug 29, 2024

maybe add else here works
image

@maheshj01 maheshj01 added the in triage Issue is currently being triaged label Aug 30, 2024
@maheshj01
Copy link
Owner

Hi @hpp0hpp Thanks for filing the issue.
The API is designed in a way that when you select a suggestion by pressing enter on a physical keyboard or submit using virtual keyboard onSubmit should be invoked and when you select a suggestion with a pointer device like mouse or with a touch onSuggestionTapped Should be invoked. If you are seeing both then please share me a minimal code sample to reproduce the issue.

Thanks

@maheshj01 maheshj01 added the waiting for author waiting for author to respond back with more info label Aug 30, 2024
@twfungi
Copy link

twfungi commented Sep 5, 2024

I'm encountering the same issue. Here is the code (for flutter web) that can reproduce the issue.

Steps to reproduce the issue:

  1. Select "Option1"
  2. Enter "Option1" to fire submit, and you see both events.

Console log:
[log] [onSuggestionTap] selected OPtion1 <--- Step 1
[log] [onSuggestionTap] selected OPtion1 <--- Step 2
[log] [onSubmit] OPtion1 <--- Step 2

Source code:

import 'package:flutter/material.dart';
import 'package:searchfield/searchfield.dart';
import 'dart:developer' as d;

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final focus = FocusNode();
  final _controller = TextEditingController();

  @override
  void initState() {
    super.initState();
    suggestions = getSuggestions();
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  var suggestions = <String>[];

  @override
  Widget build(BuildContext context) {
    Widget searchChild(x) => Padding(
          padding: const EdgeInsets.symmetric(vertical: 4.0, horizontal: 12),
          child: Text(x, style: Theme.of(context).textTheme.bodyMedium!),
        );

    SuggestionDecoration suggestionDecoration = SuggestionDecoration(
      elevation: 16.0,
      color: Colors.white54,
      borderRadius: BorderRadius.circular(24),
    );

    return Scaffold(
        appBar: AppBar(centerTitle: true, automaticallyImplyLeading: true, title: const Text('test')),
        body: GestureDetector(
            onTap: () {
              FocusScope.of(context).unfocus();
            },
            child: SizedBox(
                height: double.infinity,
                width: double.infinity,
                child: Column(
                  children: [
                    SizedBox(
                        width: 400,
                        child: SearchField(
                          controller: _controller,
                          onSearchTextChanged: (query) {
                            List<String> filter;
                            query = query.trim();
                            if (query.isEmpty) {
                              filter = suggestions = getSuggestions();
                            } else {
                              filter = suggestions
                                  .where((element) => element.toLowerCase().contains(query.toLowerCase()))
                                  .toList();
                            }
                            return filter.map((e) => SearchFieldListItem<String>(e, child: searchChild(e))).toList();
                          },
                          onSubmit: (str) async {
                            d.log('[onSubmit] $str');
                          },
                          initialValue: null,
                          onTap: () async {
                            suggestions = getSuggestions();
                            setState(() {});
                          },
                          showEmpty: false,
                          emptyWidget: Container(
                              decoration: suggestionDecoration, height: 200, child: const Center(child: Text('Empty'))),
                          key: const Key('searchfield'),
                          searchStyle: Theme.of(context).textTheme.bodyMedium!,
                          dynamicHeight: true,
                          maxSuggestionBoxHeight: 300,
                          scrollbarDecoration: ScrollbarDecoration(minThumbLength: 30, thickness: 10),
                          onTapOutside: null,
                          suggestionDirection: SuggestionDirection.down,
                          suggestionStyle: Theme.of(context).textTheme.bodyMedium!,
                          searchInputDecoration: InputDecoration(
                            prefixIcon: const Icon(Icons.search),
                            fillColor: Colors.white38,
                            suffixIcon: IconButton(
                              onPressed: _controller.clear,
                              icon: const Icon(Icons.clear),
                            ),
                            focusedBorder: OutlineInputBorder(
                              borderRadius: BorderRadius.circular(24),
                              borderSide: const BorderSide(
                                width: 1,
                                color: Colors.grey,
                                style: BorderStyle.solid,
                              ),
                            ),
                            border: OutlineInputBorder(
                              borderRadius: BorderRadius.circular(24),
                              borderSide: const BorderSide(
                                width: 1,
                                color: Colors.black,
                                style: BorderStyle.solid,
                              ),
                            ),
                            filled: true,
                            contentPadding: const EdgeInsets.symmetric(
                              horizontal: 20,
                            ),
                          ),
                          suggestionsDecoration: suggestionDecoration,
                          suggestions:
                              suggestions.map((e) => SearchFieldListItem<String>(e, child: searchChild(e))).toList(),
                          focusNode: focus,
                          suggestionState: Suggestion.expand,
                          onSuggestionTap: (SearchFieldListItem<String> x) {
                            focus.unfocus();
                            d.log('[onSuggestionTap] selected ${x.searchKey}');
                          },
                        )),
                  ],
                ))));
  }

  List<String> getSuggestions() {
    return ["OPtion1", "OPtion2", "OPtion3", "OPtion4", "OPtion5"];
  }
}

@twfungi
Copy link

twfungi commented Sep 5, 2024

I tried further with the above code by deleting one character at a time and pressing the enter key. It seems "Option1" stays selected even when I deleted characters. See the log below:

[log] [onSuggestionTap] selected OPtion1
[log] [onSubmit] OPtion

[log] [onSuggestionTap] selected OPtion1
[log] [onSubmit] OPtio

[log] [onSuggestionTap] selected OPtion1
[log] [onSubmit] OPti

[log] [onSuggestionTap] selected OPtion1
[log] [onSubmit] OPti

@maheshj01
Copy link
Owner

@twfungi Thanks for the code sample I will take a look at it, I have published a new release with few fixes v1.1.1.

However this issue has not been taken care of yet, I am not really sure if this is an issue. I need to rethink about the expected behavior or perhaps a race condition I believe?

Your suggestions are welcome! I would appreciate your feedback based on the latest version of the package.

Thanks

@maheshj01 maheshj01 added the review the issue needs to be reviewed again label Sep 14, 2024
@twfungi
Copy link

twfungi commented Sep 15, 2024

I'd suggest we fire either one, but not both. It depends on how you define these two events.

Through my observation onSuggestionTap is always fired before onSubmit. What I did to workaround this "issue" is to delay 200ms in onSuggestionTap before we make sure onSubmit is not fired. Something like:

onSubmit: (str) async {
                                          d.log('[onSubmit] $str');
                                          submitted = true;
                                          // perform the onSubmit action
                                         },                                        },
onSuggestionTap: (SearchFieldListItem<String> x) {
                                          submitted = false;
                                          focus.unfocus();
                                          d.log('[onSuggestionTap] selected ${x.searchKey}');
                                          Future.delayed(const Duration(milliseconds: 200), () async {
                                            if (!submitted) {
                                             // perform onSuggestionTap action
                                            }
                                          });
                                        },

maheshj01 added a commit that referenced this issue Sep 20, 2024
@maheshj01
Copy link
Owner

maheshj01 commented Sep 20, 2024

onSubmit is now fired only when an option is not selected and user hits enter, Let me know if this seems like a reasonable fix? Beacause while the option is selected onSuggestionTap will anyways fire

This is released in searchfield: ^1.1.2

cc: @twfungi @hpp0hpp

@twfungi
Copy link

twfungi commented Sep 22, 2024

verified the fix in 1.1.3, thanks!

@twfungi
Copy link

twfungi commented Sep 22, 2024

With 1.1.3, there's a side effect that, if the user inputs a string that partially matches something in the suggestion list and enters to fire submit, it always fires the matched item in the suggestion list instead of the string the user entered in the textedit.

I think we should allow the user to choose which text to fire, either the string the user enters in the textedit or the partially matched text. What do you think, @maheshj01 ?

@maheshj01
Copy link
Owner

maheshj01 commented Sep 22, 2024

That seems reasonable, We should make this configurable to allow Submitting custom input with an enum

  • submitType.custom / submitType.match

  • With submitType.custom: User can submit with the text entered in the textfield, and onSubmit will return the entered text

  • With submitType.match: User can Submit only the selected suggestion (matched based on the logic), if no suggestion matches the entered text onSubmit won't be fired and onSuggestionTap will be fired on selecting one of the suggestions either via keyboard or with a tap.

Let me know if this seems like a valid approach.

@twfungi
Copy link

twfungi commented Sep 23, 2024

sgtm

@maheshj01 maheshj01 added bug Something isn't working P1 High Priority: This is a show stopper and must be addressed immediately and removed waiting for author waiting for author to respond back with more info in triage Issue is currently being triaged review the issue needs to be reviewed again labels Sep 24, 2024
@maheshj01
Copy link
Owner

This is possible in latest release v1.1.4, we don't need a enum

That seems reasonable, We should make this configurable to allow Submitting custom input with an enum

  • submitType.custom / submitType.match
  • With submitType.custom: User can submit with the text entered in the textfield, and onSubmit will return the entered text
  • With submitType.match: User can Submit only the selected suggestion (matched based on the logic), if no suggestion matches the entered text onSubmit won't be fired and onSuggestionTap will be fired on selecting one of the suggestions either via keyboard or with a tap.

Let me know if this seems like a valid approach.

@maheshj01 maheshj01 added P3 Low Priority: A bug or a feature request we plan to work on in near future (default) and removed P1 High Priority: This is a show stopper and must be addressed immediately labels Sep 24, 2024
@maheshj01
Copy link
Owner

maheshj01 commented Sep 24, 2024

Bumping down the priority and keeping this issue open for discussion and feedback.

@twfungi
Copy link

twfungi commented Sep 26, 2024

This is possible in latest release v1.1.4, we don't need a enum

May I know how we can achieve this with v1.1.5? I just tried it and it still fires the matched suggestion instead of the entered text.

@maheshj01
Copy link
Owner

maheshj01 commented Sep 27, 2024

@twfungi Looks like I misunderstood, It is only partially possible as of now OnSubmit fires the entered takes when the searchresult is empty,

Note for self
OnSubmit should be fired regardless of whether the input matches or not on pressing enter as long as no suggestion is selected, if a suggestion is already selected enter will trigger onSuggestion tap replacing the input with selected suggestion.

@twfungi
Copy link

twfungi commented Sep 27, 2024

The problem here is, searchfield will just try to match one in the suggestion list and select it automatically and replace the user entered text with the auto-selected one when firing the onSubmit. This is not always helpful when the use case is to get the exact user input string and perform something else.

One solution without adding the enum is, we still fire both onSuggestion and onSubmit. On the onSuggestion event, the searchkey is the selected one, while on the other, the onSubmit string is the user entered string. Leave the decision to the user which one to use. If this is not the one you prefer, I'm also fine with the enum proposal you mentioned earlier.

@maheshj01
Copy link
Owner

Thanks for clarifying that @twfungi, I think would probably work on this over a weekend, if you are interested please feel free to make a PR.

@sabari7320
Copy link

@maheshj01 sir when i close the keyboard all the suggestion showing from scratch not showing hat i have entered char in the textfield
https://drive.google.com/file/d/132iZYWgLzDNMllLGyOlkA15SayzkrcZe/view check this

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working P3 Low Priority: A bug or a feature request we plan to work on in near future (default)
Projects
None yet
Development

No branches or pull requests

4 participants