Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle complex API data response in Flutter GetX using observable method

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": "&laquo; 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 &raquo;",
                "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.
like image 873
Shoaib Khan Avatar asked Dec 31 '20 17:12

Shoaib Khan


People also ask

Is GetX good for Flutter?

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.

What is OBX in GetX Flutter?

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.

Why should we use GETX instead of context in flutter?

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.

Why getbuilder is not reactive in flutter?

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.

What is getX and how to use it?

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.

Do I need to use statefulwidget with GETX?

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.


Video Answer


1 Answers

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": [
    ....
    }
}
''';
like image 74
Ουιλιαμ Αρκευα Avatar answered Nov 15 '22 07:11

Ουιλιαμ Αρκευα