Retrieving information from nested lists (Flutter) - list

I have what appears to most likely be a simple problem for everyone else, yet for some reason I can't seem to fix. I am a complete Flutter noob, but with coding experience. I am hoping to get tips around structuring data, and I have created a list which houses another list, like so:
class Store{
final String name;
final String image;
final List <Product> products; // this is defined in another class, and it requires a name(string), description(string), price (double)
Store({required this.name, required this.image, required this.features, required this.price})
List <Store> store= [
Store(name: "Ikea:, image: "ikealogo.png",
products :[Product(name: "wood table", description: "a very nice wood table", price: 12.50),
Product(name: "comfy chair", description: "a very nice leather chair", price: 10.50),
Product(name: "awesome lamp", description: "an ultra bright lamp", price: 5.50),]),
Store(name: "Bestbuy:, image: "bestbuylogo.png",
products :[Product(name: "television", description: "a very nice television", price: 350.00),
Product(name: "radio", description: "a very loud radio", price: 15.50),
Product(name: "cellphone", description: "a very small phone", price: 78.50),]),
];
}
Basically I have like 20 more of these things, following the same format.
Now for my problem, I can't seem to create a list out of the "Product" info nested within "Store". I can create lists with Store just fine, and I can call on the name and logo for all parts of the UI. My challenge is getting the Product information after a Store is selected, as the code I use currently shows "Iterable" when I hover over it. On the other hand, I get "List" just fine when I define or call the store list on another route.
#override
Widget build(BuildContext context) {
final product = Store.store.map((store) {
final productlist = store.products.toList();
});
I know that my code may not make any sense, and you can give me any kind of recommendations to alter the data structure altogether. For now (without using databases just yet), I want to show what products are available based on the store selected.
I hope everyone has a safe and productive day. Thank you!

In the example below I have set up a drop down button to show the list of stores. Selection causes a repaint which show the products in the selected store.
Hope the helps.
class _MyHomePageState extends State<MyHomePage> {
int _storeIdx = 0;
Store get _currentStore => storeList[_storeIdx];
List<Store> storeList = [
Store(name: "Ikea:", image: "ikealogo.png", products: [
Product(name: "wood table", description: "a very nice wood table", price: 12.50),
Product(name: "comfy chair", description: "a very nice leather chair", price: 10.50),
Product(name: "awesome lamp", description: "an ultra bright lamp", price: 5.50),
]),
Store(name: "Bestbuy:", image: "bestbuylogo.png", products: [
Product(name: "television", description: "a very nice television", price: 350.00),
Product(name: "radio", description: "a very loud radio", price: 15.50),
Product(name: "cellphone", description: "a very small phone", price: 78.50),
]),
];
#override
Widget build(BuildContext context) {
int _offset = 0;
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
DropdownButton(
value: _storeIdx,
items: storeList
.map((Store s) => DropdownMenuItem(
child: Text(s.name),
value: _offset++,
))
.toList(),
onChanged: (int? value) {
setState(() {
_storeIdx = value ?? 0;
});
},
hint: const Text('Select store')),
Text("Currently ${_currentStore.name}"),
..._currentStore.products.map((Product p) => Text(p.name)).toList(),
],
),
),
);
}
}
Note that the spread operator ... is quite useful when you are trying to flatten a hierarchy of widgets.
Also, sometimes in Flutter, there is a tendency to have one humongous build method. Sometimes it is clearer to break a screen in separate widgets or to break the build method into several methods each returning an array of widgets that can then be consolidated in the build method.

I can't help but notice that store inside of Store class is not a static variable which means Store.store should not be accessible. However, if store were a static variable inside Store class Store.store will work.
So,
class Product {
String name;
Product(this.name);
#override
String toString() {
return "Product($name)";
}
}
class Store {
List<Product> products;
Store(this.products);
static List<Store> stores = [
Store([
Product("Soap"),
Product("Bar"),
]),
Store([
Product("Sponge"),
Product("ChocoBar"),
]),
];
}
void main() {
print(Store.stores[0].products);
print(Store.stores[1].products);
}
Will yield an output of :
[Product(Soap), Product(Bar)]
[Product(Sponge), Product(ChocoBar)]
which is what we expect to find.

Related

ChartJS 4 migration: access other datasets from tooltip callback

I'm migrating from ChartJS 2.9.3 to 4.2.1 (current). By following the 3.x and 4.x migration guides, I've sorted most things out, but I've come across a problem that I don't see a solution for.
One of my charts is a stacked bar chart. There are two datasets for it:
let chartData = {
// other stuff...
datasets: [
{ label: "Has thing", data: [200, 250, etc] },
{ label: "Does not has thing", data: [10, 4, etc] },
]
}
In my tooltips, I was accessing both datasets to create a custom tooltip with the percent representation of each part of each stack. For instance, the tooltips for the first stack might say: "Has thing: 200 (95.2%)" and "Does not has thing: 10 (4.8%)". My callback function looked like this:
// other stuff
callbacks: {
label: function(tooltipItem, data) {
let dataset = data.datasets[tooltipItem.datasetIndex];
let count_with = data.datasets[0].data[tooltipItem.index]
let count_without = data.datasets[1].data[tooltipItem.index]
let total = count_with + count_without
let this_dataset_count = dataset.data[tooltipItem.index]
let this_dataset_perc = (this_dataset_count / total * 100).toFixed(1)
let label = dataset.label + ": "
label += this_dataset_count + " (" + this_dataset_perc + "%)"
return label;
}
}
Looking at the 3.x migration guide, it appears they removed the data parameter from the tooltip callback, opting instead to add the item's dataset directly to the tooltipItem. Unfortunately, they don't seem to specify how I can access other datasets.
Has this functionality simply been removed completely, or is there a different way to access it?
As #kikon pointed out, data is accessible via context.chart.data. For some reason, that doesn't show up for me when I console.dir() the context object so I was just completely overlooking it.
Anyway, for anyone this might help in the future, here's the working version:
callbacks: {
label: function(context) {
const datasets = context.chart.data.datasets
const countWith = datasets[0].data[context.dataIndex]
const countWithout = datasets[1].data[context.dataIndex]
const perc = (context.raw / (countWith + countWithout) * 100).toFixed(1)
return `${context.dataset.label}: ${context.formattedValue} (${perc}%)`
}
}

Plotting multiple lines on a Cube.js line graph

Imagine a simple line graph plotting a person count (y-axis) against a custom time value (x-axis), as such:
Suppose you have another dimension, say specific groupings of people, how do you draw a separate line on this graph for each group?
You have to use the PivotConfig here an example I used in Angular
(EDIT) Here is the Query
Query = {
measures: ['Admissions.count'],
timeDimensions: [
{
dimension: 'Admissions.createdDate',
granularity: 'week',
dateRange: 'This quarter',
},
],
dimensions: ['Admissions.status'],
order: {
'Admissions.createdDate': 'asc',
},
}
(END EDIT)
PivotConfig = {
x: ['Admissions.createdDate.day'],
y: ['Admissions.status', 'measures'],
fillMissingDates: true,
joinDateRange: false,
}
Code to extract data from resultset :
let chartData = resultSet.series(this.PivotConfig).map(item => {
return {
label: item.title.split(',')[0], //title contains "ADMIS, COUNT"
data: item.series.map(({ value }) => value),
}
})
Result Object (not the one in the chart):
[{
"label": "ADMIS",
"data": [2,1,0,0,0,0,0]
},{
"label": "SORTIE",
"data": [2,1,0,0,0,0,0]
}]
Here is what the output looks like!
The chart renderer in the Developer Playground is meant to be quite simplistic; I'd recommend creating a dashboard app or using one of our frontend integrations in an existing project to gain complete control over chart rendering.

Making TabBarView dynamically in flutter

Situation:
I have two lists,tabsText and mainListAllPlantDetailsList1.
tabsText
List<String> tabsText = ["Top","Outdoor","Indoor", "Seeds", "Flowers"];
mainListAllPlantDetailsList1
List<PlantDetails> mainListAllPlantDetailsList1 = [
PlantDetails(
indexNumber: 0,
category: "flower",
plantName: "Lamb's Ear",
price: 147,
description: "This is the Lamb's Ear flower"
),
PlantDetails(
indexNumber: 1,
category: "seeds",
plantName: "Lotus",
price: 120,
description: "This is the lotus seeds"
),
PlantDetails(
indexNumber: 2,
category: "indoor",
plantName: "Hughusi Yoon",
price: 147,
description: "This is the Hughusi Yoon indoor"
),
PlantDetails(
indexNumber: 3,
category: "outdoor",
plantName: "lily",
price: 120,
description: "This is the lily outdoor"
),
];
Details:
I have made the TabBar using for loop in the tabsText list. Now I am again making the TabBarView using for loop and I tried like this
tabViewerMaker(){
List<Widget> tabBarView = List();
for(var i = 0; i<tabsText.length;i++){
for( var j =0; j<mainListAllPlantDetailsList1.length;j++){
if(tabsText[i] == mainListAllPlantDetailsList1[j].ca){
tabBarView.add(
Text("We found category"+tabsText[i])
);
}
else{
continue;
}
}
}
}
Here, I have checked the tabsText and mainListAllPlantDetailsList1. If the String of particular index of tabsText is equal to particular index of mainListAllPlantDetailsList1 then, generate a widget,
Text("We found category"+tabsText[i])
otherwise just continue. And I have made a list of type widget and added all the text widget, but while calling the function tabViewerMaker Why does it give error?
══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
The following NoSuchMethodError was thrown building Container(bg: BoxDecoration(color:
Color(0xffffffff)), constraints: BoxConstraints(w=Infinity, h=317.0)):
The getter 'key' was called on null.
Question:
How can I achieve the desired function using for loop or feel free to give any suggestion?

Display items in a list containing a specific name - flutter

In this list, I want to display out all the items that contains this specific name.
My list items: ['US', 'SG', 'US']
print(list.contains("US"));
Using .contains() returns me a true or false but it doesn’t return me the list of strings that contains that. I want to only extract out the items that has 'US' from the list. In this case, there's 2 of it. Please help!
You can try doing it the following way -
List<String> myList = ['US', 'SG', 'US'];
print(myList.where((item) => item.contains("US")));
You can also display it directly inside a Text widget in the following way -
Text(
myList.where((item) => item.contains("US")).join(" "),
//The join function joins the elements of the Iterable into a single string with the separator provided as an argument.
),
Hope this helps!
UPDATE:
To display each of the word separately as a list you can display them inside a Column in the following way -
Column(
children: myList.map((value) {
if(value.contains("US")){
return Text(value,);
} else {
return Container();
//Return an empty Container for non-matching case
}
}).toList(),
)
The same thing can be used inside a ListView instead of Column if you want it to be scrollable.
Something like this?
var myList = ['US', 'SG', 'US'];
myList.forEach((w){
if(w == "US")
print(w);
});
To show:
class SO extends StatelessWidget {
var myList = ['US', 'SG', 'US'];
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisSize: MainAxisSize.min,
children: myList.where((w) => w == "US").map((w) => Text(w)).toList(),
),
);
}
}
or for a single line display use, Text instead of Column widget mentioned above
Text(myList.where((w) => w.contains("US")).join(" "))
If you are using "list.contains". It will only show the list exist or not , If you want to print the value you have to use follow :
var fruits = [‘banana’, ‘pineapple’, ‘watermelon’];fruits.forEach((fruit) => print(fruit)); // => banana pineapple watermelon
If you want to print just banana then you can use this
var fruits = [‘banana’, ‘pineapple’, ‘watermelon’];fruits.(fruit) => print(fruit[0]); // => banana

Rails, Highchart maps - adding custom data

I need some basic assistance with a Highmap (via Highcharts) I am trying to put in my Rails 4 app. I suspect I have some fundamental misunderstanding of it but can't find any clear guidance.
See a simple fiddle taken from the documentation, here
http://jsfiddle.net/SimonWalsh/zpdc1btu/
What I ultimately need to do is provide membership numbers for each country so that it will be displayed much the same as the population density is in this map.
I know I need to provide my data and the means to join it to the map data in
series : [{
data : data,
mapData: Highcharts.maps['custom/world'],
joinBy: ['iso-a2', 'code'],
name: 'Population density',
states: {
hover: {
color: '#BADA55'
}
}
}]
In this example, I am guessing that the data is being pulled from an external source and that the map data is the 'iso-a2' part of the array.
If this is the case, then why can't I supply this with my data....as an example see the added array with my data.....(just one example given for Denmark)
var mydata = [
{
"iso-a2": "dk",
"value": 30
},
]
and then do
series : [{
data : mydata,
mapData: Highcharts.maps['custom/world'],
joinBy: ['iso-a2', 'value'],
name: 'Population density',
states: {
hover: {
color: '#BADA55'
}
}
}]
This does not work.....any guidance at all (other than simply pointing me to docs would be greatly appreciated)
The joinBy specifies on which value you map a country with your data. With
joinBy: ['iso-a2', 'code']
you say that the 'iso-a2' value of the mapData should be equal to the 'code' value of your data. Therefore, your data must have this format:
var mydata = [
{
"code": "dk",
"value": 30
},
/* ... */
]