Flutter GetX can't assign Set<CustomClass> to RxSet<CustomClass> - flutter

I am developing an application and came across a problem, which does not cause an error but pretty frustrating for me.
The situation is that I have an RxSet of CustomClass objects with default initialization to empty Set. When I fetch data from the server, I want to assign the result to this set. As GetX suggests, I should go like myRxSet = dataFetchedFromServer. This gives me a compile time error. myRxSet.value = dataFetchedFromServer still works, but gives an info that I should not assign to .value property.
A sample code can be seen bellow
RxSet<MyCustomClass> myCustomClassEntries = Set<MyCustomClass>().obs;
Future<void> syncData() async {
myCustomClassEntries = await _fetchDataFromServer(); // this gives me compile time error
myCustomClassEntries.value = await _ fetchDataFromServer(); // this gives me a warning that RxSet is not intented to be used this way.
}
GetX version: ^4.3.4
Flutter version: 2.2.3
Dart version: 2.13.4
Any idea what I'm doing wrong?
Edit
_fetchDataFromServer() does not matter in this situation, just wanted to give some context to the problem. As simple as it is:
RxSet<MyCustomClass> myCustomClassEntries = Set<MyCustomClass>().obs;
// This line gives me a compile time error. It says Set<MyCustomClass> can't be assigned to RxSet<MyCustomClass>
myCustomClassEntries = new Set<MyCustomClass>();
// This line works, just like everywhere else with GetX, but says .value is no longer intented to be used on RxList, RxSet or RxMap. It recommends to use the syntax above, which gives the error.
myCustomClassEntries.value = new Set<MyCustomClass();
From GetX changelog
Change: You do not need to access the ".value" property of primitives. For Strings you need interpolation. For num, int, double, you will have the normal operators, and use it as dart types. This way, .value can be used exclusively in ModelClasses. Example:
var name = "Jonny" .obs;
// usage:
Text ("$name");
var count = 0.obs;
// usage:
increment() => count ++;
Text("$count");
Thus: List, Map, Set, num, int, double and String, as of this release, will no longer use the .value property.
NOTE: The changes were not break changes, however, you may have missed the details of the documentation, so if you faced the message: "The member 'value' can only be used within instance members of subclasses of 'rx_list.dart' "you just need to remove the" .value "property from your list, and everything will work as planned. The same goes for Maps and Sets.

In short, when using a list in Getx, you don't need to use .value.
...
myCustomClassEntries = Set<MyCustomClass>().obs; // just add .obs and treat it like a regular list.
final object = MyCustomClass();
myCustomClassEntries.add(object); // no error here and not using .value
I asked for the _fetchDataFromServer() function because it matters in the sense of what you're trying to return. But regardless, return an observable Set<MyCustomClass>() and then you won't have type casting errors.
Update after follow up questions:
Just return an RxSet<MyCustomClass> from your _fetchDataFromServer function so you have matching types.
Future<RxSet<MyCustomClass>> _fetchDataFromServer() async {
final tempList = Set<MyCustomClass>().obs;
// ... your code that populates list from server
return tempList;
}
You don't need to clear the list. Below will update myCustomClassEntries with only what is returned from the function.
myCustomClassEntries = await _fetchDataFromServer();

I used them on marker class for google map,markers were not setting after getting current location:
RxSet<Marker> markers = <Marker>{}.obs;
Obx(()=>
GoogleMap(
zoomControlsEnabled: true,
compassEnabled: false,
myLocationButtonEnabled: false,
onMapCreated: (GoogleMapController controller) {
},
markers: vm.markers.value,
),
)

Related

local rest api controller does not receive data from repository function-call

Our VS-2022 development project is Blazor WASM Core-6 with local REST-API for data. Using Postman, my testing is not getting data from the controller call to a repository function -- using breakpoints and local debugging -- as one would expect.
The repository function return statement is return Ok(vehicleTrips);. The IEnumerable vehicleTrips data variable contains the correct four records as expected from the DB fetch.
From the controller the call to the repository function is:
var result = (await motripRepository.GetMOTripsByDateRange((int)eModelType.Vehicle, pVehicleList, pDateFrom, pDateTo)!)!;
The controller function signature is:
[HttpGet("byDateRange/{pVehicleList}/{pDateFrom}/{pDateTo}")]
[ActionName(nameof(GetVehicleMOTripsByDateRange))]
public async Task<ActionResult<IEnumerable<MOTRIP>>> GetVehicleMOTripsByDateRange([FromRoute] string pVehicleList, [FromRoute] string pDateFrom, [FromRoute] string pDateTo) {
This is my problem. The result return value from the repository has a return.Value of null -- NOT four trip records as we should.
Additionally, the VS-Studio's 'local'-debugger shows that there are other properties of return such as .Return and .Return.Value.Count as 4 (four).
My question is "what could be causing this"? All of my other rest-api calls and controller calls with Postman work correctly as one would expect.
Did I select the wrong type of "controller" from Visual-Studio? I am not experienced at all in coding classic MVC web-applications. VS-Blazor offer a number of controller-types. In the past, I "copied" a working controller and "changed the code" for a different "model".
Your assistance is welcome and appreciated. Thanks...John
I found out what actually happened to cause the result.Value is null and had nothing to do with the controller-type -- it was in the interpretation of the return value from the repository function.
I found an SO link Get a Value from ActionResult<object> in a ASP.Net Core API Method that explains how to respond to a ActionResult<objecttype> return value in the reply/answer section with the word "actual" is first defined. You will see this word "actual" in my revised code below.
My revised code is posted here with comments both inside the code section and below the code section. My comment inside the code begins with "<==" with text following until "==>"
// Initialize.
MOTRIP emptyMoTrip = new MOTRIP();
MOTRIP? resultMoTrip = new MOTRIP();
IEnumerable<MOTRIP> allTrips = Enumerable.Empty<MOTRIP>();
int daysPrevious = (int)(pTripType == eTripType.Any ? eDateRangeOffset.Week : eDateRangeOffset.Month);
// convert DateRangeOffset to 'dateonly' values.
DateOnly dtTo = DateOnly.FromDateTime( DateTime.Today);
DateOnly dtFrom = dtTo.AddDays(daysPrevious);
// Fetch the vehicle trips by date-range.
var result = await GetVehicleMOTripsByDateRange(UID_Vehicle.ToString(), dtFrom.ToString(), dtTo.ToString());
if ((result.Result as OkObjectResult) is null) { **<== this is the fix from the SO link.==>**
return StatusCode(204, emptyMoTrip);
}
var statusCode = (result.Result as OkObjectResult)!.StatusCode;
if (statusCode==204) {
return StatusCode(204, emptyMoTrip);
}
**<== this next section allows code to get the result's DATA for further processing.==>**
var actual = (result.Result as OkObjectResult)!.Value as IEnumerable<MOTRIP>;
allTrips = (IEnumerable<MOTRIP>)actual!;
if ((allTrips is not null) && (!allTrips.Any())) {
return StatusCode(204, emptyMoTrip);
}
<== this next section continues with business-logic related to the result-DATA.==>
if (allTrips is not null && allTrips.Any()) {
switch (blah-blah-blah) {
**<== the remainder of business logic is not shown as irrelevant to the "fix".==>**
Please use browser search for "<==" to find my code-comments.
Please use browser search for "actual" and "OkObjectResult" to see the relevant code fix sentences.

FieldValue.increment(1) doenst work as expected

In my code I want to increment the usage by the value 1. I have the usage in firebase and I use it in a chart. I use this function to increment by the value 1:
addActivity(
int day,
) async {
final documentSnapshot = await FirebaseFirestore.instance
.collection('users')
.doc(FirebaseAuth.instance.currentUser!.uid.toString())
.collection('activity')
.doc('${globals.year}')
.collection('week${globals.week}')
.doc(day.toString())
.set({'usage': FieldValue.increment(1)});
}
The problem is that whatever I do the usage value is always set to the value that is in the braces (now 1). I tested this with multiple values and it doesnt seem to work. When I change the initial value to 2 the value after tapping the button isnt 3 but 1...
I'm open and thankful to/for all suggestions :)
That way it's written now using set(), your code always going to overwrite the contents of the document. If you want to update a document, you should use update() instead to update an existing document, or set() with the merge option (SetOptions(merge: true)).
.set({'usage': FieldValue.increment(1)}, SetOptions(merge: true));
To achieve the desired effect you should use update method. set overrides data so it actually sets 1 each time for you. So, just refactor to this
.update({'usage': FieldValue.increment(1)});

Get value from Instance in Flutter

I am making a search request on the List with the Provider pattern.
List<Device> _devices = [
Device(one: 'Apple', two: 'iphone'),
Device(one: 'Samsung', two: 'Galaxy')
];
And Query is like this
List<Device> queryQuery(String value) {
return _devices
.where((device) => device.one.toLowerCase().contains(value.toLowerCase()))
.toList();
the result I expect to get is iphone when I passed the value Apple.
But the result on the screen that I got is [instance of ‘Device’]
when I code like this
child: Text('${deviceData.getDevice('Apple')}'
I do know I should be using some kind of key using two... but I have no idea :-(
You serialized the wrong object.
What you did end-up being similar to:
Text(Device(one: 'Apple', two: 'iphone').toString());
But you don't want to do Device.toString(). What you want instead is to pass Device.two to your Text.
As such your end result is:
Text('${chordData.chordExpand('Apple').two}')
By the look of [Instance of 'Device'], it seems the function is returning a list so it is a good idea to check if the list is empty or not. if it is not empty, one of the elements is still needed to be selected. I guess it should be Text('${chordData.chordExpand('Apple')[0].two}') in case the list is not empty.
To summarize, use something like this to handle the case when list is empty
// Inside your build method before returning the widget
var l = chordData.chordExpand('Apple'); // Returns a list of devices
String textToWrite; // Here we will store the text that needs to be written
if(l.isEmpty) textToWrite = 'No results'; // If the filter resulted in an empty list
else textToWrite = l[0].two; // l[0] is an instance of a device which has a property called two. You can select any instance from the list provided it exists
return <Your Widget>(
.....
Text(textToWrite),
.....
);

want to store promise value in an array

I want to get all the values from a registration page and store all values in an array. How can I do that in protractor?
var arr = new Array(); //declare array
InputName.getAttribute("value")
.then(function(value){
arr[0]=value; // want to store promise value in an array
});
console.log(arr[0]);
If you run your code, it will first log arr[0] and then resolve Promise. Therefore, you may access that array's values in the next Promise. Something like this
var arr = new Array(); // <- this is by the way bad practice, use 'let arr = [];'
InputName.getAttribute("value")
.then(function(value) {
arr[0]=value; // I would use arr.push(value)
});
anotherInput.getAttribute("value")
.then(function(value) {
console.log(arr[0]); // your value should be accessible here
arr.push(value) // push another value
});
But, honestly, I've been working with Protractor fo a while now and I still have difficulties understanding promises... This why I'm using async/await in my tests so if I were to implement something like that I would end up having the following
let arr = [];
let value1 = await InputName.getAttribute("value");
arr.push(value1);
console.log(arr[0]);
Clear, neat code with no hustle. Plus protractor team is actually removing promise_manager, so one day when you update it your code will not work anymore. Then why not switch earlier

Protractor- ElementFinder returning unexpected values

I am writing a protractor test case to compare the name(s) of the displayed data is same as the searched name.
Even though my test case works fine, I am not able to understand what is happening. Because when i expect the name to compare, it compares as expected, but when i print the elementFinder's(rowData)(i have attached the output screen shot here) value in console.log, it show a huge list of some values which i am not able to understand?
PS: I am a newbie to protractor`
This is the testCase:
it('should show proper data for given last name', function () {
var searchValue='manning';
searchBox.sendKeys(searchValue);
search.click();
element.all(by.binding('row.loanNumber')).count().then(function(value) {
var loanCount = value;
for (var i = 0; i < loanCount; i++) {
var rowData = element.all(by.binding('row.borrowerName')).get(i).getText();
expect(rowData).toMatch(searchValue.toUpperCase());
console.log(rowData,'*****',searchValue.toUpperCase());
}
});
});`
And give me valuable suggestions about my style of code
rowData is a promise (not a value), so when you console.log it, you get the promise object
Protractor patches Jasmine to automatically resolve promises within the expect(), so that's how it knows to resolve the value and compare to the expected result.
If you want to console.log the value, you need to resolve the promise with .then() to get the value.
rowData.then(function(rowDataText) {
console.log(rowDataText);
)}
This is pretty much everyone's first question when they start using protractor. You will want to learn how promises work if you want a good understanding of how to manipulate them.