import 'package:flutter/foundation.dart';
import 'package:clubinn/services/network_helper.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
String userToJson(Models data) => json.encode(data.toJson());
class Models {
String url = 'http://localhost:3000';
String name;
String email;
String password;
LocationJson location;
String DOB;
String gender;
String mobile;
String type;
List<double> coordinates;
Models(
{
@required this.email,
@required this.password,
}
);
Future<http.Response> loginDataToJson() async{
Map body = {
"email": email,
"password": password
};
NetworkHelper networkHelper = new NetworkHelper(
'$url/user/login',
);
http.Response response = await networkHelper.postData(body);
//dynamic decodedData = jsonDecode(response.body);
return response;
}
Models.signUp(
{
@required this.name,
@required this.email,
@required this.password,
@required this.location,
@required this.DOB,
@required this.gender,
@required this.mobile
}
);
Future<http.Response> createUser() async{
Map<String, dynamic> body = {
"name": name,
"email": email,
"password": password,
"birthday": DOB,
"gender": gender,
"location": location.toJson(),
"phone_number": mobile
};
NetworkHelper networkHelper = new NetworkHelper(
'$url/user/signup',
);
http.Response response = await networkHelper.postData(body);
return response;
}
}
class LocationJson {
String type;
List<double> coordinates;
LocationJson({
this.type,
this.coordinates,
});
Map<String,dynamic> toJson() => {
"type": type,
"coordinates": List<double>.from(coordinates.map((x) => x)),
};
}
下面给出了注册页面的代码。
class _SignUpPageState extends State<SignUpPage> {
final dateFormat = DateFormat('MM-dd-yyyy');
String name;
String email;
String DOB;
String password;
String mobileNumber;
List<double> coordinates = [];
Location location = Location();
List<String> genderList = ['Male', 'Female', 'Others'];
String selectedGender = 'Male';
var locationTextController = new TextEditingController();
DropdownButton<String> androidDropdown() {
List<DropdownMenuItem<String>> genderDropdown = [];
for(String gender in genderList) {
var newItem = DropdownMenuItem(
child: Text(
gender,
style: TextStyle(
fontFamily: 'Montserrat',
fontWeight: FontWeight.bold,
color: Color(0xFFDDB911),
),
),
value: gender,
);
genderDropdown.add(newItem);
}
return DropdownButton<String>(
value: selectedGender,
items: genderDropdown,
onChanged: (value) {
selectedGender = value;
},
);
}
CupertinoPicker iOSPicker() {
List<Text> pickerItems = [];
for(String gender in genderList) {
pickerItems.add(
Text(
gender,
style: TextStyle(
fontFamily: 'Montserrat',
fontWeight: FontWeight.bold,
color: Color(0xFFDDB911),
),
),
);
}
return CupertinoPicker(
backgroundColor: Color(0xFF101010),
itemExtent: 32.0,
onSelectedItemChanged: (selectedIndex) {
selectedGender = genderList[selectedIndex];
},
children: pickerItems,
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
SizedBox(height: 5.0),
Align(
alignment: Alignment.topLeft,
child: FlatButton(
onPressed: () {
Navigator.pop(context);
},
child: Icon(
Icons.arrow_back_ios,
size: 50.0,
color: Color(0xFFDDB911),
),
),
),
Container(
padding: EdgeInsets.only(top: 50.0, left: 20.0, right: 20.0),
child: Column(
children: <Widget>[
TextField(
onChanged: (value) {
name = value;
},
decoration: InputDecoration(
labelText: 'NAME',
labelStyle: TextStyle(
fontFamily: 'Montserrat',
fontWeight: FontWeight.bold,
color: Colors.grey,
),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Color(0xFFDDB911)),
),
),
),
SizedBox(height: kSizedBoxHeight),
TextField(
onChanged: (value) {
email = value;
},
decoration: InputDecoration(
labelText: 'EMAIL',
labelStyle: TextStyle(
fontFamily: 'Montserrat',
fontWeight: FontWeight.bold,
color: Colors.grey,
),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Color(0xFFDDB911)),
),
),
),
SizedBox(height: kSizedBoxHeight),
TextField(
onChanged: (value) {
password = value;
},
decoration: InputDecoration(
labelText: 'PASSWORD',
labelStyle: TextStyle(
fontFamily: 'Montserrat',
fontWeight: FontWeight.bold,
color: Colors.grey,
),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Color(0xFFDDB911)),
),
),
obscureText: true,
),
SizedBox(height: kSizedBoxHeight),
TextField(
onChanged: (value) {
mobileNumber = value;
},
decoration: InputDecoration(
labelText: 'MOBILE NUMBER',
labelStyle: TextStyle(
fontFamily: 'Montserrat',
fontWeight: FontWeight.bold,
color: Colors.grey,
),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Color(0xFFDDB911)),
),
),
),
SizedBox(height: kSizedBoxHeight),
Row(
children: <Widget>[
Expanded(
flex: 6,
child: TextField(
controller: locationTextController,
decoration: InputDecoration(
labelText: 'ADDRESS',
labelStyle: TextStyle(
fontFamily: 'Montserrat',
fontWeight: FontWeight.bold,
color: Colors.grey,
),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Color(0xFFDDB911)),
),
),
),
),
SizedBox(width: 15.0),
Expanded(
flex: 1,
child: GestureDetector(
onTap: () async {
await location.getCurrentLocation();
coordinates = [location.latitude, location.longitude];
setState(() {
locationTextController.text = 'Lat: ${location.latitude}, Long: ${location.longitude}';
});
},
child: Shimmer.fromColors(
baseColor: Color(0xFFDDB911),
highlightColor: Color(0xFFFFFF99),
child: Icon(
Icons.my_location,
size: 50.0,
//color: Color(0xFFDDB911),
),
),
),
),
],
),
SizedBox(height: kSizedBoxHeight),
DateTimeField(
onChanged: (value) {
var currentDate = DateTime.now();
if(value == null) {
value = DateTime.now();
} else if(currentDate.difference(value).inDays < 6575) {
} else {
String dateWithTime = value.toString();
DOB = convertDateTimeDisplay(dateWithTime);
//print(DOB);
}
},
format: dateFormat,
decoration: InputDecoration(
labelText: 'DOB',
labelStyle: TextStyle(
fontFamily: 'Montserrat',
fontWeight: FontWeight.bold,
color: Colors.grey,
),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Color(0xFFDDB911)),
),
),
onShowPicker: (context, currentValue) {
return showDatePicker(
context: context,
firstDate: DateTime(1900),
initialDate: currentValue ?? DateTime.now(),
lastDate: DateTime.now()
);
},
),
SizedBox(height: 36.0),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'GENDER',
style: TextStyle(
fontFamily: 'Montserrat',
fontWeight: FontWeight.bold,
fontSize: 16.0,
color: Colors.grey,
),
),
Container(
height: 40.0,
alignment: Alignment.center,
color: Color(0xFF101010),
child: Platform.isIOS ? iOSPicker() : androidDropdown(),
),
],
),
SizedBox(height: 40.0),
Container(
height: 50.0,
child: GestureDetector(
onTap: () async {
Models userData = new Models.signUp(
name: name,
email: email,
password: password,
location: LocationJson(type: 'Point', coordinates: coordinates),
DOB: DOB,
gender: selectedGender,
mobile: mobileNumber
);
http.Response response = await userData.createUser();
print(response);
},
child: Material(
borderRadius: BorderRadius.circular(20.0),
shadowColor: Color(0xFFFFFF99),
color: Color(0xFFDDB911),
elevation: 7.0,
child: Center(
child: Text(
'SIGNUP',
style: TextStyle(
color: Color(0xFFEFEFEF),
fontSize: 17.0,
fontWeight: FontWeight.bold,
fontFamily: 'Montserrat'
),
),
),
),
),
),
],
),
),
],
),
),
),
);
}
}
我试图创建一个注册模型并将其发送到我的API中 但 "位置 "键有另一个mapjsonobject,包含一个 "类型": "point "和 "coordinates": [双,双]。
最终的json对象应该是这样的
{
"name": "Arsh Bansal",
"email": "[email protected]",
"password": "123456789",
"birthday": "06-21-2000",
"gender": "Male",
"location": {
"type": "Point",
"coordinates": [13.0987, 88.403]
},
"phone_number": "123456789"
}
网络助手代码如下。
import 'package:http/http.dart' as http;
import 'dart:convert';
class NetworkHelper {
NetworkHelper(this.url);
NetworkHelper.withHeader(this.url, this.headers);
final String url;
Map<String, String> headers;
Future getData() async {
http.Response response = await http.get(url);
if(response.statusCode == 200) {
String data = response.body;
return jsonDecode(data);
} else {
String error = response.body;
}
}
Future<http.Response> postData(Map body) async {
http.Response response = await http.post(url, headers: headers, body: body);
return response;
}
}
但我得到了以下的错误信息
我得到的错误是:Unhandled Exception: type '_InternalLinkedHashMap>' is not a subtype of type 'String' in type cast----------。
#0 CastMap.forEach.<anonymous closure> (dart:_internal/cast.dart:288:25)
#1 _LinkedHashMapMixin.forEach (dart:collection-patch/compact_hash.dart:379:8)
#2 CastMap.forEach (dart:_internal/cast.dart:287:13)
#3 mapToQuery (package:http/src/utils.dart:17:7)
#4 Request.bodyFields= (package:http/src/request.dart:137:12)
#5 BaseClient._sendUnstreamed (package:http/src/base_client.dart:170:17)
#6 BaseClient.post (package:http/src/base_client.dart:58:7)
#7 post.<anonymous closure> (package:http/http.dart:70:16)
#8 _withClient (package:http/http.dart:166:20)
#9 post (package:http/http.dart:69:5)
#10 NetworkHelper.postData (package:clubinn/services/network_helper.dart:28:36)
#11 Models.createUser (package:clubinn/models/models.dart:72:50)
#12 _SignUpPageState.build.<anonymous closure> (package:clubinn/sc<…>
你的问题是使用了 http.post
和 body
参数。如果你阅读文档可以看到它的描述是。
body设置请求的主体。它可以是一个String,一个List或者一个Map。如果是一个字符串,就会使用编码并作为请求的主体。请求的内容类型将默认为 "textplain"。
...
如果body是Map,则使用编码将其编码为表单字段。请求的内容类型将被设置为 "applicationx-www-form-urlencoded",不能被覆盖。
https:/pub.devdocumentationhttplatesthttppost.html)。
输入 body
你所给的是来自于下面的代码。
Map<String, dynamic> body = {
"name": name,
"email": email,
"password": password,
"birthday": DOB,
"gender": gender,
"location": location.toJson(),
"phone_number": mobile
};
其中的类型都是不差钱的 Map<String, String>
由于例如位置都被赋予了 Map<String, dynamic>
作为价值。
Map<String,dynamic> toJson() => {
"type": type,
"coordinates": List<double>.from(coordinates.map((x) => x)),
};
而且,我认为你不想给... ... body
的地图。在之前提到的文档中可以看到,地图是 "使用编码作为表单字段进行编码的"。你正确的做法是将地图解析成一个JSON字符串,并将这个字符串作为主体给到 http.post
.
所以正确的做法应该是这样的。
http.Response response = await http.post(url, headers: headers, body: json.encode(body));