Flutter Internationalization: How to access to nested data in json - flutter

I want to know how to access to nested data in json.
AppLocalizations.of(context).translate('Information.about');
en.json
{
"Information" : {
"about": "About"
}
}
I tried like the way above but it cannot access to the nested data.
And here is translate method.
class AppLocalizations {
final Locale locale;
AppLocalizations(this.locale);
static AppLocalizations of(BuildContext context) {
return Localizations.of<AppLocalizations>(context, AppLocalizations);
}
// Static member to get access to the delegate from 'main.dart' file
static const LocalizationsDelegate<AppLocalizations> delegate = _AppLocalizationsDelegate();
Map<String, String> _localizedValues;
Future<bool> load() async {
// Load a language JSON file from the 'i18n' folder
String value = await rootBundle.loadString('i18n/${locale.languageCode}.json');
Map<String, dynamic> jsonMap = jsonDecode(value);
_localizedValues = jsonMap.map((key, value) {
return MapEntry(key, value.toString());
});
return true;
}
String translate(String key) {
// Returns a localized text
return _localizedValues[key];
}
}

This is my solution based on https://stackoverflow.com/a/60924513
Map flattenTranslations(Map<String, dynamic> json, [String prefix = '']) {
final Map<String, String> translations = {};
json.forEach((String key, dynamic value) {
if (value is Map) {
translations.addAll(flattenTranslations(value, '$prefix$key.'));
} else {
translations['$prefix$key'] = value.toString();
}
});
return translations;
}
Future<bool> load() async {
String jsonString = await rootBundle.loadString('assets/i18n/${locale.languageCode}.json');
Map<String, dynamic> jsonMap = jsonDecode(jsonString);
_localizedStrings = flattenTranslations(jsonMap);
return true;
}
And this is all app_localizations.dart file
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class AppLocalizations {
final Locale locale;
AppLocalizations(this.locale);
static AppLocalizations of(BuildContext context) {
return Localizations.of<AppLocalizations>(context, AppLocalizations);
}
static const LocalizationsDelegate<AppLocalizations> delegate = _AppLocalizationsDelegate();
Map<String, String> _localizedStrings;
Map flattenTranslations(Map<String, dynamic> json, [String prefix = '']) {
final Map<String, String> translations = {};
json.forEach((String key, dynamic value) {
if (value is Map) {
translations.addAll(flattenTranslations(value, '$prefix$key.'));
} else {
translations['$prefix$key'] = value.toString();
}
});
return translations;
}
Future<bool> load() async {
String jsonString = await rootBundle.loadString('assets/i18n/${locale.languageCode}.json');
Map<String, dynamic> jsonMap = jsonDecode(jsonString);
_localizedStrings = flattenTranslations(jsonMap);
return true;
}
String translate(String key) {
return _localizedStrings[key] ?? key;
}
}
class _AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations> {
const _AppLocalizationsDelegate();
#override
bool isSupported(Locale locale) {
return ['en', 'pl'].contains(locale.languageCode);
}
#override
Future<AppLocalizations> load(Locale locale) async {
AppLocalizations localizations = new AppLocalizations(locale);
await localizations.load();
return localizations;
}
#override
bool shouldReload(_AppLocalizationsDelegate old) => false;
}

Try this:
First Method:
AppLocalizations.of(context).translate(“about”);
And change your translate function to this:
String translate(String key) {
// Returns a localized text
return _localizedValues[“Information”][key];
}
Or you can do this:
Second Method:
AppLocalizations.of(context).translate(”Information”,“about”);
And change your translate function to this:
String translate(String parentkey, String nestedKey) {
// Returns a localized text
return _localizedValues[parentKey][nestedKey];
}
This might help.
Also, This is a good article to learn how to parse complex json files
UPDATED ANSWER:
After trying the code, I could understand the problem.
The problem is your _localizedValues["Information"] will be a String not a map becuase we converted the value to value.toString() and that's why you cannot use a second key because the returned object is not a Map but it's a String.
So _localizedValues["Information"] is "{about: About}".
To solve the problem, use the code below:
Map<String, dynamic> _localizedValues; //your values are not String anymore and we use dynamic instead
Future<bool> load() async {
// Load a language JSON file from the 'i18n' folder
String value = await rootBundle.loadString('i18n/${locale.languageCode}.json');
Map<String, dynamic> jsonMap = jsonDecode(value);
_localizedValues = jsonMap.map((key, value) {
return MapEntry(key, value); //not value.toString() so the value will be a map
});
return true;
}
String translate(String parentkey, String nestedKey) {
// Returns a localized text
return _localizedValues[parentKey][nestedKey];
}
And then you have to get "About" from the code below:
AppLocalizations.of(context).translate('Information','about');

This will allow you to access nested JSON regardless of depth. Just modify your translate method like so:
String translate(String key) {
List<dynamic> keys = key.split('.');
var value = keys.fold(_localizedValues, (obj, key) => obj[key]);
return value;
}
Then you are able to access your nested JSON in your code like this:
AppLocalizations.of(context).translate('key1.key2.key3');
Just make sure there won't be any periods in your JSON keys

If you are using easy_localization flutter package for localization you can access object value from JSON like below with dot notation
"Information.about".tr()

Here is my answer, it looks like #Morez answer but it works for me:
Map<String,dynamic> _localizedValues;
Map<String,dynamic> _localizedValues2;
Future<void> load() async {
String jsonStringValues = await rootBundle.loadString('lib/jsonLanguages/${locale.languageCode}.json');
//print(jsonStringValues);
Map<String,dynamic> mappedJson = json.decode(jsonStringValues);
_localizedValues = mappedJson.map((key, value) => MapEntry(key, value));
}
String translate(String key,String subkey){
String test = _localizedValues[key].toString();
test = test.replaceAllMapped(RegExp(r'(\b\w+( +\w+)*\b)|(\b\w+\b)'), (match) {return '"${match.group(0)}"';});
//print(test);
Map<String,dynamic> mappedJson2 = json.decode(test);
_localizedValues2 = mappedJson2.map((subkey, value) => MapEntry(subkey, value));
return _localizedValues2[subkey];
}

Related

how to make return of model class into list

i have model called LoginPageModel, but the problem is my api have more than one CODD_VALU and CODD_DESC. and i dont know how to return it as list or an array.
This is my LoginPageModel
class LoginPageModel {
String CODD_VALU;
String CODD_DESC;
LoginPageModel({required this.CODD_VALU, required this.CODD_DESC});
static Future<LoginPageModel> connect(String CODD_VALU) async {
Uri url = Uri.parse("http://deltaprima.rmdoo.com/api/niv/all");
var response = await http.get(
url,
headers: {
"CompanyCode": CODD_VALU,
},
);
var dataJson = jsonDecode(response.body);
return LoginPageModel(
CODD_VALU: dataJson[0]["CODD_VALU"],
CODD_DESC: dataJson[0]["CODD_DESC"],
);
}
}
and this is response of my api (Im using postma)
[
{
"CODD_DESC": "DELTA PRIMA",
"CODD_VALU": "01"
},
{
"CODD_DESC": "SAMPLE",
"CODD_VALU": "02"
}
]
and also this is how i will call return value of LoginPageModel Like this
LoginPageModel.connect(data["CODD_VALU"]).then((value) {
print(value.CODD_DESC);
setState(() {
dataOffice = value.CODD_DESC;
});
}
import 'package:wnetworking/wnetworking.dart';
class Offices {
final String name, value;
/* ---------------------------------------------------------------------------- */
Offices(this.name, this.value);
/* ---------------------------------------------------------------------------- */
#override
String toString() => '$name [$value]';
}
class DeltaPrima {
DeltaPrima._();
/* ---------------------------------------------------------------------------- */
static const _url = 'http://deltaprima.rmdoo.com/api/office/all';
/* ---------------------------------------------------------------------------- */
static Future<List<Offices>?> getOffices(String token) async {
var result = (await HttpReqService.get<List>(_url, headers: {'CompanyCode':token}));
if (result == null) return null;
var list = result
.cast<JMap>()
.map((m) => Offices(m['CODD_DESC']!, m['CODD_VALU']!))
.toList()
;
print('Objects => $list');
return list;
}
}
void main(List<String> args) async {
await DeltaPrima.getOffices('MW');
print('Job done!');
}
Output:
Objects => [DELTA PRIMA [01], SAMPLE [02]]
Job done!
The easiest way is as follows:
You need to use a tool that passes Json to Dart class.
For example from https://app.quicktype.io and the result is:
// To parse this JSON data, do
//
// final loginPageModel = loginPageModelFromJson(jsonString);
import 'dart:convert';
List<LoginPageModel> loginPageModelFromJson(String str) =>
List<LoginPageModel>.from(
json.decode(str).map((x) => LoginPageModel.fromJson(x)));
String loginPageModelToJson(List<LoginPageModel> data) =>
json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class LoginPageModel {
LoginPageModel({
required this.coddDesc,
required this.coddValu,
});
String coddDesc;
String coddValu;
factory LoginPageModel.fromJson(Map<String, dynamic> json) => LoginPageModel(
coddDesc: json["CODD_DESC"],
coddValu: json["CODD_VALU"],
);
Map<String, dynamic> toJson() => {
"CODD_DESC": coddDesc,
"CODD_VALU": coddValu,
};
}
Update Your Login Page Model Like this.
class LoginPageModel {
String CODD_VALU;
String CODD_DESC;
LoginPageModel({required this.CODD_VALU, required this.CODD_DESC});
factory LoginPageModel.fromJson(Map<String, dynamic> json) => LoginPageModel(
coddDesc: json["CODD_DESC"],
coddValu: json["CODD_VALU"],
);
static Future<List<LoginPageModel>> connect(String CODD_VALU) async {
Uri url = Uri.parse("http://deltaprima.rmdoo.com/api/niv/all");
var response = await http.get(
url,
headers: {
"CompanyCode": CODD_VALU,
},
);
var dataJson = jsonDecode(response.body);
Iterable l = json.decode(response.body);
List<LoginPageModel> listmodel = List<LoginPageModel>.from(l.map((model)=> LoginPageModel.fromJson(model)));
return listmodel;
}
}

A value of type 'List<dynamic>' can't be assigned to a variable of type 'List<Todo>'. Try changing the type of the variable

im new in flutter , and i want to display my data from api json to my app with ResteApi ,
i made a model like that :
class Todo {
final int id;
final String title;
final bool completed;
Todo({required this.id, required this.title, required this.completed});
factory Todo.fromJson(Map<String, dynamic> json) {
return Todo(
id: json["id"] as int,
title: json["title"] as String,
completed: json["completed"] as bool);
}
Map<String, dynamic> toJson() => {'title': title, 'completed': completed};
#override
String toString() {
return 'Todo{id: $id, title: $title, completed: $completed}';
}
}
And a methode get in service class Like that :
final String apiUrl = "https://jsonplaceholder.typicode.com/todos";
Future<List<Todo>> getCases() async {
Response res = await get(Uri.parse(apiUrl));
if (res.statusCode == 200) {
List<dynamic> body = jsonDecode(res.body);
List<Todo> todo = body.map((dynamic item) => todo.fromJson(item)).toList();
return todo;
} else {
throw "Failed to load cases list";
}
}
but this errors it display to me:
A value of type 'List<dynamic>' can't be assigned to a variable of type 'List<Todo>'.
Try changing the type of the variable, or casting the right-hand type to 'List<Todo>'
how can i fix it
There is a typo todo.fromJson, it will be Todo.fromJson
List<Todo> todo = body.map((dynamic item) => Todo.fromJson(item)).toList();
Also it is better to accept null data
List<dynamic>? body = jsonDecode(res.body);
final todo =
body?.map((dynamic item) => Todo.fromJson(item)).toList() ?? [];
return todo;
Try this:
if (res.statusCode == 200) {
List<dynamic> body = jsonDecode(res.body);
List<Todo> todo = body.map<Todo>((item) => Todo.fromJson(item)).toList();
return todo;
} else {
throw "Failed to load cases list";
}
// create function like this inside ApiFunctionsCall() class
Future<String?> dataListApiCalls() async {
try {
final result = await InternetAddress.lookup('google.com');
if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
final response = await http.get(Uri.parse('url_of_api'));
if (response.statusCode == 200) {
//print(response.body);
return response.body;
}
} else {
print("check internet connection");
}
} catch (e) {
print(e);
}
}
//then in call function other file
// create list
List<Todo> searchDataList = [];
// other function
void getDataList() async {
final response = await ApiFunctionsCall().dataListApiCalls();
final searchModalDataClass = jsonDecode(response!);
setState(() {
for (var i = 0; i < searchModalDataClass.data.length; i++) {
Todo todo = Todo(
id: searchModalDataClass.data[i].id,
email: searchModalDataClass.data[i].email,
searchDataList.add(todo);
}
});
}

Select image for flutter web on mobile device

Im currently using https://pub.dev/packages/file_picker for this function
FilePickerResult result =
await FilePicker.platform.pickFiles();
if (result != null) {
setState(() {
filePicked = result;
});
for (int i = 0; i < result.files.length; i++) {
setState(() {
listBytes.add(result.files[i].bytes);
});
}
} else {
// User canceled the picker
}
when i test on web it work successfully, however the problem occur when running on web app (in mobile) after select image it got no respond. It's hard to debug since i don't really know on how to debug for web app. My question is, can i just use the function i use on web, or is there any specific function i need to use in order for it to work in web app.
You can try this for the web app (This method should only be used for the web platform):
import '../../models/html_nonweb.dart'
if (dart.library.js) 'dart:html' as html;
Future<WebFileModel> pickWebFileModel() {
final completer = Completer<WebFileModel>();
final html.InputElement input =
html.document.createElement('input') as html.InputElement;
input
..type = 'file'
..accept = 'image/*';
input.onChange.listen((e) async {
final List<html.File> files = input.files!;
final reader = html.FileReader();
reader.readAsDataUrl(files.first);
reader.onError.listen(completer.completeError);
final Future<WebFileModel> resultsFutures =
reader.onLoad.first.then((_) => WebFileModel(
path: reader.result! as String,
type: files.first.type as String,
createdAt: DateTime.fromMillisecondsSinceEpoch(
files.first.lastModified!,
),
htmlFile: files.first,
));
final results = await resultsFutures;
completer.complete(results);
});
input.click();
return completer.future;
}
To use this code, you need to create the html_nonweb.dart file:
const document = Document();
class Document {
const Document();
Element createElement(String el) => InputElement();
}
class File {
final int? lastModified = null;
final String? type = null;
}
class Element {
const Element();
}
class InputElement extends Element {
const InputElement();
final List<File>? files = null;
Stream<Object> get onChange => Stream.empty();
set type(String type) {}
set multiple(bool multiple) {}
set accept(String s) {}
void readAsDataUrl(File file) {}
void click() {}
}
class FileReader {
Stream<void Function(Object error, [StackTrace? stackTrace])> get onError =>
Stream.empty();
void readAsDataUrl(File file) {}
Stream<Object> get onLoad => Stream.empty();
final Object? result = null;
}
And WebFileModel:
import 'dart:typed_data';
import 'html_nonweb.dart' if (dart.library.js) 'dart:html' as html;
class WebFileModel {
final String path;
final String type;
final DateTime createdAt;
final html.File? htmlFile;
final Uint8List? uIntFile;
WebFileModel({
required this.path,
required this.type,
required this.createdAt,
this.htmlFile,
this.uIntFile,
});
WebFileModel copyWith({
String? path,
String? type,
DateTime? createdAt,
html.File? htmlFile,
Uint8List? uIntFile,
}) {
return WebFileModel(
path: path ?? this.path,
type: type ?? this.type,
createdAt: createdAt ?? this.createdAt,
htmlFile: htmlFile ?? this.htmlFile,
uIntFile: uIntFile ?? this.uIntFile,
);
}
}
To get a Uint8List, you need to do the following:
final imageBase64 =media.path.replaceFirst(RegExp(r'data:image/[^;]+;base64,'), '');
final uIntFile = base64Decode(imageBase64);

JSON file to List of Object keeps throwing error not subtype of specific object type

I am trying to conver JSON file to List so I can use it with DropdownMenuItem. The method stops whenever I am trying to decode the response and throws this error: Unhandled Exception: type 'List<dynamic>' is not a subtype of type 'List<Country>' How can I solve this??
method:
List<Country> _countryList = [];
Future<void> readJson() async {
final String response = await rootBundle.loadString('assets/countries.json');
print(response);
final List<Country> data = await json.decode(response).map((e) => Country.fromJson(e)).toList();
setState(() {
_countryList = data;
});
}
My Json looks like this
[
{
"value": "AFG",
"label": "Afghanistan",
"eu": false
},
....
]
Country model class
class Country {
String value;
String label;
bool eu;
Country({
required this.value,
required this.label,
required this.eu,
});
factory Country.fromJson(Map<String, dynamic> json) {
return Country(
value: json["value"],
label: json["label"],
eu: json["eu"],
);
}
}
json.decode(..) returns dynamic type and in your case you need to cast it to List
final decodedJson = jsonDecode(response) as List;
now take the decodedJson and cast its generic type
final castedList = decodedJson.cast<Map<String, dynamic>>();
now it will be so simple to map it to dart object Country
final List<Country> data = castedList.map((e) => Country.fromJson(e)).toList();
the final result:
List<Country> _countryList = [];
Future<void> readJson() async {
final String response = await rootBundle.loadString('assets/countries.json');
print(response);
final decodedJson = jsonDecode(response) as List;
final castedList = decodedJson.cast<Map<String, dynamic>>();
final List<Country> data =
castedList.map((e) => Country.fromJson(e)).toList();
setState(() {
_countryList = data;
});
}

Flutter Firestore array with Maps. Do they work?

I can't stream (read) Documents that contain array properties that are Maps in Firestore.
Using Firestore with a document containing an array with a simple String type works as expected. Easy to write (append with FieldValue.arrayUnion(['data1','data2','data3']) and stream back out with code like:
var test2 = List<String>();
for (var item in data['items']) {
print('The item $item');
test2.add(item);
}
test2 can now be used as my items property.
When I try and use a List where item type becomes a Map in Firestore and is just a simple Class containing a few Strings and a date property. I can write these to FireStore but I can't read them back out.
The following code fails: (no errors in the Debug Console but it doesn't run)
var test2 = List<Item>();
data['items'].forEach((item) {
var description = item['description'];
print('The description $description'); // <-- I don't get past this
final x = Item.fromMap(item); // <-- so I can't even attempt this
return test2.add(x);
});
I never get to actually call my Item.fromMap constructor: here is another try:
// fails
final theItems = data['items'].map((x) {
return Item.fromMap(x); // <-- never get here
});
Although the DEBUG CONSOLE doesn't say there is any problem. If I inspect theItems variable (the debugger 'jumps' a couple of lines down to my return) after the failed iteration it looks like this:
MappedListIterable
_f:Closure
_source:List (1 item)
first:Unhandled exception:\ntype '_InternalLinkedHashMap<dynamic, dynamic>' is not a subtype of type 'Map<String, dynamic>'\n#0 new Listing.fromMap.<anonymous closure> isEmpty:false
isNotEmpty:true
iterator:ListIterator
last:Unhandled exception:\ntype '_InternalLinkedHashMap<dynamic, dynamic>' is not a subtype of
So bad things have happened but I have no idea why!
Has anyone actually written and retrieved Firestore array properties that contain Maps?
Any help in how to proceed would be greatly appreciated!
More: screen shot of the document
Here is the code that reads (streams) the collection
Stream<List<T>> collectionStream<T>({
#required String path,
#required T builder(Map<String, dynamic> data, String documentID),
#required String userId,
Query queryBuilder(Query query),
int sort(T lhs, T rhs),
}) {
Query query = Firestore.instance.collection(path);
if (queryBuilder != null) {
query = queryBuilder(query);
}
final Stream<QuerySnapshot> snapshots = query.snapshots();
return snapshots.map((snapshot) {
//print('document: path $path ${snapshot.documents[0]?.documentID}');
final result = snapshot.documents
.map((snapshot) => builder(snapshot.data, snapshot.documentID))
.where((value) => value != null)
.toList();
if (sort != null) {
result.sort(sort);
}
print('returning from CollectionStream');
return result;
});
}
the .map is where the problem comes in. The builder function resolves to this:
builder: (data, documentId) {
return Listing.fromMap(data, documentId);
},
Which ends up here
factory Listing.fromMap(
Map<String, dynamic> data,
String documentId,
) {
if (data == null) {
return null;
}
final theTime = (data['createdAt'] as Timestamp).toDate();
// see above code where I fail at getting at the items property/field
Here is the Item Class:
class Item {
Item(this.description, this.imageURL, this.thumbnailURL,
{this.status = ItemStatus.active,
this.type = ListingType.free,
this.price = 0,
this.isUpdate = false,
this.createdAt});
final String description;
final String imageURL;
final String thumbnailURL;
final ItemStatus status;
final ListingType type;
final int price;
final bool isUpdate;
DateTime createdAt;
factory Item.fromMap(
Map<String, dynamic> data,
) {
if (data == null) {
return null;
}
final theTime = (data['createdAt'] as Timestamp).toDate();
return Item(
data['description'],
data['imageURL'],
data['thumbnailURL'],
status: _itemStatusFromString(data['status']),
type: data['type'] == 'free' ? ListingType.free : ListingType.flatRate,
createdAt: theTime,
);
}
Map<String, dynamic> toMap() {
// enums are for shit in Dart
final statusString = status.toString().split('.')[1];
final typeString = type.toString().split('.')[1];
return {
'description': description,
'imageURL': imageURL,
'thumbnailURL': thumbnailURL,
'itemStatus': statusString,
'price': price,
'listingType': typeString,
if (!isUpdate) 'createdAt': DateTime.now(),
if (isUpdate) 'updatedAt': DateTime.now(),
};
}
}
The above is never called to read (we crash) ... it is called to write the data.
This is a known issue with Firestore. Here is the starting thread Flutter issues I found
From reading through the issues it seems lots of folks use a serializer package which is where the issue surfaced. Its still active...
Here is my solution NOT using a serializer and just doing it 'by hand'.
I was able simplify the problem and generate an error that was Google-able. Below is a single page which just writes and reads a single Document. The Class A and B are as small as can be.
So the code writes a single document to Firestore the contains two properties. A name and items. The items being the List of Class B that Class A contains. Checkout the Firebase console. The reading just does that.
No StreamController just the Console. The problem is in the fromMap method where we have to convert the array of objects in Firesote to a List of class instances in Dart. This should not be this difficult and at a minimum it should be documented ....
the line
var theRealItems = data['items'].map((i) => B.fromMap(i));
will generate the error. And needs to be replaced with
var theItems = data['items'].map((i) {
var z = Map<String, dynamic>.from(i);
print(z['description']);
return B.fromMap(z);
}).toList();
var theRealItems = List<B>.from(theItems);
Why this is so difficult is still a mystery to me! Anyone improving this code: I'm all ears.
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class A {
A(this.name, this.items);
final name;
final List<B> items;
factory A.fromMap(
Map<String, dynamic> data,
String documentId,
) {
if (data == null) {
return null;
}
// we crash here !!!
var theRealItems = data['items'].map((i) => B.fromMap(i));
// uncomment the 6 lines below
// var theItems = data['items'].map((i) {
// var z = Map<String, dynamic>.from(i);
// print(z['description']);
// return B.fromMap(z);
// }).toList();
// var theRealItems = List<B>.from(theItems);
return A(data['name'], theRealItems);
}
Map<String, dynamic> toMap() {
var theItems = items.map((i) => i.toMap()).toList();
return {'name': name, 'items': theItems};
}
}
class B {
B(this.description);
final description;
factory B.fromMap(
Map<String, dynamic> data,
) {
if (data == null) {
return null;
}
return B(data['description']);
}
Map<String, dynamic> toMap() {
return {
'description': description,
};
}
}
class Test extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
onPressed: () => _write(),
child: Text('Write the Doc'),
),
RaisedButton(
onPressed: () => _read(),
child: Text('Read the Doc ... check Debug Console!'),
),
],
),
),
);
}
_write() async {
try {
var b = B('Inside B!');
List<B> theList = List<B>();
theList.add(b);
var a = A('myName', theList);
await Firestore.instance
.collection('test')
.document('testDoc')
.setData(a.toMap());
print('returning from write!');
} catch (e) {
print('Error ${e.toString()}');
}
}
_read() async {
try {
var aFromFs = await Firestore.instance
.collection('test')
.document('testDoc')
.get();
var a = A.fromMap(aFromFs.data, aFromFs.documentID);
print('the A from FireBase $a with name ${a.name} first item ${a.items.first.description}');
print('returning from read!');
} catch (e) {
print('Oh no Error! ${e.toString()}');
}
}
}
In the below code Name refers to the name of your respective document and collection.
Let's say you want to get "imageURL" and "thumbnailUrl" for now and update the values without deleting or changing other fields inside the array.
String imageUrl ;
String thumbnailUrl;
DocumentReference _docReference = FirebaseFirestore.instance.collection(NAME).doc(NAME);
//refering to the specific document
Map<String, dynamic> neededData= allDocsFromTraining.data();
//getting all the keys and values inside the document
List<Map<String, dynamic>> _yourDocument=
(neededData["items"] as List<dynamic>)
.map((m) => Map<String, dynamic>.from(m))
.toList();
//only getting the list of items
for (int index = 0; index < _yourDocument.length; index++) {
Map<String, dynamic> _getMap = _yourDocument[index];
if (_getMap["price"] == 0)
//giving a condition to get the desired value and make changes
{
//setting the variables with the value from the database
setState(() {
imageUrl = _getMap["imageURL"];
thumbnailUrl = _getMap["thumbnailURL"]
});
///Use this if you want to update value of imageURL and thumbnailURL at that specific index of an array
_getMap['imageURL'] = "Your Updated URL";
_getMap['thumbnailURL'] = "Your Updated Url;
break;
} else {}
}
await _docReference.update({"items": _yourDocument});
//this adds the updated value to your database.