简体   繁体   English

Flutter CRUD model 与供应商

[英]Flutter CRUD model with provider

I'm learning Flutter with Provider and trying to make a CRUD model.我正在使用 Provider 学习 Flutter 并尝试制作 CRUD model。 I've achieved the create part, read and the delete part, but struggling with the update part of the model.我已经完成了创建部分、读取部分和删除部分,但在 model 的更新部分中遇到了困难。 I made and API call that reads and displays the data, made a method in which a new object is created and one for removing the object, but all is left is modifying/edit the object. I made and API call that reads and displays the data, made a method in which a new object is created and one for removing the object, but all is left is modifying/edit the object. Here is the code I've done so far:这是我到目前为止所做的代码:

The Vehicle list that calls the API:调用 API 的车辆列表:

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'models/vehicle.dart';
import 'screens/vehicle_details_screen.dart';
import 'services/vehicle_api.dart';
import 'models/vehicle_data_provider.dart';

class VehicleList extends StatefulWidget {
  @override
  _VehicleList createState() => _VehicleList();
}

class _VehicleList extends State<VehicleList> {

  _getPosts() async {
    var provider = Provider.of<HomePageProvider>(context, listen: false);

    var postsResponse = await fetchVehicles();
    if (postsResponse.isSuccessful) {
      provider.setPostsList(postsResponse.data, notify: false);
    } else {
      provider.mergePostsList(postsResponse.data, notify: false);
    }

    provider.setIsHomePageProcessing(false);
  }

  @override
  void initState() {
    super.initState();

    _getPosts();
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Consumer<HomePageProvider>(
          builder: (context, vehicleData, child) {
            return Column(
              crossAxisAlignment: CrossAxisAlignment.center,
              mainAxisAlignment: MainAxisAlignment.spaceAround,
              children: [
                SizedBox(
                  height: 12.0,
                ),
                Container(
                  decoration: BoxDecoration(
                    color: Colors.grey[300],
                    borderRadius: BorderRadius.all(
                      Radius.circular(12.0),
                    ),
                  ),
                  child: SingleChildScrollView(
                    child: DataTable(
                      columnSpacing: 50,
                      columns: <DataColumn>[
                        DataColumn(
                          label: Text(
                            'Friendly Name',
                            style: TextStyle(fontStyle: FontStyle.italic),
                          ),
                        ),
                        DataColumn(
                          label: Text(
                            'Licence Plate',
                            style: TextStyle(fontStyle: FontStyle.italic),
                          ),
                        ),
                        DataColumn(
                          label: Text(
                            'Delete',
                            style: TextStyle(fontStyle: FontStyle.italic),
                          ),
                        ),
                      ],
                      rows: List.generate(
                        vehicleData.postsList.length,
                        (index) {
                          VehicleData post = vehicleData.getPostByIndex(index);
                          return DataRow(
                            cells: <DataCell>[
                              DataCell(
                                Text('${post.friendlyName}'),
                                onTap: () {
                                  Navigator.push(
                                      context,
                                      MaterialPageRoute(
                                          builder: (context) =>
                                              VehicleDetailsScreen(
                                                color: post.color,
                                                friendlyName: post.friendlyName,
                                                licencePlate: post.licencePlate,
                                              )));
                                },
                              ),
                              DataCell(
                                Text('${post.licencePlate}'),
                              ),
                              DataCell(
                                IconButton(
                                  icon: Icon(Icons.delete),
                                  onPressed: () {
                                    vehicleData.deletePost(post);
                                  },
                                ),
                                // onTap: vehicleData.deletePost(post),
                              ),
                            ],
                          );
                        },
                      ),
                    ),
                  ),
                ),
              ],
            );
          },
        ),
      ],
    );
  }
}

The vehicle details screen车辆详情画面

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'models/vehicle.dart';
import 'models/vehicle_data_provider.dart';

class VehicleDetailsScreen extends StatefulWidget {
  static const String id = 'vehicle_details_screen';
  final vehicleList;
  String color, friendlyName, licencePlate;
  VehicleDetailsScreen(
      {this.vehicleList, this.color, this.friendlyName, this.licencePlate});
  @override
  _VehicleDetailsScreenState createState() => _VehicleDetailsScreenState();
}

class _VehicleDetailsScreenState extends State<VehicleDetailsScreen> {
  final GlobalKey<FormState> _formKey = new GlobalKey<FormState>();
  String color, friendlyName, licencePlate;
  final TextEditingController _controllerfriendlyName = TextEditingController();
  final TextEditingController _controllerlicencePlate = TextEditingController();
  final TextEditingController _controllerColor = TextEditingController();

  @override
  void initState() {
    super.initState();
    setState(() {
      _controllerColor.text = widget.color;
      _controllerfriendlyName.text = widget.friendlyName;
      _controllerlicencePlate.text = widget.licencePlate;
    });
  }

  @override
  void dispose() {
    _controllerColor.dispose();
    _controllerfriendlyName.dispose();
    _controllerlicencePlate.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final myProvider = Provider.of<HomePageProvider>(context);
    return Scaffold(
      body: Container(
        width: MediaQuery.of(context).size.width,
        height: MediaQuery.of(context).size.height,
        color: Colors.white,
        child: Container(
          padding: EdgeInsets.all(20.0),
          decoration: BoxDecoration(
            color: Colors.white,
            borderRadius: BorderRadius.only(
              topLeft: Radius.circular(20.0),
              topRight: Radius.circular(20.0),
            ),
          ),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.center,
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text(
                'Vehicle Details',
                textAlign: TextAlign.center,
                style: TextStyle(
                  fontSize: 30.0,
                  color: Colors.grey,
                ),
              ),
              Container(
                width: MediaQuery.of(context).size.width,
                height: MediaQuery.of(context).size.height - 400,
                child: Form(
                  key: _formKey,
                  child: new ListView(
                    shrinkWrap: true,
                    padding: const EdgeInsets.symmetric(horizontal: 16.0),
                    children: <Widget>[
                      TextFormField(
                        validator: (value) {
                          if (value.isEmpty) {
                            return 'Please enter friendly name';
                          }
                          return null;
                        },
                        controller: _controllerColor,
                        onSaved: (value) {
                          color = value;
                        },
                        decoration: const InputDecoration(
                          icon: Icon(Icons.directions_car),
                          hintText: 'Enter friendly car name',
                          labelText: 'Name',
                        ),
                        keyboardType: TextInputType.datetime,
                      ),
                      TextFormField(
                        onSaved: (value) {
                          friendlyName = value;
                        },
                        controller: _controllerfriendlyName,
                        validator: (value) {
                          if (value.isEmpty) {
                            return 'Please enter vehicle model';
                          }
                          return null;
                        },
                        decoration: const InputDecoration(
                          icon: Icon(Icons.directions_car_outlined),
                          hintText: 'Enter vehicle model',
                          labelText: 'Model',
                        ),
                        keyboardType: TextInputType.phone,
                      ),
                      TextFormField(
                        validator: (value) {
                          if (value.isEmpty) {
                            return 'Please enter some text';
                          }
                          return null;
                        },
                        controller: _controllerlicencePlate,
                        onSaved: (value) {
                          licencePlate = value;
                        },
                        decoration: const InputDecoration(
                          icon: Icon(Icons.calendar_today),
                          hintText: 'Enter manufactured year',
                          labelText: 'Year',
                        ),
                        keyboardType: TextInputType.emailAddress,
                      ),
                    ],
                  ),
                ),
              ),
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  FlatButton(
                    child: Text(
                      'Cancel',
                      style: TextStyle(
                        color: Colors.white,
                      ),
                    ),
                    color: Colors.grey,
                    onPressed: () {
                      Navigator.pop(context);
                    },
                  ),
                  SizedBox(
                    width: 10,
                  ),
                  FlatButton(
                    child: Text(
                      'Edit',
                      style: TextStyle(
                        color: Colors.white,
                      ),
                    ),
                    color: Colors.grey,
                    onPressed: () async {
                      if (_formKey.currentState.validate()) {
                        _formKey.currentState.save();
////The method bellow updateList ()needs to be changed in order to modify the existing list, this method just creates a new one.
                        await myProvider.updateList(VehicleData(  
                          friendlyName: friendlyName.toString(),
                          color: color.toString(),
                          licencePlate: licencePlate.toString(),
                        ));
                        Navigator.of(context).pop();
                      }
                    },
                  ),
                ],
              ),
            ],
          ),
        ),
      ),
    );
  }
}

And here is the HomePageProvider model:这是 HomePageProvider model:

import 'package:flutter/foundation.dart';
import 'models/vehicle.dart';

class HomePageProvider extends ChangeNotifier {
  bool _isHomePageProcessing = true;
  int _currentPage = 1;
  String friendlyName;
  List<VehicleData> _postsList = [];
  bool _shouldRefresh = true;

  bool get shouldRefresh => _shouldRefresh;

  setShouldRefresh(bool value) => _shouldRefresh = value;

  int get currentPage => _currentPage;

  setCurrentPage(int page) {
    _currentPage = page;
  }

  bool get isHomePageProcessing => _isHomePageProcessing;

  setIsHomePageProcessing(bool value) {
    _isHomePageProcessing = value;
    notifyListeners();
  }

  List<VehicleData> get postsList => _postsList;

  setPostsList(List<VehicleData> list, {bool notify = true}) {
    _postsList = list;
    if (notify) notifyListeners();
  }
// This method needs to be changed
  updateList(VehicleData list) {
    _postsList.add(list);
    notifyListeners();
  }

  mergePostsList(List<VehicleData> list, {bool notify = true}) {
    _postsList.addAll(list);
    if (notify) notifyListeners();
  }

  deletePost(VehicleData list) {
    _postsList.remove(list);

    notifyListeners();
  }

  addPost(VehicleData post, {bool notify = true}) {
    _postsList.add(post);
    if (notify) notifyListeners();
  }

  VehicleData getPostByIndex(int index) => _postsList[index];

  int get postsListLength => _postsList.length;
}

And this would be the Vehicle Data model:这将是车辆数据 model:

class VehicleData {
  final String id,
      licencePlate,
      countryRegistered,
      type,
      color,
      vin,
      owner,
      garage,
      friendlyName,
      model,
      make,
      year,
      status,
      insuredBy,
      insurancePolicyNumber,
      policyExpirationDate,
      mobile,
      cellPhoneProvider,
      notes;
  final int capacity, co2perKm, luggageCapacity;

  VehicleData(
      {this.id,
      this.licencePlate,
      this.countryRegistered,
      this.type,
      this.color,
      this.vin,
      this.co2perKm,
      this.owner,
      this.garage,
      this.friendlyName,
      this.model,
      this.make,
      this.year,
      this.capacity,
      this.luggageCapacity,
      this.status,
      this.insuredBy,
      this.insurancePolicyNumber,
      this.policyExpirationDate,
      this.mobile,
      this.cellPhoneProvider,
      this.notes});

  factory VehicleData.fromJson(Map<String, dynamic> json) {
    return VehicleData(
      id: json['id'],
      licencePlate: json['licencePlate'],
      countryRegistered: json['countryRegistered'],
      type: json['type'],
      color: json['color'],
      vin: json['vin'],
      co2perKm: json['co2perKm'],
      owner: json['owner'],
      garage: json['garage'],
      friendlyName: json['friendlyName'],
      model: json['model'],
      make: json['make'],
      year: json['year'],
      capacity: json['capacity'],
      luggageCapacity: json['luggageCapacity'],
      status: json['status'],
      insuredBy: json['insuredBy'],
      insurancePolicyNumber: json['insurancePolicyNumber '],
      policyExpirationDate: json['policyExpirationDate '],
      mobile: json['mobile'],
      cellPhoneProvider: json['cellPhoneProvider '],
      notes: json['notes '],
    );
  }
}

And the API call: API 调用:

import 'dart:convert';
import 'package:http/http.dart';;
import 'models/vehicle.dart';

Future<HTTPResponse<List<VehicleData>>> fetchVehicles() async {
  final response =
      await get('https://run.mocky.io/v3/d7a00528-176c-402f-850e-76567de3c68d');
  if (response.statusCode == 200) {
    var body = jsonDecode(response.body)['data'];
    List<VehicleData> posts = [];
    body.forEach((e) {
      VehicleData post = VehicleData.fromJson(e);
      posts.add(post);
    });
    return HTTPResponse<List<VehicleData>>(
      true,
      posts,
      message: 'Request Successful',
      statusCode: response.statusCode,
    );
  } else {
    return HTTPResponse<List<VehicleData>>(
      false,
      null,
      message:
          'Invalid data received from the server! Please try again in a moment.',
      statusCode: response.statusCode,
    );
  }
}
class HTTPResponse<T> {
  bool isSuccessful;
  T data;
  int statusCode;
  String message;
  HTTPResponse(this.isSuccessful, this.data, {this.message, this.statusCode});
}

Main:主要的:

import 'package:flutter/material.dart';
import 'components/vehicle_list.dart';
import 'screens/settings_screen.dart';
import 'package:provider/provider.dart';
import 'models/vehicle_data_provider.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        ChangeNotifierProvider<HomePageProvider>(
            create: (_) => HomePageProvider()),
        ChangeNotifierProvider<AppLocale>(create: (_) => AppLocale()),
      ],
      child: Consumer<AppLocale>(builder: (context, locale, child) {
        return MaterialApp(
          home: VehicleList(),
        );
      }),
    );
  }
}

Like I said, I just need to update(edit) the existing data, which've passed from the one screen to another.就像我说的,我只需要更新(编辑)从一个屏幕传递到另一个屏幕的现有数据。 Can someone explain to me what am I doing wrong when it comes to updating the data.有人可以向我解释在更新数据时我做错了什么。 I understand the updateList() method is exactly the same as the addNew oneis not working but I can't seem to find the solution.我了解updateList()方法与 addNew 方法完全相同,但我似乎找不到解决方案。

Ok.好的。 So, I think I got it.所以,我想我明白了。 The problem might be because you have two separate data sources.问题可能是因为您有两个单独的数据源。 One is the API and the other is the HomePageProvider class.一个是 API,另一个是HomePageProvider class。 Now, what you're doing is that you're collecting data from the API and putting it in the HomePageProvider class.现在,您正在做的是从 API 收集数据并将其放入HomePageProvider class。 But every time the VehicleList() widget is called, the data is refreshed from the API.但是每次调用VehicleList()小部件时,都会从 API 刷新数据。 So, if you make any changes to your data in the HomePageProvider class, it will be overwritten by the data that comes from the API.因此,如果您对HomePageProvider class 中的数据进行任何更改,它将被来自 API 的数据覆盖。

I would suggest you collect all the data in the HomePageProvider class itself and then call the API if and only if your _postsList variable has no data.我建议您收集HomePageProvider class 本身中的所有数据,然后当且仅当您的_postsList变量没有数据时才调用 API。 Or determine some other measure to know if you should call the API or not.或者确定一些其他措施来了解您是否应该调用 API。 I would suggest using a Set instead of a List , if your data contains only unique values.如果您的数据仅包含唯一值,我建议使用Set而不是List It will help you avoid some unnecessary code.它将帮助您避免一些不必要的代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM