I am trying to copy values of one list to another,
I use three buttons 1st one to append a value to mylist, second one to clear the mylist, 3rd button to copy values from mynewlist to mylist.
i tried this
List<String> mylist = [
'Albania',
'Andorra',
'Armenia',
'Austria',
'Azerbaijan',
'Belarus',
'Belgium',
'Albania',
'Andorra',
'Armenia',
'Austria',
'Azerbaijan',
'Belarus',
'Belgium',
];
List<String> mynewlist = [
'Albania',
'Andorra',
'Armenia',
'Austria',
'Azerbaijan',
'Belarus',
'Belgium',
'Albania',
'Andorra',
'Armenia',
'Austria',
'Azerbaijan',
'Belarus',
'Belgium',
];
Padding(
padding: const EdgeInsets.all(5.0),
child: Row(
children: <Widget>[
Expanded(
child: FlatButton(
onPressed: () {
setState(() {
print('clicked 1st');
print(mylist.length);
print(mynewlist.length);
mylist.add('sdsds');
});
},
child: Container(
child: Column(
children: <Widget>[
Image.asset(
'images/bulb.png',
width: 100,
height: 100,
),
Text('bulb')
],
),
),
),
),
Expanded(
child: FlatButton(
onPressed: () {
setState(() {
print('clicked 2nd');
print(mylist.length);
print(mynewlist.length);
//after i set mylist = mynewlist; when i click this button it clears the old and new list.
mylist.removeRange(0, mylist.length);
});
},
child: Container(
child: Column(
children: <Widget>[
Image.asset(
'images/bulb.png',
width: 100,
height: 100,
),
Text('bulb')
],
),
),
),
),
Expanded(
child: FlatButton(
onPressed: () {
setState(() {
print('clicked 3rd');
print(mylist.length);
print(mynewlist.length);
mylist = mynewlist;
});
},
child: Container(
child: Column(
children: <Widget>[
Image.asset(
'images/bulb.png',
width: 100,
height: 100,
),
Text('bulb')
],
),
),
),
),
],
),
)
On the initial time it works perfectly the second time i click the second button it clears the mylist and mynewlist.
How can i copy the values of second list without clearing the new new list
Use myList = List.from(mynewlist); instead of mylist = mynewlist;
Thats because you copied the object references (mylist = mynewlist) and not the content of the list. So after the first click, mylist has a reference to the same object in memory as mynewlist. So any operation on one of them, affect both.
To solve your problem you need to keep the object references intact and just copy around the contents of these lists.
var YOURCOPY = YOURLIST.map((v) => v).toList();
use:
myNewList = [...myOldList]
it creates a shallow copy of items from myOldList to myNewList
for more information: you can search for 'spread operator in dart'.
You can also call method:toList() on any iterables (in this case List) which you want to create a copy of and not a reference.
Deep copy of a custom class List
If you have a list of classes, make sure to clone/copy each class. Otherwise, if you change objects in the original list, it will also change in the new one.
Here is one way to prevent it:
Add a clone() function to your class
class RandomObject {
RandomObject(this.x, this.y);
//add clone function to your class:
RandomObject.clone(RandomObject randomObject): this(randomObject.x, randomObject.y);
int x;
int y;
}
To copy, map through each element and clone it
final List<RandomObject> original = [RandomObject(1, 2), RandomObject(3, 4)];
final List<RandomObject> copy = original.map((v) => RandomObject.clone(v)).toList();
Related
I have a json list. from this i want to delete a particular item. Below is my code.
final List _vehicleList = [
{
'vehicleNumber': 'KL-14-V-5208',
'vehicleType': 'Two Wheeler',
},
{
'vehicleNumber': 'KL-13-H-8880',
'vehicleType': 'Four Wheeler',
},
{
'vehicleNumber': 'KL-14-M-6889',
'vehicleType': 'Three Wheeler',
},
];
This is my list. Here from this i want to delete the item based on vehicleNumber when i press a delete button. I'am using listview builder. When i print the list after the button press nothing happens
This is my UI Code.
return Column(
children: [
Padding(
padding: const EdgeInsets.all(12.0),
child: Text(
_vehicleList[index]['vehicleNumber'],
),
),
Padding(
padding: const EdgeInsets.all(12.0),
child: Text(
_vehicleList[index]['vehicleType'],
),
),
GestureDetector(
onTap: () {
print('Deleted');
_vehicleList.removeAt(_vehicleList[index]);
print(_vehicleList);
},
child: const Padding(
padding: EdgeInsets.all(12.0),
child: Icon(
FontAwesomeIcons.timesCircle,
color: Colors.redAccent,
),
),
),
],
);
You should change like this;
Before;
_vehicleList.removeAt(_vehicleList[index]);
after
_vehicleList.removeAt(index);
Documentation of how to use the "removeAt" method. https://api.flutter.dev/flutter/dart-core/List/removeAt.html
Try below code hope its help to you. just pass your index
_vehicleList.removeWhere((element) => element["vehicleNumber"] == 'KL-14-V-5208');
I have a list like this a = [{'one': 'one', 'two': null, 'three': [{'four': 'four'}]}]
I send it to a function to use it in a post request which in the body should receive a Map, so what I did was this to a[0], the problem is that I get this error The getter 'length' was called on null
I start to review and it treats all the property values as if they were Strings, even the nested list 'three': [{'four': 'four'}], I have tried to send the post in this way http.post (url, body: (recurrence [0] as Map)) but it has not worked, it always gives me the same error, even if in the body I put the properties by hand in the body: {'new property': a [0] [' tres']}, how should one act to solve this problem? Thank you very much for your help
Code:
void _ordersGet() async {
await http.get(url).then((value) {
setState(() {
orders = jsonDecode(value.body);
}
}
orders is sent to a new widget: orderList(orders)
orderList is a listView
ListView.builder(
shrinkWrap: true,
primary: false,
itemCount: orders.length,
itemBuilder: (orders, index) {
return return Card(
elevation: 5,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(orders[index]['facts']),
SizedBox(
width: 4,
),
Text('Cantidad : '),
Text(orders[index]['ITEMS'][0]['jeans']),
SizedBox(
width: 4,
),
IconButton(
onPressed: () => _reorderData(context, orders[index]),
icon: Icon(
Icons.replay_outlined,
color: Theme.of(context).accentColor,
)),
],
),
);
},
);
_reorderData is a function that make a get request, the info in shipped to ReorderModal
ReorderModal it only shows the information and has a button
void _reorderData(BuildContext ctx, order) async {
var data;
var url = 'serverAddress/${order['facts']}';
await http.get(url).then((value) {
data = jsonDecode(value.body);
data[0]['CORPORATION'] = order['corporation'];
showModalBottomSheet(
context: ctx,
builder: (_) {
return ReorderModal(data);
});
}).catchError((onError) {});
}
class ReorderModal extends StatelessWidget {
final List data;
ReorderModal(this.data);
void orderSend(orderInfo) async {
var url = 'serverAddress';
await http.post(url, body: orderInfo[0]).then((value) {
print(jsonDecode(value.body));
}).catchError((onError) {
print(onError);
});
}
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(10),
child: Column(children: <Widget>[
Row(
children: <Widget>[
Expanded(
child: Column(
children: [
ElevatedButton(
onPressed: () {
orderSend(data);
//print(data);
},
child: Text('ONE Click'))
]),
);
}
}
when i press the ONE Click button execute the function orderSend, orderSend make a post request and the problem described above
This is the simplified code, I know it must be something very simple, but it is giving me a lot of work to solve
The idea behind my code is to populate a Column widget with dynamic data I get from a list of objects
I use a List>> that's essentially just a list of objects.
My List :
List<List<Map<String, String>>> listCardsAll = [
[
{
"cardCate": "AMEX",
"cardDesc": "American Platinum 6",
"cardImg":
"images/AMEX/American-Express®-Green-Card-Earn-Rewards-Points.png"
}
],
[
{
"cardCate": "AMEX",
"cardDesc": "American Platinum 5",
"cardImg":
"images/AMEX/American-Express®-Green-Card-Earn-Rewards-Points.png"
}
],
];
Then I call a function within a column that returns a Widget(I want to return a List but it gives an error)
Widget:
Column(
children: <Widget>[
Row(
children: <Widget>[generateCardsALL()],
)
],
)
I Use a for-loop then in the function a make a widget with that dynamic data but it only returns one widget rather than the Collection that i was hoping for.
my Function :
Widget generateCardsALL() {
var count = 0;
for (var item in listCardsAll) {
count++;
if (count <= 2) {
return ReusableCards(
cardName: item[0]["cardDesc"],
cardLink: item[0]["cardImg"],
cardRowNum: count,
);
} else {
count = 0;
return ReusableCards(
cardName: item[0]["cardDesc"],
cardLink: item[0]["cardImg"],
cardRowNum: 3,
);
}
}
}
(The cardRowNum is only to see when its 3 cards next to each other that it can generate a new row)
This is the ReusableCards
ReusableCards:
class ReusableCards extends StatelessWidget {
final String cardLink;
final int cardRowNum;
final String cardName;
ReusableCards(
{#required this.cardLink,
#required this.cardRowNum,
#required this.cardName});
#override
Widget build(BuildContext context) {
// addToListcards(cardLink);
print("Inserted");
return (cardRowNum == 1 || cardRowNum == 2
? GestureDetector(
onDoubleTap: () {},
child: Padding(
padding: EdgeInsets.fromLTRB(0, 15, 15, 20),
child: Container(
width: MediaQuery.of(context).size.width * 0.24,
child: SizedBox(
child: Column(
children: <Widget>[
Image.asset(cardLink, fit: BoxFit.fill),
Text(cardName)
],
),
),
),
),
)
: cardRowNum == 3
? Padding(
padding: EdgeInsets.fromLTRB(0, 15, 0, 20),
child: Container(
width: MediaQuery.of(context).size.width * 0.24,
child: SizedBox(
child: Column(
children: <Widget>[
Image.asset(cardLink, fit: BoxFit.fill),
Text("" + cardRowNum.toString())
],
),
),
),
)
: SizedBox());
}
}
if I want to make it a List rather then just a widget it breaks. Can someone please help me with this dilemma
Try using map for iterating through the list and getting a list of widgets,
Example:
Column(
children: listCardsAll.map((oneCard){
return Container(
child: Text(oneCard.cardDesc)
);
}).toList(),
)
I think the problem is that inside of the function generateCardsALL. You don't return an array of Widgets, you should change to this.
List<Widget> generateCardsALL() {
var count = 0;
List<Widget> widgets;
for (var item in listCardsAll) {
count++;
if (count <= 2) {
widgets.add(ReusableCards(
cardName: item[0]["cardDesc"],
cardLink: item[0]["cardImg"],
cardRowNum: count,
));
} else {
count = 0;
widgets.add(ReusableCards(
cardName: item[0]["cardDesc"],
cardLink: item[0]["cardImg"],
cardRowNum: 3,
));
}
}
return widgets;
}
Hello I am having issue to understand how to manage properties of a class when it is part of a list of classes
Here are my classes
class BasketItem {
final String itemDescription;
final String itemNote;
BasketItem(
{this.itemDescription,
this.itemNote});
}
class AppData {
static final AppData _appData = new AppData._internal();
List<BasketItem> basketList = [];
factory AppData() {
return _appData;
}
AppData._internal();
}
final appData = AppData();
And here is my List
List<Container> _buildBasketList() {
return appData.basketList.map((bList) {
var container = Container(
child: Builder(
builder: (context) => Dismissible(
key: Key(UniqueKey().toString()),
background: Container(
margin: EdgeInsets.all(8.0),
color: kColorAccent,
child: Align(
alignment: Alignment(-0.90, 0.00),
child: Icon(Icons.add_comment)),
),
onDismissed: (direction) {
final newItemToAdd = BasketItem(
itemDescription: bList.itemDescription,
itemNote: 'xxxxx',);
appData.basketList.add(newItemToAdd);
setState(() {});
appData.basketList.remove(bList);
},
child: Stack(...)
),
),
);
return container;
}).toList();
}
I would like to do the following: when onDismissed get executed I would like to amend the property itemNote to 'xxxxx'. How can I do it? At the moment I remove the BasketItem I have swiped and I create a new BasketItem and I add it to the list. The problem is that this does not seem efficient and it also add the item at the end of the list while I would like to keep it at the same position/index where it was.
Thanks
Approach 1
Make fields in BasketItem non final. So you can amend them.
class BasketItem {
final String itemDescription;
/*final*/ String itemNote;
BasketItem(
{this.itemDescription,
this.itemNote});
}
// onDismissed will change itemNote.
....
onDismissed: (direction) {
setState(() {
bList.itemNote = 'xxxxx';
});
},
...
Approach 2
Replace list contents inline. Don't remove and add
List<Container> _buildBasketList() {
return appData.basketList.asMap().map((index, bList) {
var container = Container(
child: Builder(
builder: (context) => Dismissible(
key: Key(UniqueKey().toString()),
background: Container(
margin: EdgeInsets.all(8.0),
color: kColorAccent,
child: Align(
alignment: Alignment(-0.90, 0.00),
child: Icon(Icons.add_comment)),
),
onDismissed: (direction) {
setState(() {
appData.basketList[index] = BasketItem(
itemDescription: bList.itemDescription,
itemNote: 'xxxxx',);
});
},
child: Stack(...)
),
),
);
return container;
}).toList();
}
I have a hardcoded list that I want to map it to a list of widgets. The code below shows squiggly lines with the error The return type 'List<ItemWidget>' isn't a 'Widget', as defined by anonymous closure.dart(return_of_invalid_type_from_closure).
.................MISSING CODE....................
ListView.builder(
itemBuilder: (context, index) => items.map((item) => ItemWidget(item: item)).toList();
)
..................MISSING CODE....................
class ItemWidget extends StatelessWidget{
final Item item;
ItemWidget({this.item});
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Expanded(
child: FittedBox(
fit: BoxFit.fill,
child: Image.asset(item.iconPath)
)
),
Padding(
padding: const EdgeInsets.only(top: 15.0),
child: Text(item.name),
)
],
);
}
}
EDIT:
This is the list of items, currently I hold just an item for testing purposes.
List<Item> items = [
Item(name: 'Medicines', iconPath: '$ICON_BASE_PATH/medicines.svg'),
];
If you have any idea please let me know, thanks!
The issues is using the ListView.builder, the builder function expects you to return one Widget at a time corresponding to the index provided. Use ListView directly instead.
Example:
ListView(
children: items.map((item) => ItemWidget(item: item)).toList(),
);
Hope that helps!
If you want to use ListView.builder then you can use as following. This may helps you.
body: ListView.builder(
itemCount: items == null ? 0 : items.length,
itemBuilder: (BuildContext context, int index) {
return ItemWidget(
item: items[index],
);
},
),