I am a newbie in the world of flutter and GetX package and I am trying to create a simple app using Laravel as my API service and I am sending the response from the API in JSON format and I am using Laravel resource API so it is sending some extra meta data inside the response and I have already created service model and controller in my flutter app but when I am initializing an observable variable in controller it is throwing a lot error i tried all the methods but it is working fine when i am sending only data list from the API as I have to define List<Model>.obs
in controller but the problem is happening when i am sending the proper response from API as required.
Here is my JSON response data from the API
{
"data": [
{
"id": 1,
"description": "Purchased mouse",
"amount": "1200",
"type": "expense",
"user_id": 1,
"created_at": null,
"updated_at": null
},
{
"id": 2,
"description": "Purchased mouse sa",
"amount": "1200",
"type": "expense",
"user_id": 1,
"created_at": null,
"updated_at": null
},
{
"id": 3,
"description": "Purchased mouse",
"amount": "1200",
"type": "expense",
"user_id": 1,
"created_at": null,
"updated_at": null
},
{
"id": 4,
"description": "Purchased mouse sa",
"amount": "1200",
"type": "expense",
"user_id": 1,
"created_at": null,
"updated_at": null
},
{
"id": 5,
"description": "Purchased mouse",
"amount": "1200",
"type": "expense",
"user_id": 1,
"created_at": null,
"updated_at": null
},
{
"id": 6,
"description": "Purchased mouse sa",
"amount": "1200",
"type": "expense",
"user_id": 1,
"created_at": null,
"updated_at": null
},
{
"id": 7,
"description": "Purchased mouse",
"amount": "1200",
"type": "expense",
"user_id": 1,
"created_at": null,
"updated_at": null
},
{
"id": 8,
"description": "Purchased mouse sa",
"amount": "1200",
"type": "expense",
"user_id": 1,
"created_at": null,
"updated_at": null
},
{
"id": 9,
"description": "Purchased mouse",
"amount": "1200",
"type": "expense",
"user_id": 1,
"created_at": null,
"updated_at": null
},
{
"id": 10,
"description": "Purchased mouse sa",
"amount": "1200",
"type": "expense",
"user_id": 1,
"created_at": null,
"updated_at": null
},
{
"id": 11,
"description": "Purchased mouse",
"amount": "1200",
"type": "expense",
"user_id": 1,
"created_at": null,
"updated_at": null
},
{
"id": 12,
"description": "Purchased mouse sa",
"amount": "1200",
"type": "expense",
"user_id": 1,
"created_at": null,
"updated_at": null
},
{
"id": 13,
"description": "Purchased mouse",
"amount": "1200",
"type": "expense",
"user_id": 1,
"created_at": null,
"updated_at": null
},
{
"id": 14,
"description": "Purchased mouse sa",
"amount": "1200",
"type": "expense",
"user_id": 1,
"created_at": null,
"updated_at": null
},
{
"id": 15,
"description": "Purchased mouse",
"amount": "1200",
"type": "expense",
"user_id": 1,
"created_at": null,
"updated_at": null
}
],
"links": {
"first": "http://localhost:8000/api/transactions?page=1",
"last": "http://localhost:8000/api/transactions?page=2",
"prev": null,
"next": "http://localhost:8000/api/transactions?page=2"
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 2,
"links": [
{
"url": null,
"label": "« Previous",
"active": false
},
{
"url": "http://localhost:8000/api/transactions?page=1",
"label": 1,
"active": true
},
{
"url": "http://localhost:8000/api/transactions?page=2",
"label": 2,
"active": false
},
{
"url": "http://localhost:8000/api/transactions?page=2",
"label": "Next »",
"active": false
}
],
"path": "http://localhost:8000/api/transactions",
"per_page": 15,
"to": 15,
"total": 16
}
}
And here is my service class
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:m_budget/models/transaction.dart';
class TransactionService {
static var client = http.Client();
static Future<Transaction> fetchTransactions() async {
var res = await client.get("http://10.0.2.2:8000/api/transactions");
if (res.statusCode == 200) {
return transactionFromJson(res.body);
} else {
return null;
}
}
}
And this is my controller
The main problem is while declaring the observable variable check line no 6 in controller
This one var transactions = Transaction().obs;
import 'package:get/get.dart';
import 'package:m_budget/models/transaction.dart';
import 'package:m_budget/services/transaction_service.dart';
class TransactionController extends GetxController {
var isLoading = true.obs;
var transactions = Transaction().obs;
@override
void onInit() {
fetchTransactions();
super.onInit();
}
void fetchTransactions() async {
isLoading(true);
try {
var txns = await TransactionService.fetchTransactions();
if (txns != null) {
isLoading(false);
transactions(txns);
}
} catch (e) {} finally {
isLoading(false);
}
}
}
And model code is this
// To parse this JSON data, do
//
// final transaction = transactionFromJson(jsonString);
import 'dart:convert';
Transaction transactionFromJson(String str) =>
Transaction.fromJson(json.decode(str));
String transactionToJson(Transaction data) => json.encode(data.toJson());
class Transaction {
Transaction({
this.data,
this.links,
this.meta,
});
List<Datum> data;
Links links;
Meta meta;
factory Transaction.fromJson(Map<String, dynamic> json) => Transaction(
data: List<Datum>.from(json["data"].map((x) => Datum.fromJson(x))),
links: Links.fromJson(json["links"]),
meta: Meta.fromJson(json["meta"]),
);
Map<String, dynamic> toJson() => {
"data": List<dynamic>.from(data.map((x) => x.toJson())),
"links": links.toJson(),
"meta": meta.toJson(),
};
}
class Datum {
Datum({
this.id,
this.description,
this.amount,
this.type,
this.userId,
this.createdAt,
this.updatedAt,
});
int id;
String description;
String amount;
String type;
int userId;
dynamic createdAt;
dynamic updatedAt;
factory Datum.fromJson(Map<String, dynamic> json) => Datum(
id: json["id"],
description: json["description"],
amount: json["amount"],
type: json["type"],
userId: json["user_id"],
createdAt: json["created_at"],
updatedAt: json["updated_at"],
);
Map<String, dynamic> toJson() => {
"id": id,
"description": description,
"amount": amount,
"type": type,
"user_id": userId,
"created_at": createdAt,
"updated_at": updatedAt,
};
}
class Links {
Links({
this.first,
this.last,
this.prev,
this.next,
});
String first;
String last;
dynamic prev;
String next;
factory Links.fromJson(Map<String, dynamic> json) => Links(
first: json["first"],
last: json["last"],
prev: json["prev"],
next: json["next"],
);
Map<String, dynamic> toJson() => {
"first": first,
"last": last,
"prev": prev,
"next": next,
};
}
class Meta {
Meta({
this.currentPage,
this.from,
this.lastPage,
this.links,
this.path,
this.perPage,
this.to,
this.total,
});
int currentPage;
int from;
int lastPage;
List<Link> links;
String path;
int perPage;
int to;
int total;
factory Meta.fromJson(Map<String, dynamic> json) => Meta(
currentPage: json["current_page"],
from: json["from"],
lastPage: json["last_page"],
links: List<Link>.from(json["links"].map((x) => Link.fromJson(x))),
path: json["path"],
perPage: json["per_page"],
to: json["to"],
total: json["total"],
);
Map<String, dynamic> toJson() => {
"current_page": currentPage,
"from": from,
"last_page": lastPage,
"links": List<dynamic>.from(links.map((x) => x.toJson())),
"path": path,
"per_page": perPage,
"to": to,
"total": total,
};
}
class Link {
Link({
this.url,
this.label,
this.active,
});
String url;
dynamic label;
bool active;
factory Link.fromJson(Map<String, dynamic> json) => Link(
url: json["url"] == null ? null : json["url"],
label: json["label"],
active: json["active"],
);
Map<String, dynamic> toJson() => {
"url": url == null ? null : url,
"label": label,
"active": active,
};
}
Please guys help me in this I am trying from last7 days but no success.
GetX has some great features out of the box, making it even easier to develop mobile applications in Flutter without any boilerplate code: Internationalization: translations with key-value maps, various language support, using translations with singulars, plurals, and parameters.
Obx class Null safety The simplest reactive widget in GetX. Just pass your Rx variable in the root scope of the callback to have it automatically registered for changes.
If we want to use widgets like Snackbar, Bottomsheets, dialogs, etc. Then we can use GetX for it because it can build these widgets without using context and it’s provide API for navigating within the Flutter application with simple and less code needed.
Reactive State Management : GetBuilder is not reactive means we’ll not able to use streams for this we have to use GetX class. syntax of GetX is very similar to GetBuilder but the approach is based on flutter’s stream.
In this article, we will be looking at GetX and it’ s principles, features and how to use it in our flutter applications. GetX is a fast, lightweight and powerful micro framework and using this, we can easily manage states, routing and can perform dependency injection in an efficient way.
No need to use StatefulWidget with GetX because GetBuilder replaces the StatefulWidget and we can keep all the widgets Stateless and wrap the specific widgets as per our requirement with GetBuilder.
item_model.dart
class ItemModel {
int id;
String description;
String amount;
String type;
int userId;
DateTime createdAt;
DateTime updatedAt;
ItemModel.fromJson(Map<String, dynamic> data) {
id = data['id'];
description = data['description'];
amount = data['amount'];
type = data['type'];
userId = data['userId'];
if (data['created_at'] != null) createdAt = DateTime.parse(data['created_at']);
if (data['updated_at'] != null) updatedAt = DateTime.parse(data['updated_at']);
}
}
page_links_model.dart
class PageLinksModel {
String first, last, prev, next;
PageLinksModel.fromJson(Map<String, dynamic> data) {
first = data['first'];
last = data['last'];
prev = data['prev'];
next = data['next'];
}
}
pages_status_model.dart
class PagesStatusModel {
int currentPage, from, lastPage;
var links = List<PageInfoModel>();
String path;
int perPage, to, total;
PagesStatusModel.fromJson(Map<String, dynamic> data) {
currentPage = data['current_page'];
from = data['from'];
lastPage = data['last_page'];
(data['links'] as List).forEach((e) => links.add(PageInfoModel.fromJson(e)));
path = data['path'];
perPage = data['per_page'];
to = data['to'];
total = data['total'];
}
}
class PageInfoModel {
String url;
dynamic label;
bool active;
PageInfoModel.fromJson(Map<String, dynamic> data) {
url = data['url'];
label = data['label'];
active = data['active'];
}
}
transaction_model.dart
import 'package:getx_api/models/pages_status_model.dart';
class TransactionModel {
var data = List<ItemModel>();
PageLinksModel links;
PagesStatusModel meta;
TransactionModel.fromJson(Map<String, dynamic> source) {
(source['data'] as List).forEach((e) => data.add(ItemModel.fromJson(e)));
links = PageLinksModel.fromJson(source['links']);
meta = PagesStatusModel.fromJson(source['meta']);
}
}
net_service.dart
import 'dart:convert';
import 'package:getx_api/src/shared/transactions_data.dart';
import 'package:http/http.dart' as http;
class NetService {
static Future fetchJsonData(String url) {
return
http.get(url)
.then((response) => response?.statusCode == 200 ? jsonDecode(response.body) : null)
.catchError((err) => print(err));
}
static Future fetchLocalJsonData() async {
await Future.delayed(Duration(seconds: 3));
return jsonDecode(transactionData) as Map<String, dynamic>;
}
}
transaction_controller.dart
import 'package:get/get.dart';
import 'package:getx_api/models/transaction_model.dart';
import 'package:getx_api/services/net_service.dart';
const _serverUrl = 'http://10.0.2.2:8000/api/transactions';
class TransactionController extends GetxController {
var _trx;
var _dataAvailable = false.obs;
@override
void onInit() {
super.onInit();
fetchTransactions();
}
bool get dataAvailable => _dataAvailable.value;
TransactionModel get trx => _trx;
Future<void> fetchTransactions() {
// return NetService.fetchJsonData(_serverUrl)
return NetService.fetchLocalJsonData()
.then((response) {
if (response != null) _trx = TransactionModel.fromJson(response);
})
.catchError((err) => print('Error!!!!! : $err'))
.whenComplete(() => _dataAvailable.value = _trx != null);
}
}
home_page.dart
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:getx_api/src/controllers/transaction_controller.dart';
class HomePage extends StatelessWidget {
/* ---------------------------------------------------------------------------- */
const HomePage({Key key}) : super(key: key);
/* ---------------------------------------------------------------------------- */
@override
Widget build(BuildContext context) {
final obj = Get.put(TransactionController());
return Scaffold(
appBar: buildAppBar(),
body: Obx(() => obj.dataAvailable
? Text(obj.trx.toString())
: Text('... waiting ...')),
);
}
/* ---------------------------------------------------------------------------- */
AppBar buildAppBar() {
return AppBar(
title: Text('Hi!'),
centerTitle: true,
);
}
}
transactions_data.dart
const transactionData = '''
{
"data": [
....
}
}
''';
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With