redux-form Field with AutoComplete using redux-form-material-ui - material-ui

I am working on a AutoComplete Field in redux-form and found this solution. Thought this will help someone using material-ui or redux-form-material-ui and looking to get rid of muiTheme errors. For my case I found it simple using react-select.
{/* Libraries you need */}
import {AutoComplete as MUIAutoComplete} from 'material-ui'
import { AutoComplete } from 'redux-form-material-ui'
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider'
import { reduxForm, Field, Fields, formValueSelector, change } from 'redux-form'
{/* redux-form Field component for Text Input using AutoComplete */}
<MuiThemeProvider>
<Field
name="searchByText"
label="Search Suggestions"
component={AutoComplete}
floatingLabelText="Search By Suggestions"
openOnFocus
filter={MUIAutoComplete.fuzzyFilter}
dataSource={searchSuggestionList} //array list of suggestions
onChange={this.handleSearchByTextChange} //handle the onChange event by handleSearchByTextChange func
onBlur={() => {}}
/>
</MuiThemeProvider>

Related

How do I make the MUI Dialog title an H1 element so the modal is accessible

I'm working on making my app more accessible and am struggling with the MUI Dialog component. I'm using the DialogTitle component, which creates an H2 element and am getting an issue of "page doesn't contain a level-one heading". Should I be creating my modal in some other way, or are MUI Dialogs just not accessible?
import { Dialog, DialogTitle } from '#mui/material';
const MyModal = () => {
return (
<Dialog open={true}>
<DialogTitle>
My Title
</DialogTitle>
</Dialog>
);
};
export default MyModal;
Updated for MUI v5:
The Dialog component API includes a helper DialogTitle component which, by default, renders its contents within an h2 element. To change this functionality, you can pass the component property to the DialogTitle to have the DialogTitle rendered using whatever elementType that you wish. For example:
<DialogTitle component="h1">
My Dialog Title
</DialogTitle>
This is currently an undocumented feature of DialogTitle, but it can been seen in the source code that properties that are passed to DialogTitle are spread onto the underlying Typography component -- By passing component, you are essentially overwriting the hardcoded component="h2" prop with your own value.
Working example: https://codesandbox.io/s/simpledialog-material-demo-forked-kpq9k?file=/demo.js
Original answer for MUI v4:
The Dialog component API includes a helper DialogTitle component which, by default, renders its contents within an h2 element. To disable this functionality, you can use the DialogTitle component with the disableTypography prop (to disable the h2 wrapping behavior) and then include your own Typography component set to h1. For example:
<DialogTitle disableTypography>
<Typography variant="h1">My Dialog Title</Typography>
</DialogTitle>
Working example: https://codesandbox.io/s/material-demo-forked-7pso2?file=/demo.js
Extra Credit: You may then come across the problem that the h1 is styled "too large" for your design. If so, and you prefer the h2 look, you can use the Typography prop named component in combination with the variant prop to visually style it back to an h2, while maintaining the underlying h1 element. For example:
<DialogTitle disableTypography>
<Typography variant="h2" component="h1">My Dialog Title</Typography>
</DialogTitle>
In the case of TypeScript there's no typing provided so you need to do a hack:
<DialogTitle {...{ component: 'div' } as any}>
<Typography variant="h1">My Dialog Title</Typography>
</DialogTitle>
This is a temporary hack until they add the typing for all the props there.
As #Steve mentionned, in Mui v5, the job is harder. Even if you specify a component prop (which won't work in TS, moreover it's a bad practice), it won't change the style as it renders a h2 with a h6-style.
The cleanest workaround would be to mess with CSS (in a styled component for eg)
// Styling
import { styled } from "#mui/system";
// UI
import { DialogTitle as MuiDialogTitle } from "#mui/material";
const DialogTitle = styled(MuiDialogTitle)(({ theme }) => ({
"&.MuiDialogTitle-root.MuiTypography-root": {
fontSize: 25,
fontWeight: "bold",
},
}));

How to simulate ionBlur in tests

Maybe I'll start with what I want to achieve: I have a form with a required field. By default it should not display any error. The error should be displayed if a user touches the field. So my field looks more or less like this:
<ion-input .... (ionBlur)="updateDispayedErrors()"></ion-input>
But I don't know how to test it because:
Running fixture.debugElement.nativeElement.blur() does not triggers ionBlur handler (the same with ....dispatchEvent(new Event('blur')))
Plain angular (blur) does not work (i.e. if I change the code to (blur)="updateDisplayErrors()" then it does not work)
It seems that calling blur() method on native <input .../> element that is created in the browser would work but... the problem is that when I run the tests fixture.debugElement.nativeElement.childNodes is empty... So the native <input .../> is not created
Please let me know if you would like to see a full example to illustrate it.
If you add a selector to ion-input like:
<ion-input .... (ionBlur)="updateDisplayedErrors()" id="specialInput"></ion-input>
Then you can use fixture.debugElement.triggerEventHandler:
import { By } from '#angular/platform-browser';
...
it('should emit ionBlur', () => {
const ionDe = fixture.debugElement.query(By.css('#specialInput'));
const ionBlurResult = spyOn(component, 'updateDisplayedErrors');
ionDe.triggerEventHandler('ionBlur', {});
expect(ionBlurResult).toHaveBeenCalled();
});

Material-UI: "The key provided to the classes property is not implemented"

I am using the withStyles() HOC to override some MUI component styles, theme and breakpoints.
There is obviously something I do not understand here as I keep getting errors such as this one:
Warning: Material-UI: the key tab provided to the classes property
is not implemented in Items.
You can only override one of the following:
card,details,content,cover,avatar,lock
Example code: https://codesandbox.io/s/6xwz50kxn3
I have a <List /> component and its child <Items />.
My intention is to apply the styles in the demo.js file only to the <List /> component, and the styles in the demoChild.js to the <Items /> Component.
I would really appreciate an explanation of what I'm doing wrong, and maybe a solution?
Note: I have found other posts with the same error, but they seem to have something different to my example.
The warnings are caused by this line in your demo.js file:
<Items {...this.props} items={items} />
You're spreading all of List's props down into your Items. One of these props is classes, containing all of the CSS classes you define in demo.js. Since those are intended for List, they include CSS classes that are implemented by List but not Items. Since Items is receiving this prop, it's reading it as you trying to override classes that aren't available and warning you about it.
You can fix this problem by spreading only the unused props:
// Use other to capture only the props you're not using in List
const { classes, headerIsHidden, ...other } = this.props;
// Then spread only those unused props
<Items {...other} items={items} /
Then, you won't be spreading classes object into Items, so you won't get any warnings about classes that aren't implemented.
In my case, I want to reuse multiple styles in different files, so I wrote a helper function:
import { withStyles } from '#material-ui/core/styles'
// Fixed: material-ui "The key provided to the classes property is not implemented"
const withMultipleStyles = (...params) => {
return withStyles((theme) => {
var styles = {}
for (var len = params.length, key = 0; key < len; key++) {
styles = Object.assign(styles, params[key](theme));
}
return styles
})
}
export default withMultipleStyles
Usage:
import React from 'react'
import compose from 'recompose/compose'
import { connect } from 'react-redux'
import { style1, style2, withMultipleStyles } from '../../styles'
class your_class_name_here extends React.Component {
// your implementation
}
export default compose(
withMultipleStyles(style1, style2),
withWidth(),
connect(mapStateToProps, mapDispatchToProps)
)(your_class_name_here)

TextField is not getting updated on re-render with different intialValues

I'm using redux-form-material-ui for the forms. I have simple form with two text fields. This form will show the initalValues passed to it and user can also update the values of TextField. These TextFields working fine with validations and all but I'm facing problem while re-rendering. On route change, I'm passing the different intialValues to that form component but even though proper values passed to it, TextFields are not getting updated. It just shows the first time passed initialValues.
Here is my code:
From parent component:
<ReduxForm {...initialValues} />
ReduxForm component:
class ReduxForm extends React.Component {
render () {
return (
<div>
<form onSubmit={() => console.log('Submitted')} >
<Field
className='input-field'
name='name'
component={TextField}
floatingLabelText='Full Name'
/>
<Field
className='input-field'
name='email'
component={TextField}
floatingLabelText='Email'
/>
</form>
</div>
)
}
}
export default reduxForm({
form: 'test-form',
validate
})(ReduxForm)
I Know that, this is the same problem with defaultValue in material-ui's TextField. Is this expected behavior in redux-form-material-ui also? If so, is there way I can solve this issue without setting the state and all?
Thank you!
Haven't used redux-form-material-ui but try adding enableReinitialize: true to your reduxForm decorator
export default reduxForm({
form: 'test-form',
validate,
enableReinitialize: true
})(ReduxForm);
And see if that works.

React - Redux, submit a form with data from child components

I have a component which is a form, with a number of child components. What is the best way to consolidate the data from all of the child components, when submitting the form? Below is one idea, is this the correct method? I pass a reference to a function that will update a property of a form upon change in a component. What is best practice? Thanks.
import React from 'react';
import { Component , PropTypes} from 'react';
import { connect } from 'react-redux';
import { saveData } from '../actions/index'
import {bindActionCreators} from 'redux';
export default class MyClass extends Component {
constructor(props) {
super (props);
this.formData = {};
this.setFormData = this.setFormData.bind(this);
this.onSubmitHandler = this.onSubmitHandler.bind(this);
}
setFormData(key, value){
this.formData[key] = value;
}
onSubmitHandler(evt){
this.props.saveData(this.formData);
}
render (){
return (
<div>
<form onSubmit = {this.onSubmitHandler} >
<div >
<NameComponent setFormData = {this.setFormData}/>
<AddressComponent setFormData = {this.setFormData}/>
//...lots more components
</form>
</div>
);
}
}
export default connect( mapStateToProps, {saveData)(MyClass)
Yes, this approach is correct, because children are generally expected to delegate to parent that is responsible for them. In fact, that's how Redux Form works. <Field /> input components delegate their state to a Higher Order <Form /> wrapper.
The problem with your approach is that you have to do a lot of repetitive stuff on your own (such as calling onChange, delegating the value etc).
We use Redux Form for one of our projects and it's great as it integrates forms, react and redux. I find myself writing much less code and there is build in validation for both remote, local submission, submission from child components and other neat stuff.
My suggestion is to go with Redux Form instead of reinventing the wheel.