fluttersearchdynamicsubtype

Flutter : type '(dynamic) => dynamic' is not a subtype of type '(Book) => bool' of 'test'


I want to search in my content but I am facing a problem with my code. When I click my search icon it's first show me no data and then show me a error ( Another exception was thrown: type '(dynamic) => dynamic' is not a subtype of type '(Book) => bool' of 'test').

I create a search icon on my Home screen's AppBar Like this -

actions: <Widget>[
            FutureBuilder(
                future: fetchBooks(http.Client()),
                builder: (context, snapshot) {
                  return IconButton(
                    icon: Icon(Icons.search),
                    onPressed: () {
                      showSearch(
                          context: context,
                          delegate: BooksSearch(snapshot.data));
                    },
                  );
                }),
          ],

Here is my model.dart -

import 'dart:async';
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart' as http;

Future<List<Book>> fetchBooks(http.Client client) async {
  final response =
      await client.get('https://boimarket.abirahsan.com/public/api/v1/books');

  // Use the compute function to run parsePhotos in a separate isolate.
  return compute(parseBooks, response.body);
}

// A function that converts a response body into a List<Photo>.
List<Book> parseBooks(String responseBody) {
  final parsed = jsonDecode(responseBody).cast<String, dynamic>();
  return parsed['data'].map<Book>((json) => Book.fromJson(json)).toList();
}

class Book {
  final String name;
  final String author;
  final String html;
  final String description;
  final int category;

  Book({
    this.name,
    this.author,
    this.description,
    this.html,
    this.category,
  });

  factory Book.fromJson(Map<String, dynamic> json) {
    return Book(
      name: json['name'] as String,
      html: json['html'] as String,
      description: json['description'] as String,
      author: json['author'] as String,
      category: json['category'] as int,
    );
  }
}

and here is my booksearch.dart -

import 'package:flutter/material.dart';
import 'package:boimarket/model/model.dart';
import 'package:http/http.dart' as http;

class BooksSearch extends SearchDelegate<Book> {
  BooksSearch(this.allBooksData);

  final allBooksData;

  @override
  List<Widget> buildActions(BuildContext context) {
    return [
      SizedBox(
        width: 5.0,
      ),
      IconButton(
        icon: Icon(Icons.clear),
        onPressed: () {
          query = '';
        },
      )
    ];
  }

  @override
  Widget buildLeading(BuildContext context) {
    return IconButton(
      icon: Icon(Icons.arrow_back),
      onPressed: () {
        close(context, null);
      },
    );
  }

  @override
  Widget buildResults(BuildContext context) {
    return Container();
  }

  @override
  Widget buildSuggestions(BuildContext context) {
    return FutureBuilder(
        future: fetchBooks(http.Client()),
        builder: (context, snapshot) {
          if (!snapshot.hasData) {
            return Center(
              child: Text('No Data'),
            );
          } else {
            final result = allBooksData
                .where((a) => a.name.toLowerCase().contains(query))
                .toList();
            return ListView(
              children: result.map<Widget>((a) => Text(a.name)),
            );
          }
        });
  }
}

Where is the problem in my code? And How can I solve this error?


Solution

  • You can copy paste run full code below
    Step 1: You need json['name'].toString() for Unicode
    Step 2: specify List for data type

    final List<Book> allBooksData;
    ...
    AsyncSnapshot<List<Book>> snapshot)
    ...
    final List<Book> result
    

    working demo

    enter image description here

    enter image description here

    enter image description here

    full code

    import 'package:flutter/material.dart';
    import 'dart:async';
    import 'dart:convert';
    import 'package:flutter/foundation.dart';
    import 'package:http/http.dart' as http;
    import 'dart:convert' show utf8;
    
    Future<List<Book>> fetchBooks(http.Client client) async {
      final response =
          await client.get('https://boimarket.abirahsan.com/public/api/v1/books');
    
      // Use the compute function to run parsePhotos in a separate isolate.
      return compute(parseBooks, response.body);
    }
    
    // A function that converts a response body into a List<Photo>.
    List<Book> parseBooks(String responseBody) {
      final parsed = jsonDecode(responseBody).cast<String, dynamic>();
      return parsed['data'].map<Book>((json) => Book.fromJson(json)).toList();
    }
    
    class Book {
      final String name;
      final String author;
      final String html;
      final String description;
      final int category;
    
      Book({
        this.name,
        this.author,
        this.description,
        this.html,
        this.category,
      });
    
      factory Book.fromJson(Map<String, dynamic> json) {
        print(json['name'].toString());
        return Book(
          name: json['name'].toString() as String,
          html: json['html'] as String,
          description: json['description'] as String,
          author: json['author'] as String,
          category: json['category'] as int,
        );
      }
    }
    
    class BooksSearch extends SearchDelegate<Book> {
      BooksSearch(this.allBooksData);
    
      final List<Book> allBooksData;
    
      @override
      List<Widget> buildActions(BuildContext context) {
        return [
          SizedBox(
            width: 5.0,
          ),
          IconButton(
            icon: Icon(Icons.clear),
            onPressed: () {
              query = '';
            },
          )
        ];
      }
    
      @override
      Widget buildLeading(BuildContext context) {
        return IconButton(
          icon: Icon(Icons.arrow_back),
          onPressed: () {
            close(context, null);
          },
        );
      }
    
      @override
      Widget buildResults(BuildContext context) {
        return Container();
      }
    
      @override
      Widget buildSuggestions(BuildContext context) {
        return FutureBuilder(
            future: fetchBooks(http.Client()),
            builder: (context, AsyncSnapshot<List<Book>> snapshot) {
              switch (snapshot.connectionState) {
                case ConnectionState.none:
                  return Text('none');
                case ConnectionState.waiting:
                  return Center(
                    child: Text('No Data'),
                  );
                case ConnectionState.active:
                  return Text('');
                case ConnectionState.done:
                  if (!snapshot.hasData) {
                    return Center(
                      child: Text('No Data'),
                    );
                  } else {
                    print("query $query");
                    List<Book> result = allBooksData
                        .where((a) => a.name.toLowerCase().contains(query.toLowerCase()))
                        .toList();
                    print("result.length ${result.length}");
                    if (result.length != 0) {
                      return ListView.builder(
                        itemCount: result.length,
                        itemBuilder: (context, index) {
                          return ListTile(
                            title: Text('${result[index].name}'),
                          );
                        },
                      );
                    } else {
                      return Text("search no data");
                    }
                  }
              }
            });
      }
    }
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
            visualDensity: VisualDensity.adaptivePlatformDensity,
          ),
          home: MyHomePage(title: 'Flutter Demo Home Page'),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      MyHomePage({Key key, this.title}) : super(key: key);
    
      final String title;
    
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      int _counter = 0;
    
      void _incrementCounter() {
        setState(() {
          _counter++;
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text(widget.title),
            actions: <Widget>[
              FutureBuilder(
                  future: fetchBooks(http.Client()),
                  builder: (context, AsyncSnapshot<List<Book>> snapshot) {
                    return IconButton(
                      icon: Icon(Icons.search),
                      onPressed: () {
                        showSearch(
                            context: context, delegate: BooksSearch(snapshot.data));
                      },
                    );
                  }),
            ],
          ),
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Text(
                  'You have pushed the button this many times:',
                ),
                Text(
                  '$_counter',
                  style: Theme.of(context).textTheme.headline4,
                ),
              ],
            ),
          ),
          floatingActionButton: FloatingActionButton(
            onPressed: _incrementCounter,
            tooltip: 'Increment',
            child: Icon(Icons.add),
          ),
        );
      }
    }