Custom remote validator error message - parsley.js

With a custom remote validator, how are you supposed to get rid of the error messages?
Using data-parsley-remote-validator='mycustom' on the field will give you an error in the console 'undefined async validator' unless the validator is added on DOM ready i.e not inside another function. However, if it is added on DOM ready, then parsley automatically calls it, which shouldn't happen until submit/change or whatever else you have set.
I can do something like this, but it kind of defeats the object of having parsley call the validator on change:
$('#signUpForm').on('submit', function() {
//add the attribute here to avoid the initial error message
$('#exampleInputEmail1').attr('data-parsley-remote-validator', 'validateEmail');
//then add the custom validator
$('#exampleInputEmail1').parsley()
.addAsyncValidator('validateEmail', function (xhr) {
if(xhr.status == '200') {
return 200;
}
// return the error message if email is taken
else if(xhr.status == '404') {
response = '<ul class="errorlist"><li>That email has already been taken, please try another</li></ul>'
$('#errorResponse').html(response);
}
}, '/api/v1/email/available', { "type": "POST", "dataType": "json", "data": data }
);
});

For those who came here for custom remote validator error message in Parsley.js,
You can add data-parsley-remote-message to the element,
<input type="text" data-parsley-remote-validator="my_remote_validator" data-parsley-remote-message="Custom error message only for remote validation on this element" >
Tested with Parsley.js - Version 2.3.11

Your asynch validator is not supposed to set an error message itself, it should simply return if the value validates or not. The error messages are added with a different API and/or specified as data attributes, check the doc.

Related

Typescript object property 'undefined' while it is not

I'm farly new with Typescript and struggle with what seems to be a dumb issue:
I retrieve an 'agent' object from a service.
this.agentsController.getAgent(matricule).subscribe({
next: agent => {
console.log(agent)
console.log(agent.emailPro)
},
error: (error: string) => {
console.log(error)
}
});
According to the 1st console.log, it is well populated :
{
"agent": {
"matricule": "000001",
"nom": "DummyName",
"prenom": "DummyFirstname",
"emailPro": "dummy#dummy.fr",
"adresse1": "dummy address",
"telephonePerso": "0000000001"
}
}
But as clearly as the print of the agent shows a well defined email address (emailPro), the 2nd console.log always shows undefined
How is that possible ?
What am I missing ?
To summaries the comments chain as a valid response :
My service was encapsulating my proper agent object in some other dummy object that happens to be called 'agent' as well. Hence the confusion !
So instead of calling agent.EmailPro I should have called agent.agent.EmailPro.
I chose to fix my service instead so it parsed the API response better :
From this.httpClient.get('apiUrl').pipe(map((result:any) => result as Agent));
To this.httpClient.get('apiUrl').pipe(map((result:any) => result.agent as Agent));
Thanks again to #pietro909 & #T.J.Crowder

How to handle api errors using aws-amplify?

I'm currently trying to POST data to my aws lambda functions triggered by aws api-gateway using the aws-amplify react lib.
Here is the code :
API.post("snippets","snippets/", {
body: data,
}).then(response => response).catch(console.log(err))
In the main case, everything is OK.
But my lambda function is design to validate the input data and return a status code 400 with a returned payload looking like that :
{
"errors": [
{
"field": "title",
"message": "This field is required"
}
]
}
I would like to catch those errors in order to display them in the frontend but aws-amplify seems to have an undocumented behavior.
By default, status code 400 returned are throw with a default error message :
Error: Request failed with status code 400
at createError (createError.js:16)
at settle (settle.js:18)
at XMLHttpRequest.handleLoad (xhr.js:77)
Is there a way to get the returned payload instead of this magical error?
It turns out that under the hood, aws-amplifyuse Axios to make http calls.
When using Axios, you have to console.log(error.response): https://github.com/axios/axios/issues/960
Here is the fix I've made :
API.post("snippets","snippets/", {
body: data,
}).then(response => response).catch(error => console.log(error.response.data))
A Pull Request on the aws-amplify documentation is open : https://github.com/aws/aws-amplify/pull/633
I also faced the similar issues, It showed the default error message "Request failed with status code 400", instead of the message that is returned from API.
I logged the Error object and it did not show the response attribute in it. But we do have response attribute. I tried logging the Error.response and it did contain the response sent from the API.
Just figured out this by going through the 'Cancel API requests' Amplify docs.
From what I can see this is the contents of the error object returned by the API call:
Heres what I am doing to just print out the error, obviously you would do a lot more here but its a good start.
async uploadUser(state, payload) {
const promise = API.graphql({
query: createUser,
variables: { input: payload },
});
try {
await promise;
} catch (error) {
// Print out the actual error given back to us.
console.log(error.errors[0].message);
// If the error is because the request was cancelled we can confirm here.
if (API.isCancel(error)) {
// handle user cancellation logic.
console.log(error.message);
}
}
Hope that helps 😃

Using React to render flash messages from Express

I've searched around a lot but have been unable to find a simple way to get flash messages from Express and render them in React.
I need to access the data on my Express server, but what is the best way of storing this and passing it down to React? I was thinking of passing an object down when the React index.html file is rendered, but I'm not sure how I can access this data, or send the correct data when certain events happen, for example a user enters the wrong password.
I solved the issue.
I simply have a variable in my session called flash which is set to false by default.
In the correct part of the passport flow I redefine this to a string, depending on the error. I have a React action and reducer to get this data and if it's truthy, render it to the screen. When the component unmounts or the site is refreshed I reset it to false.
EDIT: I have found a better solution
1. In the passport middleware set an optional message if something goes wrong.
return done(null, false, { message: 'Email not found' });
2. In the login route send this information as a response.
router.post('/login', (req, res, next) => {
passport.authenticate('local-login', (e, user, info) => {
if(e) return next(e);
if(info) return res.send(info);
req.logIn(user, e => {
if(e) return next(e);
return res.send(user);
});
})(req, res, next);
});
3. Handle the submission and response in a Redux action generator. If the user authenticates, then the message property will be undefined.
const res = await axios.post('/auth/login', { email, password });
dispatch({
type: 'FLASH',
payload: res.data.message
});
4. In the reducer, the state will be either a string or false:
return action.payload || false;
5. Then it's a question of rendering the state to the screen. Another action can be sent when the component unmounts to reset the state.
Hope this helps someone else out there.
expressjs/flash will place an array of flash objects onto res.locals. Per the docs: https://github.com/expressjs/flash#reslocalsflash
res.locals.flash
An array of flash messages of the form:
{
"type": "info",
"message": "message"
}
From my understanding, anything placed on res.locals is available in the global scope. In other words, you should be able to do window.flash which should return an Array of flash objects.
So you would simply loop over the array as you would normally in JavaScript. That is just my guess.
const makeFlashElement = ({type, message}) => {
return (
<div>
<h1>message</h1>
<h2>type</h2>
</div>
)
}
for (message in flash) {
makeFlashElement(message)
// ...
}
Typically you'd return a JSON response which React can easily digest.
See Karl Taylor's comment.

Redux Form: Set error to a field without submitting the form

I have a form that is loading data from an API. I'm trying to set manually an error to the field if occurs some error in the api call.
// This is the input that I'm trying to set the error message
<Field
name="username"
component={CustomCombobox}
/>
Here I'm trying to set an error in the catch block.
try {
const { data } = await UserService.getUser();
} catch (e) {
// here I'm trying to set an error to "username" field
stopSubmit('myFormName', { username: 'Something wrong happened.' })
}
But here's is the problem. I'm not submitting the form, so the stopSubmit does not work. I'm just receiving data from an API to fill the options, and if some error happens I want to set the error manually.
This website has some examples on form validation
If you are trying to run a check on the username before submitting the form, you could run an API call on the value of the field and then show the error if the function fails.
Maybe this isn't what you are looking for / I have misunderstood

Global error handling in marionette.js

The UI should have a global error handler that shows a popup message whenever an error is received through the API. I'm trying but I'm not getting, I did not find any example too. This should be done Marionette.js. Please help
I got a json file:
{
"errorcodes": [{
"message": "Invalid Email/Password Combination",
"reason": "com.catt.exceptions.catttCustomerPreferencesException: Invalid Email/Password Combination\r\n\tat com.catt.v1.controller.CustomersController.customerLogin(CustomersController.java:303)\r\n\tat sun.reflect.GeneratedMethodAccessor1008.invoke(Unknown Source)\r\n\tat sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\r\n\tat java.lang.reflect.Method.invoke(Method.java:606)\r\n\tat org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerM...",
"type": "tCustomerPreferencesError"
}]
}
You can use $.ajaxError to listen for any error happening in $.ajax.
From there, you can make make a Marionnette Application (for example), handle the error, and display an alert
var App = new Marionette.Application();
App.vent.on('error', function(event, jqxhr){
alert(jqxhr.responseText);
});
$(document).ajaxError(function(event, jqxhr, settings, thrownError){
App.vent.trigger('error', event, jqxhr, settings, thrownError);
});
Fiddle Here : http://jsfiddle.net/8ff4n9ut/

Resources