skip to Main Content

Edit: solved by adding a unique key to the widget constructor call:

Edit 2: as Randal Schwartz mentioned -> this is not a solution. Issue NOT solved and still open.

  @override
  SearchTermInput get searchTermInput => SearchTermInputOneString(
        key: UniqueKey(),
        currentSearchTermInputContent:
            widgetRef.read(apiEndpointUniversalSearchTermInputContentProvider),
        captionList: ["Statement"],
        // todo : allow umlauts! or better deny numbers?
        inputFormatterAllow: RegExp(".*"),
        onSubmit: onSubmit,
        onLostFocus: onLostFocus,
      );

I have an abstract class (ApiEndpoint) with two implementations (ApiEndpointName, ApiEndpointUniversal).

Both implementations have a StatefulWidget (SearchTermInputOneString) inherited from the same base class (SearchTermInput).

For both ApiEndpoint-objects the Widget part of SearchTermInputOneStringis created separately – what is correct.
My problem is, that the State-part of SearchTermInputOneString is created only once – so ApiEndpointName and ApiEndpointUniversal own the same state.

I have to read ApiEndpoint-specific configuration during initState – that does not work because initState is called only for the first ApiEndpoint-instance πŸ™

Any ideas how to solve that?

abstract class ApiEndpoint:

enum ApiEndpointType {
  today,
  unseen,
  universal,
  name,
  exactAge,
  ageBetween,
  ageGreaterThanOrEqual,
  ageLessThanOrEqual
}

abstract class ApiEndpoint {
  ApiEndpointType get type;
  String get title;
  SearchTermInput get searchTermInput;
  String get searchFunctionName;

  bool validateData(BuildContext context, WidgetRef ref);
  void onSubmit(
      BuildContext context, WidgetRef ref, List<String> searchTermInputContent);
  void onLostFocus(
      BuildContext context, WidgetRef ref, List<String> searchTermInputContent);
}

ApiEndpointName implementation:

class ApiEndpointName implements ApiEndpoint {
  final WidgetRef widgetRef;

  ApiEndpointName({required this.widgetRef});

  @override
  String get searchFunctionName => "getObituariesByName";

  @override
  SearchTermInput get searchTermInput => SearchTermInputOneString(
        currentSearchTermInputContent:
            widgetRef.read(apiEndpointNameSearchTermInputContentProvider),
        captionList: ["Name"],
        inputFormatterAllow: RegExp("[a-zA-Z% ]"),
        onSubmit: onSubmit,
        onLostFocus: onLostFocus,
      );

  @override
  String get title => "... by name";

  @override
  ApiEndpointType get type => ApiEndpointType.name;

  @override
  bool validateData(BuildContext context, WidgetRef ref) {
    ...
  }

  @override
  void onSubmit(BuildContext context, WidgetRef ref,
      List<String> searchTermInputContent) {
    ...
  }

  @override
  void onLostFocus(BuildContext context, WidgetRef ref,
      List<String> searchTermInputContent) {
    ...
  }

ApiEndpointUniversal implementation:

class ApiEndpointUniversal implements ApiEndpoint {
  final WidgetRef widgetRef;

  ApiEndpointUniversal({required this.widgetRef});

  @override
  String get searchFunctionName => "getObituariesUniversal";

  @override
  SearchTermInput get searchTermInput => SearchTermInputOneString(
        currentSearchTermInputContent:
            widgetRef.read(apiEndpointUniversalSearchTermInputContentProvider),
        captionList: ["Statement"],
        inputFormatterAllow: RegExp(".*"),
        onSubmit: onSubmit,
        onLostFocus: onLostFocus,
      );

  @override
  String get title => "... universal";

  @override
  ApiEndpointType get type => ApiEndpointType.universal;

  @override
  bool validateData(BuildContext context, WidgetRef ref) {
    ...
  }

  @override
  void onSubmit(BuildContext context, WidgetRef ref,
      List<String> searchTermInputContent) {
    ...
  }

  @override
  void onLostFocus(BuildContext context, WidgetRef ref,
      List<String> searchTermInputContent) {
    ...
  }
}

abstract StatefulWidget:

abstract class SearchTermInput extends ConsumerStatefulWidget {
  const SearchTermInput({super.key});

  List<String> get currentSearchTermInputContent;
  List<String>? get captionList;
  RegExp get inputFormatterAllow;
  void Function(BuildContext, WidgetRef, List<String>) get onSubmit;
  void Function(BuildContext, WidgetRef, List<String>) get onLostFocus;
}

Implementation:

class SearchTermInputOneString extends SearchTermInput {
  @override
  final List<String> currentSearchTermInputContent;

  @override
  final List<String> captionList;

  @override
  final RegExp inputFormatterAllow;

  @override
  final void Function(BuildContext, WidgetRef, List<String>) onSubmit;

  @override
  final void Function(BuildContext, WidgetRef, List<String>) onLostFocus;

  const SearchTermInputOneString({
    super.key,
    required this.currentSearchTermInputContent,
    required this.captionList,
    required this.inputFormatterAllow,
    required this.onSubmit,
    required this.onLostFocus,
  });

  @override
  ConsumerState<ConsumerStatefulWidget> createState() =>
      _SearchTermInputOneStringState();
}

class _SearchTermInputOneStringState
    extends ConsumerState<SearchTermInputOneString> {
  late TextEditingController textEditingController;

  @override
  void initState() {
    super.initState();
    textEditingController = TextEditingController();
    textEditingController.text = widget.currentSearchTermInputContent.isNotEmpty
        ? widget.currentSearchTermInputContent[0]
        : "";
  }

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

  @override
  Widget build(BuildContext context) {
    return Focus(
      child: TextFormField(
        controller: textEditingController,
        decoration: InputDecoration(
          border: const OutlineInputBorder(),
          labelText: widget.captionList.isNotEmpty ? widget.captionList[0] : "",
          suffixIcon: IconButton(
            onPressed: () {
              textEditingController.text = "";
            },
            icon: Icon(Icons.clear),
          ),
        ),
        inputFormatters: [
          FilteringTextInputFormatter.allow(widget.inputFormatterAllow)
        ],
        onFieldSubmitted: (_) {
          widget.onSubmit(context, ref, [textEditingController.text]);
        },
      ),
      onFocusChange: (hasFocus) {
        if (!hasFocus) {
          widget.onLostFocus(context, ref, [textEditingController.text]);
        }
      },
    );
  }
}

I create the List of ApiEndpoints this way:

List<ApiEndpoint> getApiEndPoints({required WidgetRef widgetRef}) {
  final List<ApiEndpoint> apiEndpoints = [
    ApiEndpointName(widgetRef: widgetRef),
    ApiEndpointUniversal(widgetRef: widgetRef),
  ];

  return apiEndpoints;
}

2

Answers


  1. Chosen as BEST ANSWER

    Okay, I changed my code but unfortunately I now got the same problem - the state is not updated for the second Widget-Instance (only if the first instance is disposed before!) :(

    This is how the code now looks:

    Widget that changes the widgets (for "Search via Name" and "Universal Search"):

      @override
      Widget build(BuildContext context) {
        _runsAfterBuild(context, ref);
    
        final currentApiEndpoint = ref.watch(currentApiEndpointProvider);
    
        return Scaffold(
          appBar: AppBar(
            title: const Text("Search obituaries ..."),
            centerTitle: true,
            actions: [
              IconButton(
                  tooltip: "Start search...",
                  onPressed: () {
                    doSearch(context, ref);
                  },
                  icon: const Icon(Icons.search)),
            ],
          ),
          body: SafeArea(
            child: Padding(
              padding: const EdgeInsets.all(8.0),
              child: Column(
                children: [
                  DropdownButtonFormField<ApiEndpoint>(
                      items: dropDownMenuItems,
                      value: currentApiEndpoint,
                      onChanged: (apiEndpoint) {
                        doOnDropDownChanged(context, ref, apiEndpoint);
                      }),
                  const SizedBox(
                    height: 10,
                  ),
                  currentApiEndpoint.searchTermInput,
                ],
              ),
            ),
          ),
        );
      }
    

    BaseClass for the ApiEndpoint implementations:

    abstract class ApiEndpoint {
      ApiEndpointType get type;
      String get title;
      SearchTermInput get searchTermInput;
      String get searchFunctionName;
    
      bool validateData(BuildContext context, WidgetRef ref);
      void onSubmit(
          BuildContext context, WidgetRef ref, List<String> searchTermInputContent);
      void onLostFocus(
          BuildContext context, WidgetRef ref, List<String> searchTermInputContent);
    }
    

    ApiEndpoint-Class that owns the widget for the first instance of the widget (Search via name):

    class ApiEndpointName implements ApiEndpoint {
      final log = getLogger();
      final NotifierProvider<ApiEndpointNameSearchTermInputContent, List<String>>
          apiEndpointSearchTermInputContentProvider =
          apiEndpointNameSearchTermInputContentProvider;
    
      ApiEndpointName();
    
      @override
      String get searchFunctionName => "getObituariesByName";
    
      @override
      SearchTermInput get searchTermInput => SearchTermInputOneString(
            // key: Key("ApiEndpointName"), // UniqueKey(),
            apiEndpointSearchTermInputContentProvider:
                apiEndpointSearchTermInputContentProvider,
            captionList: ["Name"],
            textInputFormatter: [
              FilteringTextInputFormatter.deny(RegExp(r"[0-9]"))
            ],
            onSubmit: onSubmit,
            onLostFocus: onLostFocus,
          );
    
      @override
      String get title => "... by name";
    
      @override
      ApiEndpointType get type => ApiEndpointType.name;
    
      @override
      bool validateData(BuildContext context, WidgetRef ref) {
        var contentList = ref.read(apiEndpointSearchTermInputContentProvider);
        return contentList.isNotEmpty && contentList[0].isNotEmpty;
      }
    
      @override
      void onSubmit(BuildContext context, WidgetRef ref,
          List<String> searchTermInputContent) {
        // set values
        ref
            .read(currentSearchTermInputContentProvider.notifier)
            .setValue(searchTermInputContent);
        ref
            .read(apiEndpointSearchTermInputContentProvider.notifier)
            .setValue(searchTermInputContent);
    
        // start search
        var doSearch = ref.read(doSearchFunctionProvider);
        if (doSearch != null) {
          doSearch(context, ref);
        } else {
          log.d("no doSearch method found!");
        }
      }
    
      @override
      void onLostFocus(BuildContext context, WidgetRef ref,
          List<String> searchTermInputContent) {
        // set values
        ref
            .read(currentSearchTermInputContentProvider.notifier)
            .setValue(searchTermInputContent);
        ref
            .read(apiEndpointSearchTermInputContentProvider.notifier)
            .setValue(searchTermInputContent);
      }
    }
    

    ApiEndpoint-Class that owns the widget for the second instance of the widget (Universal search):

    class ApiEndpointUniversal implements ApiEndpoint {
      final log = getLogger();
      final NotifierProvider<ApiEndpointUniversalSearchTermInputContent,
              List<String>> apiEndpointSearchTermInputContentProvider =
          apiEndpointUniversalSearchTermInputContentProvider;
    
      ApiEndpointUniversal();
    
      @override
      String get searchFunctionName => "getObituariesUniversal";
    
      @override
      SearchTermInput get searchTermInput => SearchTermInputOneString(
            // key: Key("ApiEndpointUniversal"), // UniqueKey(),
            apiEndpointSearchTermInputContentProvider:
                apiEndpointSearchTermInputContentProvider,
            captionList: ["Statement"],
            textInputFormatter: [FilteringTextInputFormatter.allow(RegExp(r".*"))],
            onSubmit: onSubmit,
            onLostFocus: onLostFocus,
          );
    
      @override
      String get title => "... universal";
    
      @override
      ApiEndpointType get type => ApiEndpointType.universal;
    
      @override
      bool validateData(BuildContext context, WidgetRef ref) {
        var contentList = ref.read(apiEndpointSearchTermInputContentProvider);
        return contentList.isNotEmpty && contentList[0].isNotEmpty;
      }
    
      @override
      void onSubmit(BuildContext context, WidgetRef ref,
          List<String> searchTermInputContent) {
        // set values
        ref
            .read(currentSearchTermInputContentProvider.notifier)
            .setValue(searchTermInputContent);
        ref
            .read(apiEndpointSearchTermInputContentProvider.notifier)
            .setValue(searchTermInputContent);
    
        // start search
        var doSearch = ref.read(doSearchFunctionProvider);
        if (doSearch != null) {
          doSearch(context, ref);
        } else {
          log.d("no doSearch method found!");
        }
      }
    
      @override
      void onLostFocus(BuildContext context, WidgetRef ref,
          List<String> searchTermInputContent) {
        // set values
        ref
            .read(currentSearchTermInputContentProvider.notifier)
            .setValue(searchTermInputContent);
        ref
            .read(apiEndpointSearchTermInputContentProvider.notifier)
            .setValue(searchTermInputContent);
      }
    }
    
    

    BaseClass of the Widget:

    abstract class SearchTermInput extends ConsumerStatefulWidget {
      const SearchTermInput({super.key});
    
      NotifierProvider? get apiEndpointSearchTermInputContentProvider;
      List<String>? get captionList;
      List<TextInputFormatter>? get textInputFormatter;
      void Function(BuildContext, WidgetRef, List<String>) get onSubmit;
      void Function(BuildContext, WidgetRef, List<String>) get onLostFocus;
    }
    

    Widget implementation for ApiEndpointName and ApiEndpointUniversal:

    class SearchTermInputOneString extends SearchTermInput {
      @override
      final NotifierProvider apiEndpointSearchTermInputContentProvider;
    
      @override
      final List<String> captionList;
    
      @override
      final List<TextInputFormatter>? textInputFormatter;
    
      @override
      final void Function(BuildContext, WidgetRef, List<String>) onSubmit;
    
      @override
      final void Function(BuildContext, WidgetRef, List<String>) onLostFocus;
    
      const SearchTermInputOneString({
        super.key,
        required this.apiEndpointSearchTermInputContentProvider,
        required this.captionList,
        required this.textInputFormatter,
        required this.onSubmit,
        required this.onLostFocus,
      });
    
      @override
      // ignore: no_logic_in_create_state - this is temporarily for for logging!
      ConsumerState<ConsumerStatefulWidget> createState() {
        final log = getLogger();
        log.t("createState");
        return _SearchTermInputOneStringState();
      }
    }
    
    class _SearchTermInputOneStringState
        extends ConsumerState<SearchTermInputOneString> {
      late TextEditingController textEditingController;
      late List<String> currentContent;
    
      @override
      void initState() {
        super.initState();
        final log = getLogger();
        log.t("initstate");
        textEditingController = TextEditingController();
      }
    
      @override
      void didChangeDependencies() {
        _runsAfterInit(context, ref);
        final log = getLogger();
        log.t("didChangeDependencies");
    
        // read apiEndpoint content
        currentContent = ref
            .read(widget.apiEndpointSearchTermInputContentProvider)
            .cast<String>();
        textEditingController.text =
            currentContent.isNotEmpty ? currentContent[0] : "";
    
        super.didChangeDependencies();
      }
    
      @override
      void dispose() {
        textEditingController.dispose();
        final log = getLogger();
        log.t("dispose");
        super.dispose();
      }
    
      Future<void> _runsAfterInit(BuildContext context, WidgetRef ref) async {
        await Future.delayed(Duration.zero); // <-- Add a 0 dummy waiting time
    
        final log = getLogger();
        log.t("_runsAfterInit");
    
        // set current content
        ref
            .read(currentSearchTermInputContentProvider.notifier)
            .setValue(currentContent);
      }
    
      @override
      Widget build(BuildContext context) {
        return Focus(
          child: TextFormField(
            controller: textEditingController,
            decoration: InputDecoration(
              border: const OutlineInputBorder(),
              labelText: widget.captionList.isNotEmpty ? widget.captionList[0] : "",
              suffixIcon: IconButton(
                onPressed: () {
                  textEditingController.text = "";
                },
                icon: Icon(Icons.clear),
              ),
            ),
            inputFormatters: widget.textInputFormatter,
            onFieldSubmitted: (_) {
              widget.onSubmit(context, ref, [textEditingController.text]);
            },
          ),
          onFocusChange: (hasFocus) {
            if (!hasFocus) {
              widget.onLostFocus(context, ref, [textEditingController.text]);
            }
          },
        );
      }
    }
    

    Logoutput after the first instance has been created:

    ────────────────────────────────────────────────────────────────────────────────────────
    #0   SearchTermInputOneString.createState (package:obituary_viewer/features/obituaries/presentation/widgets/search_term_inputs/search_term_input_one_string.dart:39:9)
    β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„
    2024-11-18 08:26:03.262
    β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„
     createState
    ────────────────────────────────────────────────────────────────────────────────────────
    ────────────────────────────────────────────────────────────────────────────────────────
    #0   _SearchTermInputOneStringState.initState (package:obituary_viewer/features/obituaries/presentation/widgets/search_term_inputs/search_term_input_one_string.dart:53:9)
    β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„
    2024-11-18 08:26:03.269
    β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„
     initstate
    ────────────────────────────────────────────────────────────────────────────────────────
    ────────────────────────────────────────────────────────────────────────────────────────
    #0   _SearchTermInputOneStringState.didChangeDependencies (package:obituary_viewer/features/obituaries/presentation/widgets/search_term_inputs/search_term_input_one_string.dart:61:9)
    β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„
    2024-11-18 08:26:03.272
    β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„
     didChangeDependencies
    ────────────────────────────────────────────────────────────────────────────────────────
    ────────────────────────────────────────────────────────────────────────────────────────
    #0   ApiEndpointNameSearchTermInputContent.build (package:obituary_viewer/features/obituaries/presentation/provider/search_term_input_content_provider.dart:26:9)
    β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„
    2024-11-18 08:26:03.275
    β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„
     ApiEndpointNameSearchTermInputContent provider build
    ────────────────────────────────────────────────────────────────────────────────────────
    ────────────────────────────────────────────────────────────────────────────────────────
    #0   DoSearchFunction.build (package:obituary_viewer/features/obituaries/presentation/provider/search_screen_provider.dart:13:9)
    β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„
    2024-11-18 08:26:03.402
    β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„
     DoSearchFunction provider build
    ────────────────────────────────────────────────────────────────────────────────────────
    ────────────────────────────────────────────────────────────────────────────────────────
    #0   DoSearchFunction.setValue (package:obituary_viewer/features/obituaries/presentation/provider/search_screen_provider.dart:19:9)
    β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„
    2024-11-18 08:26:03.404
    β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„
     DoSearchFunction set to Closure: (BuildContext, WidgetRef) => void from Function 'doSearch':.
    ────────────────────────────────────────────────────────────────────────────────────────
    ────────────────────────────────────────────────────────────────────────────────────────
    #0   _SearchTermInputOneStringState._runsAfterInit (package:obituary_viewer/features/obituaries/presentation/widgets/search_term_inputs/search_term_input_one_string.dart:85:9)
    β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„
    2024-11-18 08:26:03.405
    β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„
     _runsAfterInit
    ────────────────────────────────────────────────────────────────────────────────────────
    

    Logoutput after the second instance:

    > flutter:
    > β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
    > flutter: β”‚ #0   CurrentApiEndpoint.setValue
    > (package:obituary_viewer/features/obituaries/presentation/provider/api_endpoint_provider.dart:30:9)
    > flutter:
    > β”œβ”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„
    > flutter: β”‚ 2024-11-18 08:27:41.773 flutter:
    > β”œβ”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„
    > flutter: β”‚  CurrentApiEndpoints set to Instance of
    > 'ApiEndpointUniversal' flutter:
    > └─────────────────────────────────────────────────────────────────────────────────────────
    

    That's it - no create, no initState (what seems to be correct after deleting the unique key), no didChangeDependencies :( - and the text of the texteditingcontroller is still the one of the first instance :(

    I am at the very beginning of my β€œflutter career” and don't want to learn anything wrong. I am therefore very grateful for your advice!


  2. After playing around a lot of time without getting didChangeDependencies to work I found out that didUpdateWidget did the trick. Do you think that this okay or is there another stumbling block that I overlooked?

      @override
      void didUpdateWidget(covariant SearchTermInputOneString oldWidget) {
        final log = getLogger();
        log.t("didUpdateWidget");
    
        // read apiEndpoint content
        currentContent = ref
            .read(widget.apiEndpointSearchTermInputContentProvider)
            .cast<String>();
        textEditingController.text =
            currentContent.isNotEmpty ? currentContent[0] : "";
    
        super.didUpdateWidget(oldWidget);
      }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search