How to create JSON object in flutter? - android

I'm working on one application in which I want to fill the registration form and pass this data to API.I tried almost all solutions but not solved this issue.
I'm getting this type of data after filling the form
[
{Date of Birth of the Baby: 08/01/1997},
{Gender of the baby: male},
{Time of Birth of the Baby: 12.00 pm},
{Father's Name: Nnn},
{Mother's Name: Hbhh},
{Any Extra Details?: Bnn}
]
and I want this type of data
{
"Date of Birth of the Baby": "08/01/1997",
"Gender of the baby": "male",
"Time of Birth of the Baby": "12.00 pm",
"Father's Name": "Nnn",
"Mother's Name": "Hbhh",
"Any Extra Details?": "Bnn"
}
var fieldsData = [];
final myControllers = [];
mydynamicData() {
for (var i = 0; i <= widget.fieldData.length; i++) {
fieldsData.add({
widget.fieldData[i]['question'],
myControllers[i].text != null || myControllers[i].text != ""
? myControllers[i].text
: ""
});
}
print("fieldsData:${fieldsData}");
}
This is my method i know this issue occurred due to for loop but without for loop I'm not getting all fields data. so please help.

Import:
import 'dart:convert';
then you can use:
json.encode(fieldsData);
As you have a list of objects, it may be necessary to make a for in the list calling json.encode for each item, then encoding the result.

Related

Google Sheets API: How to find a row by value and update it's content

I am working on an Android application that uses a Google Spreadsheet as a database.
The application should GET, APPEND and UPDATE values in a spreadsheet, using the Sheets API v4. The first two functions are working fine but I have difficulties updating a specific row. I need to find a row that has a specific value in it's first column ("Batch ID") and update all the cells in this row.
This is how my spreadsheet looks like.
Right now I am getting the row to be modified like this:
ValueRange response = this.mySheetsService.spreadsheets().
values().get(spreadsheetId, range).execute();
List<List<Object>> values = response.getValues();
String rangeToUpdate;
Log.i(TAG, "all values in range: " + values.toString());
int i = 0;
if (values != null) {
for (List row : values) {
i += 1;
if (row.get(0).equals(selectedBatchID)) {
Log.i(TAG, "IT'S A MATCH! i= " + i);
rangeToUpdate = "A" + (i + 1) + ":E" + (i + 1); //row to be updated
}
}
}
/*once I have the row that needs to be updated, I construct my new ValueRange requestbody and
*execute a values().update(spreadsheetId, rangeToUpdate , requestbody) request.
*/
This is actually working fine but I think it's an ugly solution and I am sure there is a better one out there.
I have read the Sheets API documentation and I got familiar with notions such as batchUpdateByDataFilter, DataFilterValueRange or DeveloperMetadata and I sense that I should use these features for what I'm trying to achieve but I couldn't put them together and I couldn't find any examples.
Can someone show me or help me understand how to use these Sheets V4 features?
Thank you.
I have exactly the same issue, and it seems that so far (March 2018) Sheets v4 API does not allow to search by value, returning cell address. The solution I found somewhere here on StackOverflow is to use a formula. The formula can be created in an arbitrary sheet each time you want to find the address by value, then you erase the formula. If you do not want to delete the formula every time, you many prefer to create in a safer place, like a hidden worksheet.
Create hidden worksheet LOOKUP_SHEET (spreadsheetId is your spreadsheet ID):
POST https://sheets.googleapis.com/v4/spreadsheets/spreadsheetId:batchUpdate
{
"requests": [
{
"addSheet": {
"properties": {
"hidden": true,
"title": "LOOKUP_SHEET"
}
}
}
]
}
Create a formula in the A1 cell of the hidden worksheet that searches for "Search value" in MySheet1 sheet, and get back the row:
PUT https://sheets.googleapis.com/v4/spreadsheets/spreadsheetId/values/LOOKUP_SHEET!A1?includeValuesInResponse=true&responseValueRenderOption=UNFORMATTED_VALUE&valueInputOption=USER_ENTERED&fields=updatedData
{
"range": "LOOKUP_SHEET!A1",
"values": [
 [
  "=MATCH("Search value", MySheet1!A:A, 0)"
 ]
]
}
The response will look like this:
{
"updatedData": {
 "range": "LOOKUP_SHEET!A1",
 "majorDimension": "ROWS",
 "values": [
  [
   3
  ]
 ]
}
}
By default, major dimension is ROWS. MATCH() returns relative row within column A, if no row IDs are provided then this position is effectively absolute. Or, you may want to use a more reliable call like =ROW(INDIRECT(ADDRESS(MATCH("Search value",A:A,0),1))). If the sheet has spaces in it, enclose it in single quotes. If you are searching for number, make sure you do not enclose it in quotes.
In the spreadsheets API we have the concept of developer metadata, that allow us to store information not visible to the end user that we can later on retrieve and use.
In this case the best approach is to assign the Batch ID as a metadata for a particular row. I will add the code based on the Javascript SDK.
const response = await sheets.spreadsheets.developerMetadata.search({
auth: jwtClient,
spreadsheetId,
requestBody: {
dataFilters: [
{
developerMetadataLookup: {
locationType: 'ROW',
metadataKey: 'batchId',
metadataValue: '$BATCH_ID'
}
}
]
}
});
if (response.matchedDeveloperMetadata) {
// There is a row with that id already present.
const { endIndex } = response.matchedDeveloperMetadata[0].developerMetadata.location.dimensionRange;
// Use endIndex to create the range to update the values range: `SheetName!A${endIndex}`,
await sheets.spreadsheets.values.update(
{
auth: jwtClient,
spreadsheetId,
range: `SheetName!A${endIndex}`,
valueInputOption: 'USER_ENTERED',
requestBody: {
majorDimension: 'ROWS',
values: [[]]
},
},
{}
);
} else {
// Append the value and create the metadata.
const appendResponse = await sheets.spreadsheets.values.append(
{
auth: jwtClient,
spreadsheetId,
range: 'SheetName!A1',
valueInputOption: 'USER_ENTERED',
requestBody: {
majorDimension: 'ROWS',
values: [[]]
},
},
{}
);
if (appendResponse.data.updates?.updatedRange) {
const updatedRange = appendResponse.data.updates?.updatedRange;
const [, range] = updatedRange.split('!');
const indexes = convertSheetNotation(range);
await sheets.spreadsheets.batchUpdate({ auth: jwtClient, spreadsheetId, requestBody: {
requests: [
{
createDeveloperMetadata: {
developerMetadata: {
location: {
dimensionRange: {
sheetId: 0,
startIndex: indexes[0],
endIndex: indexes[0] + 1,
dimension: "ROWS"
}
},
metadataKey: 'batchId',
metadataValue: '$BATCH_ID',
visibility: "DOCUMENT"
}
}
}
]
}});
}
}
We need to be careful of race conditions as we may end up with duplicated rows, let me know if that helps :)
I had the same requirement.
First:
Create a function that gets the index of targeted object from the sheet, like:
private int getRowIndex(TheObject obj, ValueRange response) {
List<List<Object>> values = response.getValues();
int rowIndex = -1;
int i = 0;
if (values != null) {
for (List row : values) {
i += 1;
if (row.get(1).equals(obj.getBatchId())) {
System.out.println("There is a match! i= " + i);
rowIndex = i;
}
}
}
return rowIndex;
}
Second:
Create the update method by passing the targeted object having your desired value "batch id" and others new values for the rest of fields.
public void updateObject(Object obj) throws IOException, GeneralSecurityException {
sheetsService = getSheetsService();
ValueRange response = sheetsService.spreadsheets().
values().get(SPREADSHEET_ID, "Sheet1").execute();
int rowIndex = this.getRowIndex(obj, response);
if (rowIndex != -1) {
List<ValueRange> oList = new ArrayList<>();
oList.add(new ValueRange().setRange("B" + rowIndex).setValues(Arrays.asList(
Arrays.<Object>asList(obj.getSomeProprty()))));
oList.add(new ValueRange().setRange("C" + rowIndex).setValues(Arrays.asList(
Arrays.<Object>asList(obj.getOtherProprty()))));
//... same for others properties of obj
BatchUpdateValuesRequest body = new BatchUpdateValuesRequest().setValueInputOption("USER_ENTERED").setData(oList);
BatchUpdateValuesResponse batchResponse;
batchResponse sheetsService.spreadsheets().values().batchUpdate(SPREADSHEET_ID, body).execute();
} else {
System.out.println("the obj dont exist in the sheet!");
}
}
Finally:
In your app you have to pass the tageted object to the update method:
TheObject obj = new Object();
obj.setBatchId = "some value";
Fill the obj with others values if you want.
Then call the method:
objectChanger.updateObject(obj);
All you need to do is to create a new array of strings from an array of arrays - so you can run the indexOf() method on this new array.
Since we know the method values.get returns array of the arrays such as
[
[""],
[""],
...
]
my approach was to a bit flattened this structure.
const data = await googleSheetsInstance.spreadsheets.values.get({
//here u have to insert auth, spreadsheetId and range
});
//here you will get that array of arrays
const allData: any[] = data.data.values;
//Now you have to find an index in the subarray of Primary Key (such as
//email or anything like that
const flattenedData = allData.map((someArray: any[]) => {
return someArray[2]; //My primary key is on the index 2 in the email
Array
});
So what you will get is a normal array of strings with primary keys so now you can easily call the indexOf() on the flattened array.
const index:number = flattenedData.indexOf("someuniquestring);
console.log(index);
And the index value will tell you the row. Do not forget spreadsheets start from 1 and indexes in Javascript start from 0.

Parse JSON with optional field

I'm trying to parse in android studio a JSON, that containts this :
"stops":
[
{
"num": 1,
"time": "2016-04-27T06:15:00.000Z",
"title":"Flight to London",
"desc":"Barcelona BCN-London-Gatwick LGW",
"type":"0",
"subtype":0
},
{
"num": 2,
"time": "2016-04-27T10:35:00.000Z",
"title":"Gatwick express",
"desc":"From Airport to London",
"type":"0",
"subtype":1
},
{
"num": 3,
"time": "2016-04-27T12:15:00.000Z",
"title":"Pub the black horse",
"desc":"From Airport to London",
"type":1,
"subtype":1,
"location": "51.476334, -0.062700",
"images": [ "https://fitzrovianews.files.wordpress.com/2011/01/black_horse_rathbone_pl.jpg"
]
},
{
"num": 4,
"time": "2016-04-27T12:16:47.000Z",
"title":"The Tower Bridge",
"desc":"# The Tower Bridge Facts\n## Architecture\n**Tower Bridge** is a combined bascule and suspension bridge in London built in _1886–1894_. The bridge crosses the River Thames close to the Tower of London and has become an iconic symbol of London. Tower Bridge is one of five London bridges now owned and maintained by the Bridge House Estates, a charitable trust overseen by the City of London Corporation. \n>It is the only one of the Trust's bridges not to connect the City of London directly to the Southwark bank, as its northern landfall is in Tower Hamlets.\n## The bridge Exhibition\nThis must-see London attraction invites you to step inside the most famous bridge in the world to explore its iconic structure, spectacular views and glass floor, modern exhibitions and magnificent Victorian Engine Rooms! ",
"type":1,
"subtype":6,
"location": "51.507792, -0.087786",
"images": [
"https://i.ytimg.com/vi/nby0Mr2LfBQ/hqdefault.jpg",
"http://raindropsofsapphire.com/wp-content/uploads/2011/10/london-bridge.jpg",
"http://www.londonforfree.net/gizmo/wp-content/uploads/2015/02/southwark-bridge.jpg"
]
},
{
"num": 5,
"time": "2016-04-27T12:18:10.000Z",
"title":"St. Paul Cathedral",
"desc":"# HISTORY \nSt **Paul's Cathedral**, London, is an _Anglican cathedral_, the seat of the _Bishop of London_ and the mother church of the Diocese of London. \n * It sits on Ludgate Hill at the highest point of the City of London and is a Grade 1 listed building. \n * Its dedication to Paul the Apostle dates back to the original church on this site, founded in AD 604.",
"type":1,
"subtype":6,
"location": "51.513825, -0.098351",
"images": [
"https://d1wgio6yfhqlw1.cloudfront.net/sysimages/product/resized6/Interior_St_Pauls_Cathedral_132_12992.jpg",
"https://d1kioxk2jrdjp.cloudfront.net/resized/486x324/48-st_pauls_ctahedral_millenirm_bridge.jpg",
"http://i4.mirror.co.uk/incoming/article8299330.ece/ALTERNATES/s615b/LOND-2016-052-HMQ-St-Pauls-Thanks-Giving-704JPG.jpg"
]
}
]
The problem is, i don't know how to deal with the field "location" or "images" which are optional. I know how to deal with the first "stop", i'm doing this :
JSONArray stops = jsonObj.getJSONArray("stops");
for (int i = 0; i < stops.length(); i++) {
JSONObject c = stops.getJSONObject(i);
String num = c.getString("num");
String time = c.getString("time");
String title = c.getString("title");
String descripcion = c.getString("desc");
String type = c.getString("type");
String subtype = c.getString("subtype");
......
}
But i don't know how to check it here is a elment location or a jsonArray "images"...
best way to handle optional fields in JSON is to use opt instead of get
opt provides the parsed value if exist or default value for that datatype if requested key does not exist.
best thing is, it don't even need a try catch block since it always returns a value and in case of any error from server, it will not let your app crash or prevent other values from being parsed.
String location = response.optString("location");
if location exist in response, then it will initialize with the value or it will leave the string null. in case of int or long default is 0, in case of boolean default is false. read about opt for more details.
Use has() method
JSONArray stops = jsonObj.getJSONArray("stops");
for (int i = 0; i < stops.length(); i++) {
JSONObject c = stops.getJSONObject(i);
String num = c.getString("num");
String time = c.getString("time");
String title = c.getString("title");
String descripcion = c.getString("desc");
String type = c.getString("type");
String subtype = c.getString("subtype");
if(c.has("location") && !c.isNull("location")){
// parse location
}
if(c.has("images") && !c.isNull("images")){
// parse images
}
.....
}
you should use Retrofit and Google Gson, where you do not have to do lot of work,
they will do the job for you.
look at these
https://guides.codepath.com/android/Consuming-APIs-with-Retrofit
http://www.vogella.com/tutorials/Retrofit/article.html

Filter array field in couchbase

I m working on couchbase lite android.
I have series of documents, every document contains a field which it's value is array of string.
now I want to filter value of this field.
{
type : "customer",
name: "customerX",
states: [ "IL" , "IO" , "NY" , "CA" ]
},
{
type : "customer",
name: "customerY",
states: [ "WY" , "CA", "WA" ]
},
{
type : "customer",
name: "customerZ",
states: [ "NY" ]
}
I want to get customer documents which have "CA" in their states field.
I m using CBL Android.
emit(states , null);
then how could I make my Start and End Key option.
startkey("CA")
Or
startKey(["CA"])
customerX customerY
how can i get only customerX and customerY by "CA" in their states field ?!
If you are just wanting to filter on one state then your best solution would be to make a view like this:
function (doc, meta) {
if(doc.type && doc.type == "customer") {
if(doc.states) {
for (index = 0, len = doc.states.length; index < len; ++index) {
emit(doc.states[index],null);
}
}
}
}
This view will emit a view row for each state in the arrays of each of your documents of type 'customer'. This means that you can then select an individual state with a startkey of "CA" and an endkey of "CA", remember to set the inclusive_true flag to true so that endkeys that match are included:
startkey="CA"&endkey="CA"&inclusive_end=true
Hope that helps!

json parsing without name in android

i have worked with json name value pair before works fine and great but below is my json object in which there is no name and only value. Can anyone tell is it possible to use this type of json in android if yes then how to extract values from this json object. or any related link will be great.
JSON OBJECT
{
"log_list": [
[
"21",
"doctorFisher",
"Pharmacy 1",
"patientfish",
"test",
"2014-08-25 05:58:18",
"record UCI tech FDNY icky shut rack soon sun TDK tell. ox it'll ohm URL did GCVO dash ugly dog did flood idiot fluff if if rid t-shirts didn't TechTV only chef doc scotch Rebekah an if lb tax scotch am ICN JCB JCB HGV JCB HGV in on pm tax UDC OK red uh HK ohm",
"<img id=\"prescription_image\" onClick=showPrescriptionDetails(\"3c59dc048e8850243be8079a5c74d079\") onmouseover=\"this.style.cursor='pointer'\" src=\"\" width=\"20\" height=\"20\">"
],
[
"20",
"doctortest12345",
"Pharmacy 1",
"testpatient12345",
"test",
"2014-08-25 03:57:32",
"she'd Urdu text scuff uno dad uno each ink why tough days ICO saved USCIS David rig though end FDIC UCI's for USCIS tend did for dog such vidi fly floor exited did DND hand bid GMD.",
"<img id=\"prescription_image\" onClick=showPrescriptionDetails(\"98f13708210194c475687be6106a3b84\") onmouseover=\"this.style.cursor='pointer'\" width=\"20\" height=\"20\">"
]
}
thanks in advance
Yes, that format would work and you can pretty easily use it.
Assuming you have a variable String json which contains that data:
JSONObject jsonObj = new JSONObject(json);
Now log_list would be parsed as a JSONArray like so:
JSONArray logJsonArray = jsonObj.getJSONArray("log_list");
Then you can iterate through that outer array very similar to how you would a normal array or ArrayList:
for(int outerArrayPos = 0; outerArrayPos < logJsonArray.length(); outerArrayPos++){
JSONArray innerArray = logJsonArray.getJSONArray(outerArrayPos);
for(int innerArrayPos = 0; innerArrayPos < innerArray.length(); innerArrayPos++){
String valueAtIndex = innerArray.getString(innerArrayPos); //innerArray
// Do whatever you want with the values here
}
}
That will parse your String, but figuring out how to actually use that data is going to be most of your struggle, so I hope the order in which the information is returned will always be the same for your sake.
If you can, I would definitely recommend using a JSONObject for the data that is currently contained in your inner array. e.g.
{
"log_list": [
{
"id": "21",
"name": "doctorFisher",
.....
}
]
}

web service call causing my app to crash

Hi all I am trying to integrate a webservice in Titanium but when I press the button to call it my log is terminated and my app freezes. I am getting no error messages. Below is my code:
Post_array.push({
variable1:value1,
variable2:value2
variable3:value3
});
var AddJobURL="http:/NUMBERS/MytestURL";
var AddJobxhr=Titanium.Network.createHTTPClient();
AddJobxhr.onload=function(){
console.log("Response text ----------------------"+ this.responseText);
var doc= JSON.parse(this.responseText);
};
AddJobxhr.onerror=function(e){
alert(e.error);
};
AddJobxhr.open('POST', AddJobURL);
AddJobxhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
AddJobxhr.send(Post_array);
EDIT: I've realised the problem. My issue is my Post_array. What I am currently doing is pushing 4 items to an array on a button click and then pushing an additional 4 items on a second different button click and then posting this array but the array at his point is [object Object],[object Object] I think this is my issue? Any ideas how to solve?
The format of the sending data is not correct here I guess.
Below is the format in which you need to send the data:
AddJobxhr.send({
variable1: "value1",
variable2: "value2"
});
Where as Post_array is an array and not in the above format.
You should do something like:
var Post_array = {};
Post_array = $.extend(Post_array, {
"variable1": "value1",
"variable2": "value2",
"variable3": "value3"
});
Post_array = $.extend(Post_array, {
"variable4": "value4",
"variable5": "value5",
"variable6": "value6"
});
AddJobxhr.send(Post_array);
Alternatively you can do:
var Post_array = {};
// Doesn't have to be in quotes it's just the value you assign, strings are in quotes
// where as integers are not. Let us assume that value1, valu2 and value3 are the
// variable and they can hold anything;
Post_array["variable1"] = value1;
Post_array["variable2"] = value2;
Post_array["variable3"] = value3;
Post_array["variable4"] = value4;
Post_array["variable5"] = value5;
Post_array["variable6"] = value6;
AddJobxhr.send(Post_array);

Categories

Resources