I am following this udemy course(https://www.udemy.com/learn-flutter-dart-to-build-ios-android-apps) on flutter, and using scoped_model for state management.
I want to edit a product from list of products. For that I set the product id as a flag - selectedProductId in scoped model. When submitting, I want to navigate away and set this selectedProductId to null.
//method to edit product
editProduct(productId, newValues);
Navigator.pushReplacementNamed(context, '/productsPage').then((_){
debugger();
setSelectedProductId(null);
}).catchError((err){print(err);});
The debugger is never hit. and there is no error either.
I tried using async await and still no use.
editProduct(editableProductId, _formData);
await Navigator.pushReplacementNamed(context, '/productsPage').catchError((err){print(err);});
debugger();
setSelectedProductId(null);
the page is navigated to the given route, but the line after, is never executed. I even tried using pushNamed instead of pushReplacementNamed.
I know that pushReplacementNamed returns a future, so .then() must be called, but doesn't seem to happen, am I missing something? Are there any other factors or situations I should know?
You have got the concept wrong. Suppose you have Activity A and Activity B. From Activity A you navigate from A to B. Now the then from A is called only if Navigator.pop(context) is called from B. If pop is not called from B then the then callback is never called.
In your case you are calling Navigator.pushReplacementNamed from A, so what you are doing is REPLACING A with B. So, even if you pop from B then Activity A is not available anymore, so the then callback will never be called.
You can refer to this section in the flutter cookbook for further info.
As for executing the code in then callback you should move it to dispose method of the Widget, you will see it getting called but I don't see the point in doing this because the Widget is getting destroyed and no point in setting its instance property as null.
Create a Custom Future Object might solve the Problem
Navigator.pushReplacementNamed(context, '/product');
Future.delayed(Duration(milliseconds: 700)).then((_)=>resetSelectedProduct(null));
Just simply add the below code:
Navigator.of(context).pushNamedAndRemoveUntil('/productsPage', (route) => false);
Related
I make an app using firestore and a bottom navigation bar in Flutter. The problem is that when I switch between tabs, the build method is called everytime. The build method downloads data from firestore. Therefore, the app flickers when I switch tabs (the spinning bar is showed for a very short time). I tried to fix this by moving the firestore stream to the constructor. However, since the stream can emit before the build method, it loads forever.
A solution could been to save the last value that was emitted. I tried to fix this using the shareReplay method in Rx, but they have not implemented in RxDart yet. So, what is the best practice to implement this?
Use the shareValue operator of rxdart:
final observable = Observable(yourStream).shareValue();
Internally, this operator uses a BehaviorSubject. It will subscribe to the stream as soon as there is a single subscriber (it will only subscribe once), and unsubscribe (and dispose the subject) when there are no more subscribers.
Also, as you said, you have to create the observable in initState or a similar method (NOT the build method!). The observable should be stored in a field in the State.
In the currently accepted answer, the Observable class in RXDart has now been deprecated. Instead, you could use a BehaviorSubject but its probably best to use a ValueConnectableStream instead, like this:
final newStream = ValueConnectableStream(yourStream).autoConnect()
See the RXDart docs for more info.
Convert stream to BehaviorSubject in rxDart.
BehaviorSubject<Data> _subject = BehaviorSubject<Data>();
stream.listen((x) => _subject.add(x));
I ran the flutter app in release mode and the lag was gone, without any modifications.
You could have a look at BehaviorSubject in rxdart. According to the docs
The latest item that has been added to the subject will be sent to any new listeners of the subject.
I am new to flutter, dart or reactive programming in general.
I suppose, I am calling add() on the BehaviorSubject while items are being added to that stream by some previous call.
How can I avoid this bad state? How can I add the event once the event in previous call have been added?
As mentioned in the documentation: "Events must not be added directly to this controller using add, addError, close or addStream, until the returned future is complete." You may want to wait for the Future callback first before calling add().
Here's my attempt:
https://github.com/DaveNotik/dart-stack/commit/99f877491dbd7163aa1bd8d5844c489bdab05eeb
My aim was to make it so when /welcome is detected (which I set the Facebook callback URL to) a window.alert is triggered. But right now it triggers on every page load, so it doesn't seem the router is working appropriately? Is my approach correct?
Most likely you problem is this:
addHandler(Routes.sayWelcome, MainController.sayWelcome(app))
The second argument should be a function to call; but you are calling the function immediately such that its return value is being used as the handler. You need to make this a function so that it will be invoked only when the route is navigated to. For example:
addHandler(Routes.sayWelcome, (_) => MainController.sayWelcome(app))
I added a ParameterHandler to my application's main window so I can catch and process custom get parameters in my url. However, the presence of one parameter reloads the first page of my application, for some reason building this page triggers the handleParameters method again, this time with no parameters passed. If left unchecked (e.g. no ifs) the page's elements will just replicate themselves on top of themselves over and over again.
I suspect it has something to do with my main windows's addComponent method.
How can I stop it from doing that?
I completely forgot I still had this question open. I found that the problem was that the method got triggered for both get and post type parameters, and this is what caused the unexpected output.
I already implemented an HttpServletRequestListener because I used Vaadin's ThreadLocal pattern, so I just filtered all GET parameters out of the request object in one of the implemented methods and went from there.
debug your application and have a view at the call stack of the handleParameters method
accountTab.setChangeListener(new FieldChangeListener() {
public void fieldChanged(Field field, int context) {
if (field==TabBar.accountTab) {
Dialog.alert(" Account Tab is clicked ");
}
}
});
why this code is not working?
but some places it works. I am ceating the tab bar for 9800 torch with Horizontal field manager and "accountTab" in this code is the custom button field. Please Help me.........
If you are attaching a FieldChangeListener to one Field, you shouldn't really need to test whether or not it is the Field (unless you're doing something very custom). I would try debugging and see whether or not the fieldChanged call is getting hit, and if you want to use the test in there, make sure TabBar.accountTab is actually a reference to what you think it is.
Another possibility is that you haven't set the tab as FOCUSABLE, or possibly you have something further up the chain intercepting the clicks and not allowing it to proceed further.
The information provided is too vague to know the exact problem. However, there's a good chance it has to do with the fact that you're trying to open a dialog in response to an event and you might not currently be holding the event lock. Use Application#invokeLater() to open the dialog. You'll need to implement Runnable and make the Dialog.alert call from the run method.
does the callback fire? have you attached a debug breakpoint to the conditional to see if it actually calls?
if so, then #Fostah's answer above is a pretty good place to start, you may not be in the event dispatch thread when this callback fires...