How to use deleted method in ListView builder in flutter? - flutter

I am using two apis, one is to use get method which I am using to fetch Image from server and display using ListView builder, and another api which I need to use to delete the image.
This model class is for Fetching data:
List<DisplayImageModels> displayImageModelsFromJson(String str) =>
List<DisplayImageModels>.from(
json.decode(str).map((x) => DisplayImageModels.fromJson(x)));
String displayImageModelsToJson(List<DisplayImageModels> data) =>
json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class DisplayImageModels {
DisplayImageModels({
this.id,
this.category,
this.documentImage,
this.document,
this.user,
});
int? id;
int? category;
String? documentImage;
int? document;
int? user;
factory DisplayImageModels.fromJson(Map<String, dynamic> json) =>
DisplayImageModels(
id: json["id"],
category: json["category"],
documentImage: json["document_image"],
document: json["document"],
user: json["user"],
);
Map<String, dynamic> toJson() => {
"id": id,
"category": category,
"document_image": documentImage,
"document": document,
"user": user,
};
}
This is model class for delete method
DeleteImageModels deleteImageModelsFromJson(String str) =>
DeleteImageModels.fromJson(json.decode(str));
String deleteImageModelsToJson(DeleteImageModels data) =>
json.encode(data.toJson());
class DeleteImageModels {
DeleteImageModels({
required this.ids,
});
List<int> ids;
factory DeleteImageModels.fromJson(Map<String, dynamic> json) =>
DeleteImageModels(
ids: List<int>.from(json["ids"].map((x) => x)),
);
Map<String, dynamic> toJson() => {
"ids": List<dynamic>.from(ids.map((x) => x)),
};
}
And this is API class for Delete method, which apparently is throwing exception
Future<DeleteImageModels> deleteAlbum() async {
var preferences = await SharedPreferences
.getInstance(); // This is Shared preference which is used to store the tokens of the users
var getToken = preferences.getString("token");
print("This is access: $getToken");
final http.Response response = await http.delete(
Uri.parse('http://10.0.2.2:8000/api_vi/deletedocument/'),
headers: {
'Context-Type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Bearer $getToken',
},
);
if (response.statusCode == 200) {
return DeleteImageModels.fromJson(jsonDecode(response.body));
} else {
// If the server did not return a "200 OK response",
// then throw an exception.
throw Exception('Failed to delete album.');
}
}
}
The id is only common thing between two models and I am supposed to delete using that id, now how do I do it? I did go through flutter official documents for deleting but it doesn't relate to mine.
Here in this image below we can see some numbers on the image, those are id which is displayed from get API now how do I pass that ID in delete api and and delete those image?

AFAIK your question is how to pass the image id by clicking on the remove icon.
If you are using the List.builder for representing your images then in the end you must return a widget that represents your image. This widget must contain id of image and pressable button where you can register click handler. You can place logic responsible for deleting the image inside of this handler.
I make a brief example that highlights the main points here.
Image widget example
class ImageWidget extends StatelessWidget {
final String id;
final String url;
ImageWidget(this.id, this.url);
#override
Widget build(BuildContext context) {
return SizedBox(
width: 64,
height: 64,
child: Stack(children: [
Positioned(child: IconButton(icon: ..., onPressed: {
// here delete logic
// api.deleteImgae(id);
},)),
Positioned.fill(child: Image(image: image))
],),
)
}
}
You can specify delete logic in onPressed callback of IconButton or any other (InkWell, GestureDetector, ElevatedButton and etc)
ListView example:
ListView.builder(itemBuilder: (_, i) => ImageWidget(images[i].id, images[i].url))

Related

Firebase: How to fetch data from an array field and print it in console?

Almost all tutorials and articles I have watched and read always lead to complex things like Streambuilder or Futurebuilder. I just want to print the data from an array field in the console. Nothing extraordinary.
I want to fetch this data right here.
To get the data, do this:
final doc = await FirebaseFirestore.instance.doc('goals/7L3n...').get();
final data = (doc.data()) as Map<String, dynamic>;
for (final photo in data['photos'] as List<String>) {
print(photo);
}
print(data['photos'][0]); // should print (https://www...)
print(data['photos'][1]);
Below is a cleaner (better) approach:
First define goal model (in a separate file).
// install json_serializable, json_annotation, equatable
import 'package:json_annotation/json_annotation.dart';
import 'package:equatable/equatable.dart';
#JsonSerializable(
explicitToJson: true,
fieldRename: FieldRename.snake,
includeIfNull: false,
)
class Goal extends Equatable {
final String goalName;
final List<String> photos;
final String someText;
const Goal({
required this.goalName,
required this.photos,
required this.someText,
});
Goal copyWith({
String? goalName,
List<String>? photos,
String? someText,
}) {
return Goal(
goalName: goalName ?? this.goalName,
photos: photos ?? this.photos,
someText: someText ?? this.someText,
);
}
factory GoalModel.fromJson(Map<String, dynamic> json) =>
_$GoalModelFromJson(json);
Map<String, dynamic> toJson() => _$GoalModelToJson(this);
factory GoalModel.fromFirestore(
DocumentSnapshot<Map<String, dynamic>> snapshot,
_,
) {
return _$GoalModelFromJson(snapshot.data()!);
}
#override
List<Object?> get props => [goalName, photos, someText];
}
run flutter pub run build_runner watch --delete-conflicting-outputs; on your terminal.
Then fetch your photo like this:
// import goal model here.
final goalDoc = await FirebaseFirestore.instance
.doc('goals/7L3n...')
.withConverter<Goal>(
fromFirestore: Goal.fromFirestore,
toFirestore: (data, _) => data.toJson(),
)
.get();
final goal = goalDoc.data()!;
for (final photo in goal.photos) {
print(photo);
}

How do I Display Nested json array in flutter?

Whenever I try accessing a field from the nested array I get the following Range error. Not sure what's gone wrong, any help would be appreciated.
RangeError (index): Invalid value: Only valid value is 0: 1
This is my User Model :
import 'dart:convert';
List<User> userFromJson(String str) =>
List<User>.from(json.decode(str).map((x) => User.fromJson(x)));
class User {
User({
required this.userName,
required this.facilities,
});
final String userName;
final List<Facility>? facilities;
factory User.fromJson(Map<String, dynamic> json) => User(
userName: json["userName"],
facilities: json["facilities"] == null
? null
: List<Facility>.from(
json["facilities"].map((x) => Facility.fromJson(x))),
);
}
class Facility {
Facility({
required this.id,
required this.employeeGlobalId,
required this.facilityId,
});
final int id;
final int employeeGlobalId;
final int facilityId;
factory Facility.fromJson(Map<String, dynamic> json) => Facility(
id: json["id"],
employeeGlobalId: json["employeeGlobalId"],
facilityId: json["facilityId"],
);
}
This is how I connect with the API and convert the response to a list.
class ApiService {
final url = Uri.parse("http://47.254.237.237:81/api/Users/GetAllUser");
Map<String, String> headers = {
"Accept": 'application/json',
'content-type': 'application/json',
'Authorization':
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjYyIiwibmJmIjoxNjY2OTU0NTEzLCJleHAiOjE2NjcwNDA5MTMsImlhdCI6MTY2Njk1NDUxM30.EXEzTX8-MHQqZuuILwHGoQ0Vpw2fAgsi2QypGNFgMAE',
'userId': '62'
};
Future<List<User>> fetchUsers(http.Client client) async {
final response = await client.get(url, headers: headers);
return compute(parseUsers, response.body);
}
List<User> parseUsers(String response) {
final parsed = jsonDecode(response).cast<Map<String, dynamic>>();
return parsed.map<User>((json) => User.fromJson(json)).toList();
}
}
Lastly, This is how I am trying to display the facility ID.
ListView.builder(
itemBuilder: (context, index) {
return ListTile(
title: Text(users[index].userName),
subtitle: Text(users[index].facilities![index].facilityId.toString()),
);
},
);
Probably facilities![index] is causing the issue. You're trying to access facilities values at index range, builder's current position, while only one value might be available.
Change to facilities![0]. Or use loop/map fn to print each facilities if there are more than 1 facilities values.
Updated code:
ListView.builder(
itemBuilder: (context, index) {
return ListTile(
title: Text(users[index].userName),
subtitle: Text(users[index].facilities![0].facilityId.toString()),
);
},
);

Flutter http.get

My problem is, that when I try to map the brands I need to declare brandsData as a Map<String, dynamic> but in that case jsonDecode(s) is red because it could be null
You can change your Model to this .
// To parse this JSON data, do
//
// final album = albumFromJson(jsonString);
import 'dart:convert';
List<Album> albumFromJson(String str) => List<Album>.from(json.decode(str).map((x) => Album.fromJson(x)));
String albumToJson(List<Album> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class Album {
Album({
this.userId,
this.id,
this.title,
});
int userId;
int id;
String title;
factory Album.fromJson(Map<String, dynamic> json) => Album(
userId: json["userId"],
id: json["id"],
title: json["title"],
);
Map<String, dynamic> toJson() => {
"userId": userId,
"id": id,
"title": title,
};
}
and use the function that #Ravindra via link like this
Future<List<Album>> fetchPost() async {
String url =
'https://jsonplaceholder.typicode.com/albums/1';
var response = await http.get(Uri.parse(url), headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
});
if (response.statusCode == 200) {
// If the call to the server was successful, parse the JSON
return Album.fromJson(json
.decode(response.body));
} else {
// If that call was not successful, throw an error.
throw Exception('Failed to load post');
}
}
Hope it helps you. Lastly you can use this link https://app.quicktype.io/ to create your model class.

How to use polymorphism in dart

Hi I need to use polymorphism in flutter to use it in get data from Restfull API
but it doesn't work.
first I have a base class (Model)
class Model
{
Model();
Model.fromJson(Map<String, dynamic> json) ;
Map<String, dynamic> toJson(){}
}
then I have derived class (City)
class City extends Model {
int id;
String name;
List<Region> regions;
City({this.id, this.name, this.regions});
City.fromJson(Map<String, dynamic> json) {
id = json['id'];
name = json['name'];
if (json['regions'] != null) {
regions = new List<Region>();
json['regions'].forEach((v) {
regions.add(new Region.fromJson(v));
});
}
}
}
and this is a function with getAllModel method
class Repository
{
static Future<List<T>> getAllModel<T extends Model>( apis url) async {
try {
bool tk = await Cache.tokenExists();
if (tk) {
String token = await Cache.getString(keys.api_token);
var body = {};
List<dynamic> data = await Request.callAPI(
apiName.name(url),
body,
method: 'GET', apiToken: token);
List<T> objs = new List();
if (data != null) if (data.length > 0) {
data.forEach((v) {
T r = Model.fromJson(v) as T;
objs.add(r);
});
return objs;
}
return objs;
}
return new List();
} catch (e, stacktrace) {
print("getAll() | catch exception");
print(e);
print(stacktrace);
return new List();
}
}
}
finally this is a call method
static Future<List<City>> getCities() async {
return Repository.getAllModel(apis.getCities);
}
this is a problem
type 'Model' is not a subtype of type 'City' in type cast
How can I solve this ?
Model.fromJson(v) will always return a value of the base type, Model.
You can't cast this to T = City here:
T r = Model.fromJson(v) as T;
because Dart can't know how to turn a Model into a City.
You would want to call “T.fromJson(v)”, so to speak, but Dart doesn't allow us to speak polymorphically about constructors.
I think your best bet might be to pass the relevant fromJson function along to getAllModel:
// The type of functions that take a JSON map and return T.
typedef JsonDecoder<T> = T Function(Map<String, dynamic> json);
// Use a provided `fromJson` callback to transform your API results:
Future<List<T>> getAllModel<T extends Model>(String url,
JsonDecoder<T> fromJson) async {
...
T r = fromJson(v);
...
}
// And provide it like so:
void myFunction() {
final cities = await getAllModel<City>("city url", (j) => City.fromJson(j));
}
(Somewhat annoyingly, we can't even write this:)
getAllModel<City>("city url", City.fromJson);
^^^^^^^^^^^^^
By the way, I recommend looking into json_serializable.
Here is an aproach i am thinking of taking to render different components returned from a REST api (strapi)
I want to render the components based on type from a response like this
{
"data": {
"id": 1,
"homepage": [
{
"id": 1,
"__component": "explore.search",
"enabled": true,
"include_articles": true,
"include_menu_entries": true,
"include_contributors": true
},
{
"id": 1,
"__component": "explore.whats-new",
"entry_count": 7
}
]
},
"meta": {}
}
I created a base component model like this to capture the common parameters to be extended by each component model later
class CmsComponent {
CmsComponent({
required this.id,
required this.component,
});
int id;
String component;
factory CmsComponent.fromJson(Map<String, dynamic> json) => CmsComponent(
id: json["id"],
component: json["__component"],
);
Map<String, dynamic> toJson() => {
"id": id,
"__component": component,
};
}
then an example of a single component model is
class CmsComponentSearch extends CmsComponent{
CmsComponentSearch({
required id,
required component,
required this.enabled,
required this.includeArticles,
required this.includeMenuEntries,
required this.includeContributors,
}) : super(id: id, component: component);
bool enabled;
bool includeArticles;
bool includeMenuEntries;
bool includeContributors;
factory CmsComponentSearch.fromJson(Map<String, dynamic> json) => CmsComponentSearch(
id: json["id"],
component: json["__component"],
enabled: json["enabled"],
includeArticles: json["include_articles"],
includeMenuEntries: json["include_menu_entries"],
includeContributors: json["include_contributors"],
);
Map<String, dynamic> toJson() => {
"id": id,
"__component": component,
"enabled": enabled,
"include_articles": includeArticles,
"include_menu_entries": includeMenuEntries,
"include_contributors": includeContributors,
};
}
then at the top level i can create this model with a method to switch out each components model as needed
class CmsExploreHome {
CmsExploreHome({
required this.id,
required this.components,
});
int id;
List<dynamic> components;
factory CmsExploreHome.fromJson(Map<String, dynamic> json) => CmsExploreHome(
id: json["id"],
components: List<dynamic>.from(json["homepage"].map((x) => getCmsComponentModelFromJson(x))),
);
Map<String, dynamic> toJson() => {
"id": id,
"homepage": List<dynamic>.from(components.map((x) => x.toJson())),
};
}
getCmsComponentModelFromJson(Map<String, dynamic> json) {
switch(json['__component']) {
case 'explore.search' : return CmsComponentSearch.fromJson(json);
case 'explore.whats-new' : return CmsComponentWhatsNew.fromJson(json);
default : return CmsComponent.fromJson(json);
}
}
Thats the data modelling done, then in the UI widget i can do something like this
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('explore'),
for (var component in exploreProvider.cmsExploreHome!.components) _RenderComponent(component),
],
),
and add the following widgets
class _RenderComponent extends StatelessWidget {
const _RenderComponent(this.component, {Key? key}) : super(key: key);
final CmsComponent component;
#override
Widget build(BuildContext context) {
if(component is CmsComponentSearch) return CmsSearchComponent(component as CmsComponentSearch);
return Text("${component.component} not implemented");
}
}
and for example
class CmsSearchComponent extends StatelessWidget {
const CmsSearchComponent(this.component, {Key? key}) : super(key: key);
final CmsComponentSearch component;
#override
Widget build(BuildContext context) {
return Text("Search field");
}
}
That gets the job done, the flutter app can receive dynamic types from the REST api in a list and render them

Flutter: Parsing JSON data and showing in App

I am very new to Flutter and Dart.
I have a signup page and I would like to show error in the App. My backend page is returning the errors and status in JSON format. Like below.
{"errors":{"Password1":"Password could not be empty",
"Email1":"Invalid Email Format",
"Name":"Your name must be between 3 to 30 characters!"},
"success":false}
I created a file for JSON parsing like below.
import 'dart:convert';
Signup signupFromJson(String str) => Signup.fromJson(json.decode(str));
String signupToJson(Signup data) => json.encode(data.toJson());
class Signup {
Errors errors;
bool success;
Signup({
this.errors,
this.success,
});
factory Signup.fromJson(Map<String, dynamic> json) => Signup(
errors: Errors.fromJson(json["errors"]),
success: json["success"],
);
Map<String, dynamic> toJson() => {
"errors": errors.toJson(),
"success": success,
};
}
class Errors {
String password1;
String email1;
String name;
Errors({
this.password1,
this.email1,
this.name,
});
factory Errors.fromJson(Map<String, dynamic> json) => Errors(
password1: json["Password1"],
email1: json["Email1"],
name: json["Name"],
);
Map<String, dynamic> toJson() => {
"Password1": password1,
"Email1": email1,
"Name": name,
};
}
Now I need to show this data to App after Async call.
Future userRegistration() async{
try{
// Showing CircularProgressIndicator.
setState(() {
visible = true ;
});
// Getting value from Controller
String name = nameController.text;
String email = emailController.text;
String password = passwordController.text;
// SERVER API URL
var url = 'http://192.168.100.10:8080/app/registerexec.php';
// Store all data with Param Name.
var data = {'name': name, 'email': email, 'password' : password};
// Starting Web API Call.
var response = await http.post(url, body: json.encode(data));
// Getting Server response into a variable.
final message = signupFromJson(response.body);
if(response.statusCode == 200){
setState(() {
visible = false;
});
}
// Showing Alert with Response JSON Message.
}catch(e){
return userRegistration();
}
}
How can I show the JSON data to SnackBar?
Edit
I managed to get the data in Print after manually defining it. Like below. But I want to automate it. So, if there are any errors it can show and if its successful then a different message.
print(message.errors.email1);
print(message.errors.name);
print(message.errors.password1);
print(message.success);
you could use FutureBuilder at your snackBar. I've edited from the code available here:
class SnackBarPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: userRegistration,
initialData: '',
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
// snapshot.data = yourData from your userRegistration
// print(snapshot.data) to show your data here
return snackBar = SnackBar(
content: Text('Yay! A SnackBar!'),
action: SnackBarAction(
label: 'Undo',
onPressed: () {
},
)
};
)
},
),
}
}