A little context:
I have a form in which the user needs to select a date from a date picker, then submit the form with the selected date and some other pre-populated information. I am using Redux Field to wrap a custom component which includes the React Date Picker.
The problem:
I am using the validate prop for Redux <Field>, which simply enforces that the input value not be undefined. The problem is when I select a date I see the error message that I would normally see when validation fails. In other words the app thinks the date picker input value is undefined even though it clearly has a value.
Troubleshooting
I console logged this.props and checked the React Components Tab in dev tools, and observed the prop in question, "moveInDate", before and after selecting a date. I see an empty string prior to selecting a date (this is expected since I am setting an empty string as an initial value), and I see the expected value after selecting a date.
I also console logged the input value in the wrapped component, and I can see the name of the element and selected value are making down into it.
At this point I'm not sure where to look. Everything is updating as it should from what I can tell, yet the app still sees the input as having a value of undefined some how. I feel I am missing something as it relates to handling the input with Redux. It is useful to note I'm using this Field implementation on another page in the app, and it works without issue. I speculate there must be something elsewhere in the parent component messing with the state, but I'm not sure what to look for.
On a related note, I have a similar issue when selecting a dropdown that is also wrapped in Redux <Field>: the dropdown options don't always display, and I get the same validation bug as described above when I am able to select an option. I don't mean to get off topic with this, but I can't help but feel these issues are related.
I will post code I think will be helpful, but it is quite a lot in its entirety.
Field:
<Field
highlightDates={busyDates}
name="moveInDate"
type="text"
component={DateField}
label="Installation Date"
onChange={moveInDate =>
this.handleMoveInDateChange(
moveInDate,
leaseLength
)
}
validate={[required, this.dateAvailable]}
filterDate={(date) => {
const day = date.day();
return day !== 0 && day !== 6;
}}
minDate={
mode === MODE_RENEW &&
formValues?.currentMoveOutDate !== null
? moment(formValues?.currentMoveOutDate)
: moment().add(settings.blackoutPeriod, 'days')
}
maxDate={
mode === MODE_RENEW &&
formValues?.currentMoveOutDate !== null &&
moment(formValues?.currentMoveOutDate).add(1, 'week')
}
openToDate={
formValues?.moveInDate ||
this.getFirstAvailableDateForMoveIn()
}
Validate Rule
export const required = value => value ? undefined : 'You can\'t leave this empty';
Handler:
handleMoveInDateChange(moveInDate, leaseLength) {
const newMoveOutDate = getMoveOutDateByMoveInDate(
moveInDate,
leaseLength,
this.getBusyMoveOutDates()
);
if (leaseLength && moveInDate) {
this.props.formValues.moveOutDate = newMoveOutDate;
}
}
The handler simply calculates a move out date based on the move in date, then adds it to form values. There isn't a move out date picker in the form. I thought this handler could be causing a problem, but it's not doing anything with the move in date (the problematic input).
Final thought:
My question is admittedly similar to this one, but in my case the issue arises when inputting a new value, and not from dealing with a preloaded value.
Update
I noticed when selecting a date in the datepicker, the value never changes. I refactored the validate rule with braces so I could console log the arg, and there is nothing making it into the function. Conversely when I try this on another page using the same <Field> with datepicker I see the new value each time I change it.
I resolved the issue with keepDirtyOnReinitialize: true in the redux connect code.
I discovered the date picker was working correctly when I commented out the values I was assigning in initialValues in mapStateToProps, so it looks like the problem was the date picker always thought it had a pristine value, which is why the redux field never thought the value changed (from null to the selected value), so the validation logic didn't think anything was in there!
Hope this helps someone who stumbled across a similar problem.
Related
I'm using react together with react-semantic-ui and I'm having following input type:
<Input
onChange={e => this.onTextInputChange(e, 'date')}
value={this.state.searchQuery.date}
type='datetime-local'/>
onTextInputChange function sets input value as the state field and value of this input is bound to this field. Also, I have an additional button in my app which is responsible for clear form fields (by setting null on each state field).
state = {
searchQuery: {
date: null
}
}
Clear works pretty well for other fields, but the problem occurs when I touch datetime-local input. When I fill some part of the date I'm getting this message when I hit the clear button.
I'm able to clear this field only when I provide a full date. I know I can solve this issue by setting the value of this field to blank string ' ' during clear, but it isn't the best solution, because later I have to filter out those fields. I was even playing with react ref, but unfortunately I didn't achieve any positive result, what's more, blue cross which appears on hover clears the form. Any tips how can I handle it in a pretty way?
Edit #1:
event.preventDefault helped me to get rid of this validation message, but anyway input stays without cleared value.
You need to set the value of this.state.searchQuery.date to an empty string instead of null. In an input of type date, value={null} is not a valid as mentioned here. It is the only solution to this problem. If you specifically need null values you need to parse the empty string as null to avoid having to filter.
Value: A DOMString representing a date in YYYY-MM-DD format, or empty
Regarding the blue clear button, webkit has a pseudo-element input[type="date"]::-webkit-clear-button that allows you you style it after your needs. It is however pretty straightforward to implement a clear-button yourself as styling the button through CSS is not supported by all browsers.
Somehow I found the way to handle it.
I've made Ref in the constructor:
...
dateRef: any;
constructor(props: Readonly<Properties>) {
super(props);
this.dateRef = React.createRef();
}
...
assigned ref to my input:
<Input
...
type='datetime-local'/
ref={this.dateRef}
...
/>
In clearForm method I set '' on UI and null value in state.
private clearForm = (event: React.FormEvent): void => {
event.preventDefault();
this.date.current.inputRef.current.value = '';
this.setState({searchQuery: EMPTY_SEARCH_QUERY});
}
Also I'm preventing from search in case when input is invalid by accesing this.dateRef.current.inputRef.current.validity.valid
Maybe this solution isn't the best but it works.
I'm trying to use jQuery and AJAX to validate that users entered a number in a particular field and that they didn't leave it blank and I'm a little confused as to why I can seem to do one, but not the other.
I'm doing this in a jQuery change() function so any time they change the value in that field, it updates it in the database without refreshing the whole page and it works fine until I try to use isNull() to validate.
I'm saving their input to a variable called UserInput and first checking to make sure it's a number with this:
if (!isNaN(UserInput))
which works perfectly. I'm also trying to check and make sure it isn't empty by using this:
if (isNull(UserInput))
Intellisense completes isNull() for me just like it did for isNaN() and all appears well in Visual Studio, it compiles without error. I've also tried isNullOrUndefined() here with a similar result, intellisense completes it for me and all seems well. Right up until I change the value in the field, at which point it promptly gives me this error:
JavaScript runtime error: 'isNull' is undefined.
I'm not sure why it's undefined (especially since intellisense is completing it for me) or how to go about defining it.
I also tried this because it seemed like it covered all the bases, not just isNull():
https://stackoverflow.com/a/5515349/8767826
and I put an alert() inside the if and I didn't get an error, but my alert didn't fire either.
The end goal is to get it to change to a zero on the client side if they leave do leave it blank.
Anyway I'm kind of stumped and I appreciate any help anyone can offer.
Thanks
There's no need for an isNull function; you can check
if (UserInput === null)
isNaN exists because NaN, unlike every other value in JavaScript, is not equal to itself.
But null doesn't mean the field is blank! If the field is blank, its value will be the empty string. Check for that instead:
if (UserInput === '')
I have a simple controlled input of type number like below.
<input type="number" value={+value} step={1} onChange={this.updateMyChange} />
My value often returns a decimal number like 123.123 . My problem is, when I try edit the value. The cursor loses focus and shifts to the beginning ignoring the whole numbers as soon as the decimal places are cleared. Like below:
How do I address this? Immediately after the decimal places are cleared, the cursor jumps to the beginning thereby making it impossible to edit the whole numbers. Any help would be appreciated.
Update
Below is the remaining code as requested by the user below.
render() {
const {value} = this.state;
return (
<input type="number" value={+value} step={1} onChange={this.updateMyChange} />
)
}
And my updateMyChange method is simply
updateMyChange(e) {
this.setState({ value: e.target.value });
}
It does nothing much simply sets the new value. The cursor position jumps to the end as soon as decimal places are cleared. It does not set cursor for whole numbers.
This is how React updates an input field's value:
node.setAttribute(attributeName, '' + value);
When you set value attribute using that method, the caret goes to the beginning of the field, regardless of using React. You can see what I am saying in this fiddle - https://jsfiddle.net/5v896g3q/
(Just try and position the cursor in the field, between changes).
According to MDN, setAttribute is unstable when dealing with value. The recommended way of changing value is by accessing the value property of the element, like element.value = newValue. If you use that approach, all seems to go as expected.
This is all I can tell for sure. Now let's speculate a little. When you type anything in that field, you are:
updating the value of the input
reading that value, and sending to React as state
React updates the value of the input, with the new state
When you are typing on the field, step 3 is likely to have no impact, because when the value comes back, the input already got it right. Except on the case with the float number. When your field reads 1., the actual value React updates the field with is 1. And React uses the evil method (setAttribute).
So, a workaround I found was setting the value of the field, using the proper method, before React touches it, on componentWillUpdate:
componentWillUpdate(nProps, nState){
this.refs.input.value = '0' + nState.value
}
The problem there, is that it is "numerizing" the value on every change, meaning I won't be able to have a point (1.). For that reason, I will only edit the input in case new value is 2 characters shorter than the old one (point + digit after point):
componentWillUpdate(nProps, nState){
if(this.state.value.length - nState.value.length === 2){
this.refs.input.value = '0' + nState.value
}
}
Working example - https://jsfiddle.net/bsoku268/3/
note: the fiddle is for demonstration purposes, and not supposed to be a bulletproof solution, as there are many ways of interacting with an input field, such as copy & paste, drag & drop, autofill, etc
I'm having a weird behavior here,
I have a field "new_field", this field is in the form, the tab where it is, is hidden, the type is string and usually doesn't have value.
Sometimes Xrm.Page.getAttribute("new_field") brings me the field with value or not. Sometimes it gets null, this only occurs when there is no value on the field.
What could cause the field returns null?
Unfortunately, Xrm.Page.getAttribute("new_field") is not very robust and it can, indeed, return null sometimes. So, as a good practice, you could check for nulls like this:
var value = Xrm.Page.getAttribute("new_field") ? Xrm.Page.getAttribute("new_field").getValue() : null;
We even put helper methods like that in a separate .js file we reuse everywhere.
Hope this helps!
I'm trying to create a simple function which, when ribbon button is pressed, sets entity attribute value to null.
Now the problem I am facing is, that the changes I make to the entity are not saved, form reloads and returns previous value.
To the button event I pass 'Task' activity attribute 'actualend'. 'Actual End' field is disabled by default.
ClearField: function (field) {
if (Xrm.Page.getAttribute(field) == null) return;
Xrm.Page.ui.controls.get(field).setDisabled(false);
Xrm.Page.getAttribute(field).setSubmitMode("always");
Xrm.Page.getAttribute(field).setValue(null);
if (Xrm.Page.data.entity.getIsDirty()) {
Xrm.Page.data.entity.save(); //also tried addOnSave(function)
}
}
Following debugger I was able to track that all changes are made correctly, except that on save() method they are 'discarded', then form reloads with previous value. This code works fine with CRM UR8 yet with CRM UR13 it does not.
Am I missing something?
As Guido mentions in his comment the code looks good which leads me to think that one of your two if statements is failing.
The first one obviously will fail if it is set to null. A little bit less obvious is that it will fail as well as if the field is not actually on the form (even though it may be a valid attribute of the entity). So step 1, ensure that your field exists on the form.
The second one I'm not sure of... I don't think getIsDirty() is keeps track of programmatic changes, so even though your programmatically updating a field and setting it to always submit, it may be returning false. Regardless of how exactly it's working, the if statement really isn't needed. The Xrm.Page.data.entity.save function will only actually save if it has some value that has changed, so I'd remove your dirty check regardless.
Eh, the problem with my issue all this time was that even though the field existed in the form, it never had an entity passed to it, therefore it was unable to save it. I've edited a ribbon button so to pass entity through CrmParameters and the issue was gone. Thank you both for supplying me with possible solutions regardless!