Home > Enterprise >  load images in field of form
load images in field of form

Time:03-12

I have custom form to upload files (code below)(I shortened the code for ease of understanding).

class CustomImageFormField extends StatelessWidget {
  CustomImageFormField(
      {Key? key, required this.validator, required this.onChanged,}) : super(key: key);
  final String? Function(File?) validator;
  final Function(File) onChanged;
  File? _pickedFile;
  @override
  Widget build(BuildContext context) {
    return FormField<File>(
        validator: validator,
        builder: (formFieldState) {
          return Column(
            children: [
              GestureDetector(
                onTap: () async {
                  FilePickerResult? file = await FilePicker.platform
                      .pickFiles(type: FileType.image, allowMultiple: true);
                  if (file != null) {
                    _pickedFile = File(file.files.first.path!);
                    onChanged.call(_pickedFile!);
                  }

                },
                  ),
                
              if (formFieldState.hasError)
                Padding(
                  padding: const EdgeInsets.only(left: 8, top: 10),
                  child: Text(
                    formFieldState.errorText!,
                    style: TextStyle(
                        fontStyle: FontStyle.normal,
                        fontSize: 13,
                        color: Colors.red[700],
                        height: 0.5),
                  ),
                )
            ],
          );
        });
  }
}

And there is a class that uses CustomImageFormField with other form fields (code below).

class _FormForDeviceService extends State {
  final _formKey = GlobalKey<FormState>();

  Widget build(BuildContext context) {
    return Container(padding: const EdgeInsets.all(10.0),
        child: Form(key: _formKey, child: Column(children: <Widget>[
          
          new Text('What is problem', style: TextStyle(fontSize: 20.0),),
          new TextFormField(decoration: const InputDecoration(
            hintText: 'Describe the problem',),
              validator: (value){if (value!.isEmpty) return 'Please, describe the problem ';}),
          new SizedBox(height: 20.0),

          CustomImageFormField(
            validator: (val) {},
            onChanged: (_file) {},
          ),

          ElevatedButton(
            onPressed: (){if(_formKey.currentState!.validate()) {_formKey.currentState?.reset();
            ScaffoldMessenger.of(context).showSnackBar(
                const SnackBar(content: Text('Form completed successfully',
                  style: TextStyle(color: Colors.black),),
                  backgroundColor: Colors.yellow,));
            }},
            child: const Text('Submit', style: TextStyle(color: Colors.black),),
            style: ButtonStyle(backgroundColor: MaterialStateProperty.all(Colors.yellow)),)
        ],)));
  }
}

The app looks like this enter image description here

My problem is that I click 'Upload Image', select files, and they load immediately. But I would like:

  1. so that the name of the selected files can be displayed in the form (with the ability to delete an incorrectly selected file)
  2. and that they would be loaded only after applying the button 'Submit'

enter image description here

CodePudding user response:

You'll need to add the file.files.first.path! to a List (or better, add all picked files using images.addAll(file.files.map((file) => file.path!))). Show each item in the list with a delete button next to it and when you press delete, you remove said item from the list.

Once you press submit, you then iterate over the list using a map and call the onChanged with that list.

_pickedFiles = images.map((path) => File(path)).toList();
onChanged.call(_pickedFiles);

CodePudding user response:

First create an empty array to store your image files:

var _images = [];

When calling onTap() function, you have to call all paths instead just one:

onTap: () async {
    FilePickerResult? result = await FilePicker.platform.pickFiles(
        allowMultiple: true,
        type: FileType.image,
    );
    if (file != null) {
        for (String? path in result.paths) {
            File file = File(path!);
            _images.add(file);
        }
        // Here your onChanged() function is returning just one image
     }
 }

Then create a listview builder to show all the images:

ListView.builder(
    itemCount: _images.length,
    shrinkwrap: true, // Remove if not needed, performance improves
    itemBuilder: (_,i){
        return Image.file(
            _images[i],
            fit: BoxFit.cover,
        );
    }
);

NOTE: Improve your code format, it's easier and faster for developers to read.

  • Related