icemanbsi / searchable_dropdown

MIT License
107 stars 166 forks source link

Model Class Support #9

Closed PrismaSoftGC closed 4 years ago

PrismaSoftGC commented 4 years ago

I tried to use the package with a model class, but when I search, it doesn't appear in the list. Do you have a model example? Or does this plugin really not support it?

My code:

class FabricanteOleo {
  String nome;
  int id;

  FabricanteOleo({this.nome, this.id});

  FabricanteOleo.fromJson(json) {
    nome = json['nome'];
    id = json['id'];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['nome'] = this.nome;
    data['id'] = this.id;
    return data;
  }
}

 _dropSearch() {
    return new SearchableDropdown<FabricanteOleo>(
      isCaseSensitiveSearch: true,
      items: listaFabricantes.map((fab){
        return DropdownMenuItem<FabricanteOleo>(
          child: new Text(fab.nome),
          value: fab,
        );
      }).toList(),
      value: fabricanteOleoSelecionado,
      hint: new Text('Select One'),
      searchHint: new Text(
        'Select One',
        style: new TextStyle(fontSize: 20),
      ),
      onChanged: (FabricanteOleo value) {
        setState(() {
          this.fabricanteOleoSelecionado = value;
        });
      },
    );

Captura de Tela 2020-02-05 às 20 06 28

lcuis commented 4 years ago

Hello @PrismaSoftGC ,

Here is a working example:

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

class FabricanteOleo {
  String nome;
  int id;

  FabricanteOleo({this.nome, this.id});

  FabricanteOleo.fromJson(json) {
    nome = json['nome'];
    id = json['id'];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['nome'] = this.nome;
    data['id'] = this.id;
    return data;
  }

  String toString(){
    return(nome);
  }
}

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {

  List<FabricanteOleo> listaFabricantes = [];
  FabricanteOleo fabricanteOleoSelecionado;

  @override
  void initState() {
    listaFabricantes.add(FabricanteOleo(nome:"Petronas",id:1));
    listaFabricantes.add(FabricanteOleo(nome:"Petrobras",id:2));
    listaFabricantes.add(FabricanteOleo(nome:"Trebol",id:3));
    super.initState();
  }

  _dropSearch() {
    return new SearchableDropdown<FabricanteOleo>(
      isCaseSensitiveSearch: true,
      items: listaFabricantes.map((fab){
        return DropdownMenuItem<FabricanteOleo>(
          child: new Text(fab.nome),
          value: fab,
        );
      }).toList(),
      value: fabricanteOleoSelecionado,
      hint: new Text('Select One'),
      searchHint: new Text(
        'Select One',
        style: new TextStyle(fontSize: 20),
      ),
      onChanged: (FabricanteOleo value) {
        setState(() {
          this.fabricanteOleoSelecionado = value;
        });
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Searchable Dropdown Demo'),
        ),
        resizeToAvoidBottomPadding: false,
        body: Padding(
          padding: const EdgeInsets.all(15.0),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.center,
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              _dropSearch(),
            ],
          ),
        ),
      ),
    );
  }
}

The main difference is the use of the toString() function which is used in the plugin to match the typed strings.

PrismaSoftGC commented 4 years ago

Worked perfectly. Please write in the documentation that it is necessary to use toString in model classes. Thank you very much for your willingness.

PrismaSoftGC commented 4 years ago

Is it possible to use the package with validator and label? If so how to do it?

lcuis commented 4 years ago

Worked perfectly. Please write in the documentation that it is necessary to use toString in model classes. Thank you very much for your willingness.

You're welcome! Yes, I believe the documentation could use some efforts. I may do some of this the next time I propose a PR.

Is it possible to use the package with validator and label? If so how to do it?

Here is an example of what I understand from your request.

Call SearchableDropdown constructor with 2 parameters (which don't exist right now):

Example:

Here are cases where user enters:

Is this correct?

If so, no, I don't know of any way to achieve this for now.

PrismaSoftGC commented 4 years ago

@lcuis Yes, similar to what you described. The label I am referring to is this.

Captura de Tela 2020-02-10 às 08 29 42

And just to make it clearer, it is not exactly the TextInputType, but a simple validator. When the user does not select any value in the dropdown I would like it to be a validator in the Form widget. like this:

Captura de Tela 2020-02-10 às 08 31 33

lcuis commented 4 years ago

I understand.

This validation is especially useful for mandatory fields.

Since PR #10 merged 3 days ago, it is possible to do something very close to what you are asking for with the help of the new selectedValueWidgetFn parameter as shown below:

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

class FabricanteOleo {
  String nome;
  int id;

  FabricanteOleo({this.nome, this.id});

  FabricanteOleo.fromJson(json) {
    nome = json['nome'];
    id = json['id'];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['nome'] = this.nome;
    data['id'] = this.id;
    return data;
  }

  String toString(){
    return(nome);
  }
}

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {

  List<FabricanteOleo> listaFabricantes = [];
  FabricanteOleo fabricanteOleoSelecionado;

  @override
  void initState() {
    listaFabricantes.add(FabricanteOleo(nome:"Petronas",id:1));
    listaFabricantes.add(FabricanteOleo(nome:"Petrobras",id:2));
    listaFabricantes.add(FabricanteOleo(nome:"Trebol",id:3));
    super.initState();
  }

  _dropSearch() {
    return new SearchableDropdown<FabricanteOleo>(
      isCaseSensitiveSearch: true,
      items: listaFabricantes.map((fab) {
        return DropdownMenuItem<FabricanteOleo>(
          child: new Text(fab.nome),
          value: fab,
        );
      }).toList(),
      value: fabricanteOleoSelecionado,
      hint: new Text('Select One'),
      searchHint: new Text(
        'Select One',
        style: new TextStyle(fontSize: 20),
      ),
      onChanged: (FabricanteOleo value) {
        setState(() {
          this.fabricanteOleoSelecionado = value;
        });
      },
      displayClearButton: true,
      selectedValueWidgetFn: (value) =>
          Padding(
              padding: EdgeInsets.fromLTRB(20, 20, 20, 20),
              child: value != null ? Text(
                value.toString(),
              ) :
              Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      "Select please",
                      style: TextStyle(
                        color: Theme.of(context).hintColor,
                      ),
                    ),
                    Text(
                      "Mandatory",
                      style: TextStyle(
                        height: 1.5,
                        fontSize: 10,
                        color: Colors.red,
                        decoration: TextDecoration.overline,
                        decorationColor: Colors.red,
                      ),
                    ),
                  ]
              )
          ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Searchable Dropdown Demo'),
        ),
        resizeToAvoidBottomPadding: false,
        body: Padding(
          padding: const EdgeInsets.all(15.0),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.center,
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              _dropSearch(),
            ],
          ),
        ),
      ),
    );
  }
}

Here is the result: image

lcuis commented 4 years ago

Here is something even closer to what you asked for using the same selectedValueWidgetFn parameter: image image

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

class FabricanteOleo {
  String nome;
  int id;

  FabricanteOleo({this.nome, this.id});

  FabricanteOleo.fromJson(json) {
    nome = json['nome'];
    id = json['id'];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['nome'] = this.nome;
    data['id'] = this.id;
    return data;
  }

  String toString(){
    return(nome);
  }
}

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {

  List<FabricanteOleo> listaFabricantes = [];
  FabricanteOleo fabricanteOleoSelecionado;

  @override
  void initState() {
    listaFabricantes.add(FabricanteOleo(nome:"Petronas",id:1));
    listaFabricantes.add(FabricanteOleo(nome:"Petrobras",id:2));
    listaFabricantes.add(FabricanteOleo(nome:"Trebol",id:3));
    listaFabricantes.add(FabricanteOleo(nome:"AGIP",id:4));
    super.initState();
  }

  _dropSearch() {
    return new SearchableDropdown<FabricanteOleo>(
      isCaseSensitiveSearch: true,
      items: listaFabricantes.map((fab) {
        return DropdownMenuItem<FabricanteOleo>(
          child: new Text(fab.nome),
          value: fab,
        );
      }).toList(),
      value: fabricanteOleoSelecionado,
      hint: new Text('Select One'),
      searchHint: new Text(
        'Select One',
        style: new TextStyle(fontSize: 20),
      ),
      onChanged: (FabricanteOleo value) {
        setState(() {
          this.fabricanteOleoSelecionado = value;
        });
      },
      displayClearButton: true,
      selectedValueWidgetFn: (value) =>
          Padding(
              padding: EdgeInsets.fromLTRB(20, 20, 20, 20),
              child:
              Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    value==null?SizedBox.shrink():Text(
                      "Oil maker",
                      style: TextStyle(
                        height: 1.5,
                        fontSize: 10,
                        color: Colors.blueAccent,
                      ),
                    ),
                    Text(
                      value!=null?value.toString():"Select oil maker",
                      style: value!=null?null:TextStyle(
                        color: Theme.of(context).hintColor,
                      ),
                    ),
                    value!=null?SizedBox.shrink():Text(
                      "Mandatory",
                      style: TextStyle(
                        height: 1.5,
                        fontSize: 10,
                        color: Colors.red,
                        decoration: TextDecoration.overline,
                        decorationColor: Colors.red,
                      ),
                    ),
                  ]
              )
          ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Searchable Dropdown Demo'),
        ),
        resizeToAvoidBottomPadding: false,
        body: Padding(
          padding: const EdgeInsets.all(15.0),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.center,
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              _dropSearch(),
            ],
          ),
        ),
      ),
    );
  }
}
PrismaSoftGC commented 4 years ago

Ok, thankyou. When will this new version be released? how can i have access to it?

lcuis commented 4 years ago

This version selectedValueWidgetFn was released 3 days ago. You should have access already by updating your plugins. Please let us know if this is not the case. By the way, I am currently working on a version making it easier to have a label, a validator and a defined keyboard.

PrismaSoftGC commented 4 years ago

Unfortunately I don't have access to the newest features. I have the version ^ 1.1.0 When you can make the current version available on pub.dev or else the new one you are working on. I look forward to using this plugin. Thanks

lcuis commented 4 years ago

Indeed, the package is not deployed to pub.dev . Thanks for letting us know. Until then, if you want, you can use the following in your pubspec.yaml to get the latest version of the plugin:

  searchable_dropdown:
    git:
      url: https://github.com/icemanbsi/searchable_dropdown.git
PrismaSoftGC commented 4 years ago

thank you so much.

lcuis commented 4 years ago

You're welcome @PrismaSoftGC !

Just so you know, I am preparing the next pull request PR #11 with the following.

Label and error returned by function as Widget:

      validator: (value){return(value==null?Row(
        children: <Widget>[
          Icon(Icons.error,color: Colors.red,size: 14,),
          SizedBox(width: 5,),
          Text("Mandatory",style: TextStyle(color: Colors.red,fontSize: 13),),
        ],
      ):null);},
      label: (value){return(Row(
        children: <Widget>[
          Icon(Icons.info,color: Colors.blueAccent,size: 14,),
          SizedBox(width: 5,),
          Text("Oil producer",style: TextStyle(color: Colors.blueAccent,fontSize: 13),),
        ],
      ));},

image Or as strings:

      validator: (value){return(value==null?"Mandatory":null);},
      label: (value){return("Oil producer");},

image

Possibility to set the keyboard type for searches as follows:

keyboardType: TextInputType.number,

image

PrismaSoftGC commented 4 years ago

Top. incredible you work.

lcuis commented 4 years ago

Thanks @PrismaSoftGC !

PrismaSoftGC commented 4 years ago

When the pull request is approved, please let me know, as I believe this latest version is better.

lcuis commented 4 years ago

Sure, I will let you know.

lcuis commented 4 years ago

Hello @PrismaSoftGC , A merge request with the described features has been approved.

PrismaSoftGC commented 4 years ago

ok, very nice, thankyou