Flutter Futurebuilder gets modified - list

I have a Futurebuilder that fetches data from an Api.
I am assigning its data to a list;
List<TicketModel> ticketList = [];`
ticketList = snapshot.data;
Now the weird thing is, snapshot.data and ticketList should be independent right?
However if I remove data from the List e.g I remove every Object that has the price 1 the snapshot.data modifies too(Has same data as list now).
Why is that so?
The Futurebuilder is in a Modal bottom sheet if that's necessary
void main() {
List<String> listofAllTickets =[];
listofAllTickets = ["ticket eins","ticket zwei", "ticket drei"];
List<String> listOfAllTicketsSecond = listofAllTickets;
listOfAllTicketsSecond.removeWhere((element) => element == "ticket eins");
print(listofAllTickets);
print(listOfAllTicketsSecond);
}

you need to use a futurebuilder and connect ticketlist to it. the futurebuilder will generate a snapshot in its callback function. you can not access the snapshot outside of the futurebuilder.
I prefer using Bloc and streambuilder. Streambuilder events occur when change occurs on the notification stream.

As #Jeppe posted in the comments what I did before was that:
void main() {
List<String> listofAllTickets =[];
listofAllTickets = ["ticket eins","ticket zwei", "ticket drei"];
List<String> listOfAllTicketsSecond = listofAllTickets;
listOfAllTicketsSecond.removeWhere((element) => element == "ticket eins");
print(listofAllTickets);
print(listOfAllTicketsSecond);
}
the right solution would be doing this:
void main() {
List listofAllTickets = ["ticket eins","ticket zwei", "ticket drei"];
List listOfAllTicketsSecond = [];
listOfAllTicketsSecond = List.from(listofAllTickets);
listOfAllTicketsSecond.removeWhere((element) => element == "ticket eins");
print(listofAllTickets);
print(listOfAllTicketsSecond);
}
In Example two I am copying the data instead of referencing the list.

Related

Flutter - how to store a list in GetStorage?

For each article the user browses, I want to save the ID information.
I am using getstorage my code sample is below.
I can not find a true way also, i am looking best way to save id's list.
final box = GetStorage();
List<String> myFavoriteList = [];
saveFav(String id) {
myFavoriteList.add(id);
box.write('favoriteArticles', myFavoriteList.cast<String>());
}
ifExistInFav(String id) async {
bool ifExists = false;
List<String> my = (box.read('favoriteArticles').cast<String>() ?? []);
ifExists = my.contains(id) ? true : false;
return ifExists;
}
First, you need to define your list and convert it to String.
** note that if you use a custom data type ensure you convert your model to String.
then you can use the following to store a List as a String object
final box = GetStorage('AppNameStorage');
/// write a storage key's value
saveListWithGetStorage(String storageKey, List<dynamic> storageValue) async => await box.write(/*key:*/ storageKey, /*value:*/ jsonEncode(storageValue));
/// read from storage
readWithGetStorage(String storageKey) => box.read(storageKey);
the saving procee implemention:
saveList(List<dynamic> listNeedToSave) {
/// getting all saved data
String oldSavedData = GetStorageServices().readWithGetStorage('saveList');
/// in case there is saved data
if(oldSavedData != null){
/// create a holder list for the old data
List<dynamic> oldSavedList = jsonDecode(oldSavedData);
/// append the new list to saved one
oldSavedList.addAll(listNeedToSave);
/// save the new collection
return GetStorageServices().saveListWithGetStorage('saveList', oldSavedList);
} else{
/// in case of there is no saved data -- add the new list to storage
return GetStorageServices().saveListWithGetStorage('saveList', listNeedToSave);
}
}
/// read from the storage
readList() => GetStorageServices().readWithGetStorage('saveList');
then the usage:
onTap: () async => debugPrint('\n\n\n read list items ${jsonDecode(await readList())}\n\n\n', wrapWidth: 800),

Put some ListB into ListA as items, then clear ListB and ListA is gone too

I have 2 List as I code here.
List<Detail> orderDetailList = List();
List<List> allOrders = List();
var result;
String tmpCustomerName;
My data came from my database as json, and here is some of my code.
await Dio().get(myURL).then((value) async {result = json.decode(value.data)});
for (var item in result) {
OrdersDetailModel ordersDetailModel = OrdersDetailModel.fromJson(item);
setState(() {
orders.add(ordersDetailModel);
customerName = ordersDetailModel.customerName;
customerPhone = ordersDetailModel.customerPhone;
var res2 = json.decode(ordersDetailModel.orderDetail);
for (var item2 in res2) {
Detail detail = Detail.fromJson(item2);
orderDetailList.add(detail);
}
allOrders.add(orderDetailList);
print('before $allOrders');
if (tmpCustomerName != customerName) {
orderDetailList.clear();
print('after $allOrders');
}
tmpCustomerName = customerName;
});
}
As I mentioned in my question part, when I use orderDetailList.clear() after added it to allOrders, the value in allOrders is gone too so allOrders has only empty list, as you can see I printed 'before' and 'after', the 'before' has value but 'after' does not. What am I doing wrong? Or how can I keep the value inside my allOrders list after clearing orderDetailList list?
This is the clear case of referencing error, you are doing. There is a concept called Shallow and Deep copy.
Shallow: It copies the item, but has some reference of the parent item. So when made any changes to either of them make changes in the other item. Which you are doing right now
Deep Copy: This is the copy method, where there is no reference to the parent variable. Which we have to do
So, let us quickly jump in the code:
// rather than doing add directly from orderDetailsList
// we add the data to the tempList holding the Details list,
// and then add it to the data
for (var item2 in res2) {
Detail detail = Detail.fromJson(item2);
orderDetailList.add(detail);
}
// this will keep the data into the list
List<Detail> tempList = [];
// traversing the item from orderDetailsList
orderDetailList.forEach((item) => tempList.add(item));
// here you add the tempList now holding the data
allOrders.add(tempList);
Read about List.forEach(). It will give you some concept clarity about the method.

Flutter add item to list

I would like to add an item to a list:
void submitAll() async {
List<UserSearchItem> userSearchItems = [];
Firestore.instance
.collection('insta_users')
.snapshots()
.listen((data) =>
data.documents.forEach((doc){
print(data.documents.length);
User user = new User.fromDocument(doc);
UserSearchItem searchItem = new UserSearchItem(user);
userSearchItems.add(searchItem);
print(user.bio);
}));
print("Loaded");
print(userSearchItems.length);
}
But if I print the length of the list to the console, it always says, the list is 0 long...
print(userSearchItems.length);
Any suggegstions?
Best Regards
I will try to give an explanation of what is happing here take a look on this code:
import 'dart:async';
void main() {
List<int> userSearchItems = [];
Timer _sendTimeOutTimer;
const oneSec = Duration(seconds: 2);
_sendTimeOutTimer = Timer.periodic(oneSec, (Timer t) {
userSearchItems.add(1);
print(userSearchItems.length); // result 1 and it will be executed after 2 seconds
_sendTimeOutTimer.cancel();
});
print(userSearchItems.length); // result 0 and it will be executed first
}
The print inside asynchronous action(Timer) it will be executed after 2 seconds means after the asynchronous action ends but the one which is outside of asynchronous action(Timer) it will be executed directly without waiting 2 seconds, in your case the asynchronous action is listening to data .listen((data) =>, so if you print the length outside of your asynchronous action you will not see the deferent because the item is not added yet.
Solution: you can create function witch return Future and then wait until it's finished then print the length.
List<UserSearchItem> userSearchItems = [];
Future<String> submitAll() async {
Firestore.instance
.collection('insta_users')
.snapshots()
.listen((data) =>
data.documents.forEach((doc){
print(data.documents.length);
User user = new User.fromDocument(doc);
UserSearchItem searchItem = new UserSearchItem(user);
userSearchItems.add(searchItem);
print(user.bio);
return 'success';
}));
}
void yourFunction() async{
await submitAll();
print("Loaded");
print(userSearchItems.length);
}
Then call yourFunction().
Try to add print(userSearchItems.length); inside forEach after adding the item and you will see the real length.
There is a simple way tu add new data tu a list on Flutter.
for (var i = 0; i < list.length; i++) {
double newValue=newValue+1; //This is just an example,you should put what you'r trying to add here.
list[i]["newValueName"] = newValue; //This is how we add the new value tu the list,
}
See if it work by doing a:
print(list);//You can put a breakpoint her to see it more clearly
Hope it helps.

Numbered lists continues when Apps Script appends template-content into document

I have an Apps Script that copies the content of an template-file to the end of a document. It works with one minor annoyance: the numbered list continues from one copy to the next.
I have many different templates that users can append to the end of the document. Each template is stored in its own Document.
function addSub(template_id){
var mainBody = DocumentApp.getActiveDocument().getBody();
var tempBody = DocumentApp.openById(template_id).getBody();
for(var i = 0;i<tempBody .getNumChildren();i++){
var element = tempBody .getChild(i);
if(element.getType() == DocumentApp.ElementType.TABLE)
mainBody.appendTable(element.copy());
else if(element.getType() == DocumentApp.ElementType.PARAGRAPH)
mainBody.appendParagraph(element.copy());
else if(element.getType() == DocumentApp.ElementType.LIST_ITEM)
mainBody.appendListItem(element.copy());
else if(element.getType() == DocumentApp.ElementType.PAGE_BREAK)
mainBody.appendPageBreak(element.copy());
}
}
It could look like this: ( I want the list to reset for each new copy of the template)
table with name of this template
some raw text
List item1
List item2
table with name of this template
some raw text
List item1
List item2
Do you now that ListItems have an ID, which is a STRING and you can access it via myListItem.getListId().
It seems that all your ListItems have the same ID.
If this is the case, the numbering has to be as you described.
Why do they have the same ListID?
I don't know.
Seems that the body.appendListem method always chooses the same listId.
I didn't test it yet, but you could try to set the listID of the newly append ListItem to that of the original document, if they are different.
Yes, i know, the .copy() method should enclose this information, but the body.appendListItem method may not care.
So, you could try to first save the detached copy of the listItem.
Then append it to the new body.
And then set the id of the newly appended listItem to that of the detached copy.
It's stupid, i know, but it may help.
Didn't try it yet.
And i have little experience with listItems, bit what i saw up to now is that there seems to be only one ListId in the body of a document, if you append or insert listItems.
This could be the cause of the problem.
Hope this helps.
After Richard Gantz solved it, It was corrected by this code:
var listItemDictionary = {};//top
...
else if(element.getType() == DocumentApp.ElementType.LIST_ITEM){
var listCopy = element.copy().asListItem()
var lcID = listCopy.getListId();
if (listItemDictionary[lcID] == null){
var tempLI = mainBody.appendListItem("temp")
listItemDictionary[lcID] = tempLI;
}
Logger.log(lcID)
mainBody.insertListItem(childIndex+j, listCopy.setListId(listItemDictionary[lcID]));
}
...
if(listItemDictionary){//bottom
mainBody.appendParagraph("");
for(var key in listItemDictionary){
listItemDictionary[key].clear().removeFromParent()
}
}
Based on the answer from Niklas Ternvall/Richard Gantz, I found a simpler solution for the case of each template having no more than one list.
function addSub(template_id) {
var mainBody = DocumentApp.getActiveDocument().getBody();
var tempBody = DocumentApp.openById(template_id).getBody();
var listID = null;
for(var i = 0;i<tempBody.getNumChildren();i++){
var element = tempBody.getChild(i).copy();
var type = element.getType();
if(type == DocumentApp.ElementType.TABLE)
mainBody.appendTable(element);
else if(type == DocumentApp.ElementType.PARAGRAPH)
mainBody.appendParagraph(element);
else if(type == DocumentApp.ElementType.LIST_ITEM){
if(listID==null) // First list item
listID = mainBody.appendListItem('temp'); // Define new listID
mainBody.appendListItem(element).setListId(listID); // Apply to copy
}
else if(type == DocumentApp.ElementType.PAGE_BREAK)
mainBody.appendPageBreak(element);
}
mainBody.removeChild(listID); // Delete temporary list item
}
Each time you call the function, listID=null is the indicator for whether or not there have been any list items in the template. When you get to the first list item, appending the text 'temp' forces a new list and hence a new listID that you can apply to the list items from the template. After you finish going through the template, mainBody.removeChild(listID) removes 'temp' from the top of your list.
This solution worked for me when using one template 100 times in one document, essentially as a mail merge. I'm fairly new to Apps Script, so I would appreciate any feedback if there is a reason this wouldn't work for a single-list template.

Retrieve count of SelectList items?

Problem: I can't access the count of items in a SelectList
I have an HtmlHelper method that returns a SelectList:
public static SelectList FilterSelectList(this HtmlHelper helper, List<Stuff> eList, string dept)
{
List<Stuff> returnList = new List<Stuff>();
//Do Stuff
return new SelectList(returnList, "ID", "Name");
}
I then have a test which confirms that the filter was done correctly:
// Arrange
List<Stuff> eList = MVCMocks.GetList();
string dept = "T";
int expectedCount = eList.FindAll(e => e.Dept == dept).Count;
// Act
var actual = HtmlHelpers.FilterSelectList(helper, eList, dept);
// Assert
Assert.AreEqual(expectedCount, actual.Count, "The list was not properly filtered.");
Calling actual.Count results in an error.
I'm hoping this is just a case of me having a stupid oversight, but I've been banging my head on this for a while. Prove me right! :)
EDIT: Stuff I've Tried
actual.Count
actual.Count()
actual.Items.Count()
actual.GetEnumerator().?
You need actual.Count() (note parens!) not actual.Count.