Registering User using Flutter and PHP Laravel and saving User info with SharedPreferrence - flutter

I am trying to save result from json to SharedPreferrence but i keep getting Unhandled Exception: type 'String' is not a subtype of type 'int' of 'index'
This is my Code
_register(BuildContext context, User user) async {
var _userService = UserService();
var registeredUser = await _userService.createUser(user);
var encodeFirst = json.encode(registeredUser.body);
var result = json.decode(encodeFirst);
if(result['result'] == true){
SharedPreferences _prefs = await SharedPreferences.getInstance();
_prefs.setInt("userId", result["user"]["id"]);
_prefs.setString("userName", result["user"]["name"]);
_prefs.setString("userEmail", result["user"]["email"]);
Navigator.push(
context, MaterialPageRoute(builder: (context) => CheckoutScreen(cartItems: this.widget.cartItems,)));
} else {
_showSnackMessage(Text('Failed to register the user!', style: TextStyle(color: Colors.red),));
}
}
this is my User, UserService and Repository file
class User{
int id;
String name;
String email;
String password;
toJson(){
return{
'id': id.toString(),
'name': name,
'email': email,
'password': password
};
}
}
class UserService {
Repository _repository;
UserService(){
_repository = Repository();
}
createUser(User user) async{
return await _repository.httpPost('register', user.toJson());
}
}
httpPost(String api, data) async {
return await http.post(_baseUrl + "/" + api, body: data);
}

var encodeFirst = json.encode(registeredUser.body); will call User toJson()
And in toJson() , you have set 'id': id.toString(),
when you do var result = json.decode(encodeFirst);
It's actually a string not int
Correct toJson() please see below
// To parse this JSON data, do
//
// final user = userFromJson(jsonString);
import 'dart:convert';
User userFromJson(String str) => User.fromJson(json.decode(str));
String userToJson(User data) => json.encode(data.toJson());
class User {
int id;
String name;
String email;
String password;
User({
this.id,
this.name,
this.email,
this.password,
});
factory User.fromJson(Map<String, dynamic> json) => User(
id: json["id"],
name: json["name"],
email: json["email"],
password: json["password"],
);
Map<String, dynamic> toJson() => {
"id": id,
"name": name,
"email": email,
"password": password,
};
}

Related

How to get a first single data from firestore as a string in flutter

I want to query users data as stored in firestore then use it anywhere across the app by simply calling the function or getter.
Trying to implement it,
This is my Controller.
Future<Member?> readMember(mid) async {
final docMember =
FirebaseFirestore.instance.collection('users').doc(mid.toString());
final snapshot = await docMember.get();
if (snapshot.exists) {
return Member.fromJson(snapshot.data()!);
} else {
return null;
}
}
This is my model
class Member {
String id;
final String? name;
int? age;
final String? gender;
final String? username;
int? sponsor;
int? phoneNumber;
DateTime? birthday;
Member({
this.id = '',
this.name,
this.age,
this.gender,
this.username,
this.sponsor,
this.phoneNumber,
this.birthday,
});
Map<String, dynamic> toJson() => {
'id': id,
'name': name,
'age': age,
'gender': gender,
'username': username,
'sponsor': sponsor,
'phoneNumber': phoneNumber,
'birthday': birthday,
};
static Member fromJson(Map<String, dynamic> json) => Member(
id: json['id'],
name: json['name'],
age: json['age'],
gender: json['gender'],
username: json['username'],
sponsor: json['sponsor'],
phoneNumber: json['phoneNumber'],
birthday: (json['birthday'] as Timestamp).toDate(),
);
}
Then in my view I want to easily call any of the user data from the firestore.
I tried this
FutureBuilder<Member>? mems() {
future:
readLoggedMember(user?.uid);
builder:
(context, snapshot) {
if (snapshot.hasError) {
return const Text("Got Error");
}
if (snapshot.hasData) {
final member = snapshot.data;
return member;
}
};
return null;
}
then assign it to widget like this
Widget _userUid() {
return Text(mems?.name ?? 'User name');
}
I have tried but seems not working. please I need a help on how to do this.

Why is GetConnect/GetX/Flutter not calling my backend and returning a null object?

I'm using get: 4.6.5
I have defined a provider
class CredentialsProvider extends GetConnect implements GetxService {
#override
void onInit() {
httpClient.defaultDecoder =
(val) => Auth.fromJson(val as Map<String, dynamic>);
httpClient.baseUrl = 'http://localhost:1337/api/';
super.onInit();
}
Future<Response<dynamic>> postCredentials(Credentials credentials) async {
return await post('auth/local', credentials);
}
}
In my binding class add it as a dependency
class LoginBinding extends Bindings {
#override
void dependencies() {
Get.lazyPut(() => CredentialsProvider());
Get.lazyPut(() => LoginController());
}
}
And register the LoginView as a route
GetPage(
name: "/login",
page: () => const LoginView(),
binding: LoginBinding(),
)
And added it to my controller
class LoginController extends GetxController {
final provider = Get.put(CredentialsProvider());
//...
}
The controller is used in my LoginView
class LoginView extends GetView<LoginController> {...}
In my MaterialButton of the LoginView I use the onPressed to call the provider and get the result object Auth and print it out as json.
onPressed: () {
var c = Credentials(
identifier: controller.emailController.text,
password: controller.passwordController.text);
controller.provider.postCredentials(c).then((value) {
var auth = value.body as Auth;
print(auth.toJson());
});
},
I generated my Auth model from JSON using the GetX cli:
class Auth {
String? jwt;
User? user;
Auth({this.jwt, this.user});
Auth.fromJson(Map<String, dynamic> json) {
jwt = json['jwt'];
user = json['user'] != null ? User?.fromJson(json['user']) : null;
}
Map<String, dynamic> toJson() {
final data = <String, dynamic>{};
data['jwt'] = jwt;
if (user != null) {
data['user'] = user?.toJson();
}
return data;
}
}
class User {
int? id;
String? username;
String? email;
String? provider;
bool? confirmed;
bool? blocked;
String? createdAt;
String? updatedAt;
User(
{this.id,
this.username,
this.email,
this.provider,
this.confirmed,
this.blocked,
this.createdAt,
this.updatedAt});
User.fromJson(Map<String, dynamic> json) {
id = json['id'];
username = json['username'];
email = json['email'];
provider = json['provider'];
confirmed = json['confirmed'];
blocked = json['blocked'];
createdAt = json['createdAt'];
updatedAt = json['updatedAt'];
}
Map<String, dynamic> toJson() {
final data = <String, dynamic>{};
data['id'] = id;
data['username'] = username;
data['email'] = email;
data['provider'] = provider;
data['confirmed'] = confirmed;
data['blocked'] = blocked;
data['createdAt'] = createdAt;
data['updatedAt'] = updatedAt;
return data;
}
}
What I get in the console is
flutter: {jwt: null}
And my localhost service is never called.
The issue was with the decoder for the request being different that for the response. So I ended up with something like this:
Future<Auth> postCredentials(Map<String, dynamic> body) async {
var response = await post(
contentType: 'application/json',
decoder: (val) => Auth.fromJson(val as Map<String, dynamic>),
"/api/auth/local",
body);
return response.body as Auth;
}
And I call this via
controller.provider.postCredentials(credentials.toJson());

how to add map data to cloud firestore in flutter?

I want to add the name of the user as a map containing 'firstName' and 'lastName'. I already have the user model and the name model, here is the code:
name_model.dart
class Name {
final String firstName;
final String lastName;
Name({
required this.firstName,
required this.lastName,
});
Map<String, dynamic> toMap() {
return {
'firstName': firstName,
'lastName': lastName,
};
}
Name.fromMap(Map<String, dynamic> nameMap)
: firstName = nameMap['firstName'],
lastName = nameMap['lastName'];
}
user_model.dart
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:ukk_backup/models/name_model.dart';
class User {
final String? docId;
final String email;
final String password;
final String phoneNumber;
final Name name;
User({
this.docId,
required this.email,
required this.password,
required this.phoneNumber,
required this.name,
});
Map<String, dynamic> toMap() => {
'docId': docId,
'email': email,
'password': password,
'phoneNumber': phoneNumber,
'name': name.toMap(),
};
User.fromDocumentSnapshot(DocumentSnapshot<Map<String, dynamic>> doc)
: docId = doc.id,
email = doc['email'],
password = doc['password'],
phoneNumber = doc['phoneNumber'],
name = Name.fromMap(doc['name']);
}
when I pressed the register button I want all the data to be saved in cloud firestore, including the name with the map type. This is the onPressed:
onPressed: (() async {
if (_formKey.currentState!.validate()) {
DatabaseService service = DatabaseService();
User user = User(
email: emailController.text,
password: passwordController.text,
phoneNumber: phoneNumberController.text,
name: , //what to type?
);
setState(() {
_isLoading = true;
});
await service.addUser(user);
setState(() {
_isLoading = false;
});
}
}),
If you found some of my code is not correct or you found the solution, please tell me. Thank you.
Edit:
database_services.dart
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:ukk_backup/models/user_model.dart';
class DatabaseService {
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
addUser(User userData) async {
await _firestore.collection('users').add(userData.toMap());
}
updateUser(User userData) async {
await _firestore
.collection('users')
.doc(userData.docId)
.update(userData.toMap());
}
Future<void> deleteUser(String documentId) async {
await _firestore.collection('users').doc(documentId).delete();
}
Future<List<User>> retrieveUser() async {
QuerySnapshot<Map<String, dynamic>> snapshot =
await _firestore.collection('users').get();
return snapshot.docs
.map((docSnapshot) => User.fromDocumentSnapshot(docSnapshot))
.toList();
}
}
I misunderstood your question first. Your DataBaseService class looks ok to me. So if I am right the only problem you have is that you do not know how to add the name to the UserObject. If that's the essence of your question then that is very easy:
onPressed: (() async {
if (_formKey.currentState!.validate()) {
DatabaseService service = DatabaseService();
User user = User(
email: emailController.text,
password: passwordController.text,
phoneNumber: phoneNumberController.text,
name: Name(firstName: firstNameController.text, lastName: lastNameController.text),
);
setState(() {
_isLoading = true;
});
await service.addUser(user);
setState(() {
_isLoading = false;
});
}
}),

Save nested objects in shared preferences

I have an object that contains a json array , which am trying to store in shared preferences but i don't know how to do so .
This is my model :
import 'dart:convert';
import 'package:deepnrise/models/settings/perimeter.dart';
import 'package:deepnrise/models/user/user_perims.dart';
UserWithPerim user(String str) => UserWithPerim.fromJson(json.decode(str));
class UserWithPerim {
// ignore: non_constant_identifier_names
UserWithPerim({
required this.identifier,
required this.firstName,
required this.lastName,
required this.email,
required this.role,
required this.perimeters,
});
String identifier;
String firstName;
String lastName;
String email;
String role;
List<UserPerimeter> perimeters;
factory UserWithPerim.fromJson(Map<String, dynamic> json) {
return UserWithPerim(
identifier: json['identifier'] ?? "",
firstName: json['firstName'] ?? "",
lastName: json['lastName'] ?? "",
email: json['email'] ?? "",
role: json['role'] ?? "",
perimeters: (json['perimeters'] as List)
.map((p) => UserPerimeter.fromJson(p))
.toList(),
);
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['identifier'] = identifier;
data['firstName'] = firstName;
data['lastName'] = lastName;
data['role'] = role;
data['email'] = email;
data['perimeters'] = perimeters;
return data;
}
}
This the perimeters model :
import 'dart:convert';
Userperimeters(String str) => UserPerimeter.fromJson(json.decode(str));
String UserPerimToJson(UserPerimeter data) => json.encode(data.tojson());
class UserPerimeter {
// ignore: non_constant_identifier_names
UserPerimeter(
{required this.id, required this.label, required this.perimeterId});
// ignore: non_constant_identifier_names
int id;
String label;
int perimeterId;
factory UserPerimeter.fromJson(Map<String, dynamic> json) {
return UserPerimeter(
id: json['id'] ?? "",
label: json['label'] ?? "",
perimeterId: json["perimeterId"] ?? "");
}
Map<String, dynamic> tojson() => {
"id": id,
"label": label,
"perimeterId": perimeterId,
};
}
For now I've two models of my user object , one that contains the perils list and one that doesn't because whenever I try to store my user in shared prefs I get this exception thrown :
Unhandled Exception: type 'UserPerimeter' is not a subtype of type 'Map<String, dynamic>'
This is how am saving and reading my user:
saveUser(value) async {
final prefs = await SharedPreferences.getInstance();
String user = jsonEncode(User.fromJson(value));
prefs.setString(Preferences.USER_KEY, user);
}
Future<User?> getUser() async {
final prefs = await SharedPreferences.getInstance();
if (prefs.containsKey(Preferences.USER_KEY)) {
Map<String, dynamic> userMap =
jsonDecode(prefs.getString(Preferences.USER_KEY) ?? "");
User user = User.fromJson(userMap);
return user;
}
}
Is there a way with which I can store the whole user model with the perils object list without making two models of the user object ? thank you so much in advance.
The work around here to convert your whole json response to string.
save that string into sharedprefs, then you can call it back and decode it using:
var response = json.decode(prefs.getString("response");
So, the full idea:
prefs.setString("response",json.encode(response.body));
using that String as json format again:
MyModel model = MyModel.fromJson(json.decode(prefs.getString("response")));
I hope you find what you need from this idea.
Convert the list of perimeters to list of Json like this:
if (this.perimeters != null) {
data['perimeters'] = this.perimeters!.map((v) => v.toJson()).toList();
}

Unhandled Exception: Converting object to an encodable object failed: Instance of 'LoginModel'

Am still learning and understanding the working of flutter, I am trying to save json string whenever a user logins in for the First time, and use the ID and token to call and interact with different API endpoints. Whenever I try to save the json content to Shared Preference I end with error
Unhandled Exception: Converting object to an encodable object failed:
Instance of 'LoginModel'
My LoginModel
import 'dart:convert';
LoginModel loginModelFromJson(String str) => LoginModel.fromJson(json.decode(str));
String loginModelToJson(LoginModel data) => json.encode(data.toJson());
class LoginModel {
LoginModel({
this.id,
this.username,
this.email,
this.roles,
this.userid,
this.surname,
this.firstname,
this.telephoneno,
this.whatsappno,
this.active,
this.studyrole,
this.tokenType,
this.accessToken,
});
int id;
String username;
String email;
List<String> roles;
String userid;
String surname;
String firstname;
String telephoneno;
String whatsappno;
int active;
String studyrole;
String tokenType;
String accessToken;
factory LoginModel.fromJson(Map<String, dynamic> json) => LoginModel(
id: json["id"],
username: json["username"],
email: json["email"],
roles: List<String>.from(json["roles"].map((x) => x)),
userid: json["userid"],
surname: json["surname"],
firstname: json["firstname"],
telephoneno: json["telephoneno"],
whatsappno: json["whatsappno"],
active: json["active"],
studyrole: json["studyrole"],
tokenType: json["tokenType"],
accessToken: json["accessToken"],
);
Map<String, dynamic> toJson() => {
"id": id,
"username": username,
"email": email,
"roles": List<dynamic>.from(roles.map((x) => x)),
"userid": userid,
"surname": surname,
"firstname": firstname,
"telephoneno": telephoneno,
"whatsappno": whatsappno,
"active": active,
"studyrole": studyrole,
"tokenType": tokenType,
"accessToken": accessToken,
};
}
how am trying to save the Json to shared pref when user clicks on the login button
login(username, password) async {
SharedPref sharedPref = SharedPref();
LoginModel userSave = LoginModel();
final String url = "http://21.76.45.12:80/data/api/auth/signin"; // iOS
final http.Response response = await http.post(
url,
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: jsonEncode(<String, String>{
'username': username,
'password': password,
}),
);
print(response.body);
sharedPref.save("user", userSave);
}
My Login button Widget
RoundedButton(
text: "LOGIN",
press: () async {
if (_formKey.currentState.validate()) {
progressDialog.show();
await login(
username,
password,
);
SharedPreferences prefs =
await SharedPreferences.getInstance();
String token = prefs.getString("accessToken");
loadSharedPrefs();
print(token);
// ignore: null_aware_in_condition
if (token == null) {
progressDialog.hide();
showAlertsDialog(context);
// ignore: null_aware_in_condition
} else {
progressDialog.hide();
showAlertzDialog(context);
}
}
},
),
whenever I try to load the preference I get no data
loadSharedPrefs() async {
try {
LoginModel user = LoginModel.fromJson(await sharedPref.read("user"));
Scaffold.of(context).showSnackBar(SnackBar(
content: new Text("Loaded!"),
duration: const Duration(milliseconds: 500)));
setState(() {
userLoad = user;
});
} catch (Excepetion) {
Scaffold.of(context).showSnackBar(SnackBar(
content: new Text("Nothing found!"),
duration: const Duration(milliseconds: 500)));
}
}
My SharedPref class
class SharedPref {
read(String key) async {
final prefs = await SharedPreferences.getInstance();
return json.decode(prefs.getString(key));
}
save(String key, value) async {
final prefs = await SharedPreferences.getInstance();
prefs.setString(key, json.encode(value));
}
remove(String key) async {
final prefs = await SharedPreferences.getInstance();
prefs.remove(key);
}
}
what am I doing wrong such that the JSON is not being saved to shared prefs? Thank you for the help
You are not parsing the json anywhere in your code. You are creating an empty object using:
LoginModel userSave = LoginModel();
Which contains null values for the properties and that's why you are getting those exceptions. You want to parse the json and create the object using:
LoginModel userSave = loginModelFromJson(response.body);
sharedPref.save("user", userSave);