jurassix / react-validation-mixin

Simple validation mixin (HoC) for React.
MIT License
283 stars 38 forks source link

Issue with the fields #22

Closed batata004 closed 9 years ago

batata004 commented 9 years ago

Hi,

First of all I would like to say thank you for your jurassix library, it's amazing. :) I just have an issue that is probably a bug on it. Please, open your own demo at this link:

http://jurassix.github.io/react-validation-mixin/

After that open your browser console (F12) and paste the following code:

document.getElementById("email").value = "testing@gmail.com";

It will work fine, I mean, the "Email" field will receive the value "testing@gmail.com". But there is a problem: when I try to send the form, clicking the SIGN UP button at the bottom of it the error message says that the Email field was not filled right. Can you tell me how to solve this bug cause I really love your library and I use it in dozens of websites I develop. It's pretty handy and really nice!

Hope you can help me.

OBS: I know my question can be solved with a different approach but I need to give my customer to ability to manipulate the form fields with JS at the console cause they have testing tools to make sure the sign up form is working and one of my customer pointed me this "bug" yesterday.

JURASSIX: I have control over the input it has a ChangeHandler in the input and I would like to just fire this event. The simulate to me is not working, for some reason... it gives me undefined error.

jurassix commented 9 years ago

I'll take a look and see what options we have for supporting this within React.

jurassix commented 9 years ago

The real issue is that when manually setting the value of a React controlled input you are not firing any events to let React know the value has changed; no 'change' event triggered. I'm assuming you cannot have the client manually fire change after updating the the value?

Example: since all my event listeners are on blur this will signal to React to kick in.

  var email = document.getElementById("email");
  email.value = "testing@gmail.com";
  email.dispatchEvent(new Event('blur'))

If you cannot have the client add the dispatchEvent logic, you can still address this by overriding the getValidatorData function. Basically the idea is that since you have input that is entered outside of React you cannot validate your state directly, you need to use another api to ensure the DOM value is used: React.findDOMNode(this.refs.email).value. This may cause issues with your components functionality that relies on state but the validation will work.

getValidatorData: function() {
  return {
    email: React.findDOMNode(this.refs.email).value
  };
}
batata004 commented 9 years ago

Hi, thank you so much for helping me into this. You are very kind.

About this issue, you are right, indeed, changing the value of the input is not making React fire the change event. I can ask my customers to execute any JS code you gave me, they dont care. It can be a big or small JS. I just need someway to change the value of the input and have your excelent library to recognize this new value.

I tried your code below and it didnt work, it changed the value of the input but when I clicked the SIGN UP button I still got an error on email field.

var email = document.getElementById("email"); email.value = "testing@gmail.com"; email.dispatchEvent(new Event('blur'))

Your another suggestion of overriding "getValidatorData" I think I didnt get it. I am not too smart into React and into your library as I would like, because of that I didnt understand your last suggestion. Should I try to copy/paste your code into the browser console? I need a solution that can be copied/pasted in the console.

If you know how to dispatch the "onchange" event of the input maybe this "bug" would be solved. But I already tried dispatching this event with many different JS codes and none of them work.

I love your library and this is the first time I really find a small problem. I am tired of using many other libraries in the past and yours is far way the best but unfortunatelly I have this "bug" that I need to find a solution cause my customers demand a way to set the value of the input with JS.

Hope you can find a solution to this, I will be following this thread daily and will be glad for any, any, any help you can give me to solve this "bug".

jurassix commented 9 years ago

Ok so after some research it seems that the best approach is to manually expose the onChange handler and call it directly from the console; or if you are using FLUX, expose and call the Action directly. I also think this is would be the recommended way to do what your trying to do.

To further expand on getValidatorData api. This api is exposed as a way to provide data to this library on validate. By default this library uses this.state as data, but if you data comes from props you would do the following:

getValidatorData: function() {
  return this.props;
}

With the above whenever this.validate is called getValidatorData will also be called to get the data to validate. In your case you have uncontrolled input data, because it was entered outside of React and is not stored inside state or props. For uncontrolled data you need to get the data out of the DOM and return it from getValidatorData:

getValidatorData: function() {
  return {
    email: React.findDOMNode(this.refs.email).value
  };
}

Above we assume we have a single field, email, and we grab the DOM value. This is contrived, but it should be enough for you to get going.

The real issue with this approach is you are outside of react and limits what you can do. I would recommend exposing the onChange handler and directly calling it from the console to solve your issue.

If you put together a jsbin or other working example I'll help you get to the solution you are looking for.

batata004 commented 9 years ago

@jurassix nice explanation! Really nice. Unfortunatelly it would be too hard to me open every website I created and make this change only to allow my customer to interact with the form. Your getValidatorData approach is really good and it will certainly work pretty well! But I am more interested in exposing the onchange handler. I have no idea how to do that, do you know how do I expose the onchange event so I can call it later in the browser console?

jurassix commented 9 years ago

To expose your onChange handler you would need to update every site too! Since your handlers are encapsulated inside the React component you would need to componentDidMount expose the handler to the the window or other console accessible object; and on componentWillUnmount clean up the exposed handler. Again this is a manual change.

You might also try to simulate the events: http://facebook.github.io/react/docs/test-utils.html

batata004 commented 9 years ago

:( Ok, at least it's a solution. I will implement it on every website.

I thank you so much for helping me into this, I will use your manual solution :) I am very glad you helped me, keep up the good work!

jurassix commented 9 years ago

Do a quick test and see if you can use the simulate tools too, it might work, and shouldn't require any code changes:

var node = React.findDOMNode(this.refs.email);
React.addons.TestUtils.Simulate.change(node, {target: {value: 'testing@gmail.com'}});
batata004 commented 9 years ago

Your idea of simulating the event is muuuch better indeed! But I didnt get it to work. I opened http://jurassix.github.io/react-validation-mixin/ and after the page load I executed the last code you provided me (2 lines of code) in the console but it gives me the following error:

ReferenceError: React is not defined

Why React is not defined if you example page loads React?

jurassix commented 9 years ago

You won't be able to test on my example page. I would need to expose React to the window. I'll update the example when I have some time and ping back. You can try to test on one of your client pages if possible.

batata004 commented 9 years ago

Again I say thank you thank you thank you! I will try it on a page of my customer but I think React is not exposed too and I have no idea how to expose it... anyway, if someday you expose it on your page I would be glad if you could tell me so I can open your page and test it there!

Thank you, many thanks!

jurassix commented 9 years ago

Ok I have exposed React on my examples page and tested that this is a working solution!

var email = document.querySelector('#email');
React.addons.TestUtils.Simulate.change(email, {target: {value: 'testing@gmail.com'}});

To expose React you need to find the entry point of your app and set window.React = React; or exclude React from you bundle and add it as an external dep.

You are good to go.