Navigate to page and trigger some method - vue.js

My use case:
After saving the changes on the form, I want to navigate the user to the home page and display for a few seconds message about successful saving. How to do this correct?
My method is simplified like this:
async updateOrder() {
try {
await this.updateOrder({order: this.order});
this.$root.$emit("openCompletedMsg", true); <- I try this, but it doesn't work
this.$router.push("/");
} catch (error) {
...
}
},
So I need show q-dialog on the home page, but after saving my order.

Related

React-admin: User Identity is not updating the User name in the Appbar instantly

I created a custom page which updates the user name. It gets updated successfully both in my controlled TextField component and in the database. But the name doesn't get updated in the Appbar instantly. If I reload the page then the User name gets updated.
I configured my authProvider.getIdentity() as follows in the authProvider.js file
const authProvider = {
......
getIdentity: () => {
try {
const { _id, name } = JSON.parse(localStorage.getItem("auth")).user;
return Promise.resolve({ id: _id, fullName: name });
} catch (error) {
return Promise.reject(error);
}
},
......
};
export default authProvider;
This authProvider gets the name from the localStorage and displays the name fine. Is there any way to call this getIdentity method manually to get the updated user info? My Custom page's fetch API updates the localStorage instantly which gets updated in the Appbar but after a reload. Is there any other way?
In case needed, the fetch API of my custom page is as follows:
fetch('/my-api')..then(...)
.then(
....
localStorage.setItem("auth", JSON.stringify(data)); //-> setting the user value in local Storage
....
})

Can React Native AsyncStorage use to store data forever?

I want to store app data in AsyncStorage. And I want to persist that data and never get lost when app is going to refresh. Actually I'm going to create a job listing site and I want that user choose cities once whom jobs he wants to see and save that information forever.
I'm doing like this.
deviceStorageCity.saveItem("cities", checkedCities);
export const deviceStorageCity = {
async saveItem(key, value) {
try {
var jsonOfItem = await AsyncStorage.setItem(key, JSON.stringify(value));
return jsonOfItem;
} catch (error) {
console.log('AsyncStorage Error: ' + error.message);
}
}
};
But when I refresh state of that page is also refreshed.
Any help would be appriciated.

Render() is called before ComponentWillmount(), Can't get show data on first attempt

I want to show user profile in my react native app. I get the userinfo from another component but now I can't show the data on first attempt. Render() is called before componentWillmount() so the first time I click on profile, data is undefined, but when I go back to home page and click again I see the userinfo.
I already tried to set a state and stop rendering until data is loaded but didn't work
var data = [];
class Profiel extends Component {
constructor(props) {
super(props)
this.state={fetching:false};
}
componentWillMount() {
SInfo.getItem("userdata",{}).then( JsonData => {
data = JSON.parse(JsonData)
console.log(data.nickname) //Show secon
});
this.setState({fetching:true});
}
render() {
console.log('render ' + data.nickname) //shows first
if(!this.state.fetching){
return null;
}
return (
<Text>{data.nickname}</Text>
<Text>{data.email}</Text>
<Text>{data.age}</Text>
)
}
This is normal behavior, render is called so you can offer user feedback while loading something in the background, you should show something to the user like an activity indicator to let them know your app has not crashed and is fetching data.
In your will mount method, you are making an asynchronous call and waiting for the response with "then", but you call this.setState({fetching:true}); outside the promise return, this means that it is being called as soon as the data fetch is being called so it renders the wrong state without the data, try placing it inside your promise resolution:
componentWillMount() {
SInfo.getItem("userdata",{}).then( JsonData => {
data = JSON.parse(JsonData)
console.log(data.nickname) //Show secon
this.setState({fetching:true});
});
}

How to do error handling with bloc pattern in flutter?

Imagine I'm using a bloc to handle a network request. If the request fails, the way to handle the failure would be different depending on the platform. On my web app, I would like to redirect the user to an error page while on my IOS app I would like to show a dialog.
As bloc should only be used and shared to handle the business logic, and the error handling part has nothing to do with the business logic, we should ask the UI part to take care of the error handling.
The UI can send error callback to the bloc and the bloc will run it when an error happens. We can also handle the error in a platform-specific way by sending different callbacks in different platforms.
Then there come my two questions:
Is there a more appropriate way to do this?
How to send the callback to the bloc?
In flutter, we only have access to bloc after the initState life cycle method(for we get bloc from builder context, which only comes after initState). Then we can only send callback in the build method.
In this way, we will repetitively send callback to bloc every time rebuilding happens(these repetitions make no sense).
With react, such one-time initialization could be done in life cycles such as componentDidMount.
In flutter how do we reach the goal of running these initialization only once?
This is how we handle it in my team:
First we build our main page (The navigation root) like this:
#override
Widget build(BuildContext context) {
return BlocBuilder<SuspectEvent, SuspectState>(
bloc: _bloc,
builder: (context, state) {
if (state.cameras.isEmpty) _bloc.dispatch(GetCamerasEvent());
if (!_isExceptionHandled) {
_shouldHandleException(
hasException: state.hasException,
handleException: state.handleException);
}
return Scaffold(
...
We declare the _shouldHandleException like this (still on the main page):
_shouldHandleException(
{#required bool hasException, #required Exception handleException}) {
if (hasException) {
if (handleException is AuthenticationException) {
_isExceptionHandled = true;
SchedulerBinding.instance.addPostFrameCallback((_) async {
InfoDialog.showMessage(
context: context,
infoDialogType: DialogType.error,
text: 'Please, do your login again.',
title: 'Session expired')
.then((val) {
Navigator.popUntil(context, ModalRoute.withName('/'));
this._showLogin();
});
});
} else if (handleException is BusinessException) {
_isExceptionHandled = true;
SchedulerBinding.instance.addPostFrameCallback((_) async {
InfoDialog.showMessage(
context: context,
infoDialogType: DialogType.alert,
text: handleException.toString(),
title: 'Verify your fields')
.then((val) {
_bloc.dispatch(CleanExceptionEvent());
_isExceptionHandled = false;
});
});
} else {
_isExceptionHandled = true;
SchedulerBinding.instance.addPostFrameCallback((_) async {
InfoDialog.showMessage(
context: context,
infoDialogType: DialogType.error,
text: handleException.toString(),
title: 'Error on request')
.then((val) {
_bloc.dispatch(CleanExceptionEvent());
_isExceptionHandled = false;
});
});
}
}
}
On our block we have:
#override
Stream<SuspectState> mapEventToState(SuspectEvent event) async* {
try {
if (event is GetCamerasEvent) {
... //(our logic)
yield (SuspectState.newValue(state: currentState)
..cameras = _cameras
..suspects = _suspects);
}
... //(other events)
} catch (error) {
yield (SuspectState.newValue(state: currentState)
..hasException = true
..handleException = error);
}
}
In our error handling (on main page) the InfoDialog is just a showDialog (from Flutter) and it gets on top of any route. So the alert just needed to be called on the root route.
You can access the BLoC in the initState method if you wrap it in a scheduleMicrotask method, so that it runs after the initState method completed:
#override
void initState() {
super.initState();
// Do initialization here.
scheduleMicrotask(() {
// Do stuff that uses the BLoC here.
});
}
You can also check out this answer to a different question outlining the Simple BLoC pattern, which just calls asynchronous methods directly on the BLoC instead of putting events into sinks.
That would allow code like this:
Future<void> login() {
try {
// Do the network stuff, like logging the user in or whatever.
Bloc.of(context).login(userController.text, emailController.text);
} on ServerNotReachableException {
// Redirect the user, display a prompt or change this
// widget's state to display an error. It's up to you.
}
}
You can use superEnum package to create states and events for a Bloc.(and here you will declare a state for the Error by doing this :
#Data(fields: [DataField<Error>('error')])
OrderLoadingFailedState,
(If anyone need an example of how to use it, please tell me i will show you an example)

Protractor not waiting for login redirect before continuing tests in AngularJS, any suggestion?

I have a standard username/password/submit button form, when the user clicks on the button the form submits with ng-submit="login.submit()" which does the login and on success redirects to the main page using ui.router ($state.go("main")).
The following test fails:
describe("login", function() {
beforeEach(function() {
var email = element(by.model("login.email"));
email.clear().sendKeys("mail");
var password = element(by.model("login.password"));
password.clear().sendKeys("pass");
var submit = element(by.id("submit"));
submit.click();
});
it("should be able to login", function() {
expect(element(by.css(".loginPage")).isPresent()).toBe(false);
expect(element(by.css(".mainPage")).isPresent()).toBe(true);
});
});
and if I try to add wait times around, I can see that the browser stays on the login page the whole time (after clicking on the button) - then I get a timeout.
After a successful login the browser receives a cookie with a token for authenticating each following request.
EDIT: with some tinkering I found out where it fails..
function login(email, pass) {
alert("it gets here");
return _auth.post({ username: email, password: pass }).then(function(data) {
alert("does not get here");
console.log("loginok, token:" +$browser.cookies().apiToken); //this should be the received token
return data;
});
}
EDIT2: the Auth service
var _auth = Restangular.withConfig(function(Configurer) {
Configurer.setBaseUrl("/");
}).service("auth/simple");
return {
login: login,
};
function login(email, pass) {
return _auth.post({ username: email, password: pass });
}
Manually everything works as expected.
#JoMendez's answer was very close but didn't work in my case. Used #DaveGray's here.
Had to wrap the isPresent() call in a function.
browser.wait(function() {
return element(by.css('.mainPage')).isPresent();
});
Try this:
it("should be able to login", function() {
browser.wait(element(by.css(".mainPage")).isPresent);//this is different from sleep, this will stop the excecution of all the protractor code that is after it, until the element is present, but it won't prevent the application of loading or if is redirecting, it will keep working.
expect(element(by.css(".loginPage")).isPresent()).toBe(false);
expect(element(by.css(".mainPage")).isPresent()).toBe(true);
});
});