I have variable called to totalQuantity in provider:
get totalQuantity => total_quantity();
total_quantity() {
var totalQty = 0;
for (var x in myCart) {
totalQty += (x.quantity);
}
return totalQty;
}
I use it in the app bar:
child: Text('${prod.totalQuantity}',
I have a logout function I want when I pressed on it to reset totalQuantity, I guess using setter for that in provider, but I don't know how to do that.
IconButton(
onPressed: () {
prod.clear_myCart();
loginProd.log_out();
// ----------------- I want to reset it here
},
I found my mistake ,I forgot to add listen notifier
void clear_myCart() {
myCart.clear();
notifyListeners();
}
after I add it ,it works fine
I understand that you want to return totalQuantity to the original (empty) value, so lets have a look at where it gets its value from:
Your total_quantity() function depends on one variable, myCart.
So, if you clear myCart in prod.clear_myCart();, the quantity should also be updated accordingly.
Now, what your code does not show is how the value change of myCart is being handled in your code;
I am speculating here because your code snippets don't provide enough information, but your ChangeNotifier might just not call notifyListeners() when you call prod.clear_myCart(); (See https://flutter.dev/docs/development/data-and-backend/state-mgmt/simple).
Related
I'm trying to add code to my Flame Game to check if a list isn't empty and if it isn't, then send it to a function. However, I'm receiving an error on the if statement that says "Expected an identifier". How do I change my code to run an if statement here? Additionally, how would I cancel the Timer after it runs?
var instructions = [];
myGame(){
add(
TimerComponent(period: 2, repeat: true, onTick: () =>
if(instructions != null){populateInfo(instructions)}),
);
}
You can use runtimeType, Use runtimeType to get the runtime type.
A property of the Object class, which is the base class of all objects in Dart, and of type Type.
for (final element in gameRef.children) {
if (element.runtimeType == Instructions) {
//my element exist in the scene
}
}
I used the last code for explain the use of runtimeType, but with Dart you have more options like to
children.query<Intructions>();
I've noticed a problem with splitting responsibilities in React components based on the fetched data using RTK Query.
Basically, I have two components like HomePage and NavigationComponent.
On HomePage I'd like to fetch the information about the user so that I can modify NavigationComponent accordingly.
What I do inside HomePage:
import { setNavigationMode } from "features/nav/navSlice";
export default function HomePage() {
const {data: user} = useGetUserDataQuery();
const dispatch = useAppDispatch();
const navMode = user ? "all-options" : "none";
dispatch(setNavigationMode(navMode)); // here I change the default Navigation mode
return <MainLayout>
<Navigation/>
<Content/>
<Footer/>
</MainLayout>;
}
The HomePage is a special Page when the NavigationComponent shouldn't display any options for the not logged in user.
Other pages presents additional Logo and Title on Nav.
React communicates:
Warning: Cannot update a component (NavComponent) while rendering a different component (HomePage). To locate the bad setState() call inside HomePage, follow the stack trace as described in https://reactjs.org/link/setstate-in-render
Not sure what is the right way to follow.
Whether the state should be changed in GetUser query after it is loaded - that doesn't seem to be legit.
problem is dispatch calls every render. Instead you can create a navigationSlice (if you don't have already) and use extraReducers for matching your authorization action like:
extraReducers: (builder) => {
builder.addMatcher(
usersApi.endpoints.login.matchFulfilled,
(state, { payload }) => {
if (payload.user) {
state.navigationMode = "all-options"
}
}
);
}
This way, state.navigationMode will only change when authorization changes
The solution was too obvious. The dispatch should be run in useEffect.
import { setNavigationMode } from "features/nav/navSlice";
export default function HomePage() {
const {data: user} = useGetUserDataQuery();
const dispatch = useAppDispatch();
const navMode = user ? "all-options" : "none";
// changed lines
useEffect( () => {
dispatch(setNavMode(navMode));
}, [navMode, dispatch]);
// /changed lines
return <MainLayout>
<Navigation/>
<Content/>
<Footer/>
</MainLayout>;
}
Thank you #papa-xvii for the hint with changing the navMode after user login. That solves the second problem I had.
However I cannot accept the answer as it does not solve the problem I described above.
I am using the bindStream() function with the GetX package inside a controller.
class FrediUserController extends GetxController {
#override
void onReady() {
super.onReady();
final userController = Get.find<FrediUserController>();
var groupIds = userController.user.groups;
groupList.bindStream(DatabaseManager().groupsStream(groupIds));
ever(groupList, everCallback);
}
}
But, when the groupIds update in the FrediUserController (with an ever function that gets triggered, I want to RE-bind the streams. Meaning, delete the existing ones and bind again with new ids, or replace the ones that have changed.
Temporary Solution: Inside ever() function
Get.delete<FrediGroupController>();
Get.put(FrediGroupController());
This code gets run everytime my groupIds change from the database. But I do not want to initiate my controllers every time a small thing changes, it is bad UX.
This seems difficult, could someone guide me to the right direction? Maybe there is a completely different approach to connecting two GetX controllers?
Note: the first one include editing the source code of the Getx package.
first:
looking in the source code of the package :
void bindStream(Stream<T> stream) {
final listSubscriptions =
_subscriptions[subject] ??= <StreamSubscription>[];
listSubscriptions.add(stream.listen((va) => value = va));
}
here is what the bind stream actually do, so if we want to access the listSubscriptions list, I would do:
final listSubscriptions;
void bindStream(Stream<T> stream) {
listSubscriptions =
_subscriptions[subject] ??= <StreamSubscription>[];
listSubscriptions.add(stream.listen((va) => value = va));
}
now from your controller you will be able to cancel the streamSubscription stored in that list with the cancel method like this :
listSubscriptions[hereIndexOfThatSubscription].cancel();
then you can re-register it again with another bindStream call
second :
I believe also I've seen a method called close() for the Rx<T> that close the subscriptions put on it, but I don't know if it will help or not
Rx<String> text = ''.obs;
text.close();
I've also run into this issue, and there appears to be no exposed close function. There is a different way to do it though, using rxdart:
import 'package:get/get.dart';
import 'package:rxdart/rxdart.dart' hide Rx;
class YourController extends GetxController {
final value = 0.obs;
final _closed = false.obs;
void bindValue(Stream<int> valueStream) {
_closed
..value = true
..value = false;
final hasClosed = _closed.stream.where((c) => c).take(1);
value.bindStream(
valueStream.takeUntil(hasClosed)
);
}
}
Whenever you want to unbind, just set _closed.value = true.
I'm making a reactive model with Getx on a product list, but when I start the list it comes with no value and causes an index error even though there are actually values in the list it appears empty at first, which somehow gets fixed automatically. (this is inside a build of a statelesswidget)
return GetX<CartController>(
init: CartController(),
builder: (controller) {
try {
return Text(
"${StringConvert.toMoney(controller.totalByProduct[productId])}",
style: kSmallTextBold,
);
} catch (e) {
return const Text("Error...");
}
},
);
}
I did try catch to manage this, but the catch part doesn't show up;
this is relevant part of the controller
var totalByProduct = [].obs;
fetchTotal() {
List products = storage.read(StorageKeys.cartProducts);
double currentValue = 0.0;
List currentTotals = [];
for (var item in products) {
currentTotals.add(item['total'] * item['amount']);
currentValue += item['total'] * item['amount'];
}
total.value = currentValue;
totalByProduct.value = currentTotals;
}
I believe it's not the right way to do this, so what do I need to know to fix this correctly?
If helps this is the error:
With a method to read the storage (sharedPreferences) in async mode, with a FutureBuilder it was possible to correct the error, because in the initial state the list takes the value assigned explicitly. Even if it then receives the correct value, accessing the index in its initial state causes the error, this explains why even with the error it works.
I am building my first app with Flutter, here's the problem I stuck with:
I have several tabs with radio buttons, the tabs are generated dynamically. I am using two functions to handle the changes in those radio buttons. Each function is used in every tab.
My problem is that I don't know how to assign the value of the radio buttons to different variables.
I precreated the variables, but how do I access them from my functions? I tried do do it this way:
var bedsRoom1, bedsRoom2... bedsRoom7; //7 variables which is maximum of what I need
I use the functions as a callback inside the state of the stateful widget. Inside the function I tried to do:
void _handleRadioValueChange1(int value, int counter) {
setState(() {
_radioValue1 = value;
bedsRoom$counter = value;
});
}
I get error messages about an undefined name of a variable. Please explain how to do it right.
Instead of declaring multiple variables, you can declare a list of variables like this -
List bedRooms = new List(7);
Then you can access the variables like this -
void _handleRadioValueChange1(int value, int counter) {
setState(() {
_radioValue1 = value;
bedsRooms[counter] = value;
});
}
You can read more about List in dart from here -
Lists in dart