Pagination in Wizard Redux Form in Stateless Component - forms

i'm new to react-redux and i want some help with a task. As you can see in the redux-form documentation for a wizard for the author uses a stateful main component to create next and previous page functions using setState but in our project we must not use class base components
class WizardForm extends Component {
constructor(props) {
super(props)
this.nextPage = this.nextPage.bind(this)
this.previousPage = this.previousPage.bind(this)
this.state = {
page: 1
}
}
nextPage() {
this.setState({ page: this.state.page + 1 })
}
previousPage() {
this.setState({ page: this.state.page - 1 })
}
render() {
const { onSubmit } = this.props
const { page } = this.state
return (<div>
{page === 1 && <WizardFormFirstPage onSubmit={this.nextPage}/>}
{page === 2 && <WizardFormSecondPage previousPage={this.previousPage} onSubmit={this.nextPage}/>}
{page === 3 && <WizardFormThirdPage previousPage={this.previousPage} onSubmit={onSubmit}/>}
</div>
)
}
}
How to make this transformation correctly?

Related

How to implement an ag-grid custom floating filter with material-ui withStyles HoC?

Created an ag-grid custom floating filter with validation and need to style the filter when the validation fails with material-ui themed class using withStyles higher order component (HoC). However, when you wrap the custom floating filter with HoC onParentModelChanged doesn't get called at all.
Used hard-coded style to set the element style property but this is not allowed in the themed project using #material-ui/core v1.4.0.
Below is the custom floating filter that I created with validation and hard-coded style.
import { PropTypes } from 'prop-types';
import styles from './styles';
const DEFAULT_MIN_CHARS = 3;
const ENTER_KEY = 13;
export class CustomFloatingFilter extends Component {
constructor(props) {
super(props);
this.state = {
currentValue: '',
minChars: props.minChars ? props.minChars : DEFAULT_MIN_CHARS,
invalidFilter: false,
styles: styles()
};
this.keyPressed = this.keyPressed.bind(this);
this.valueChanged = this.valueChanged.bind(this);
this.onParentModelChanged = this.onParentModelChanged.bind(this);
this.onFloatingFilterChanged = change => {
const { minChars } = this.state;
if(change && change.model && (!change.model.filter || change.model.filter.length >= minChars)) {
return props.onFloatingFilterChanged(change);
}
return false;
};
}
keyPressed(event) {
this.setState(
{ enterPressed: event.which === ENTER_KEY },
() => {
const { enterPressed } = this.state;
if(enterPressed) { //update filter only when enter. valueChanged will handle all other cases
this.onFloatingFilterChanged(this.buildChanged());
}
}
);
}
valueChanged(event) {
const { minChars } = this.state;
this.setState(
{
currentValue: event.target.value,
invalidFilter: !!event.target.value && event.target.value.length < minChars
},
() => {
this.onFloatingFilterChanged(this.buildChanged());
}
);
}
onParentModelChanged(parentModel) {
this.setState({ currentValue: parentModel ? parentModel.filter : '' });
}
buildChanged() {
const { currentValue, enterPressed, invalidFilter } = this.state;
return {
model: {
filterType: 'text',
type: 'equals',
filter: currentValue
},
apply: !invalidFilter && (enterPressed || currentValue === '') //for applyButton:true case
};
}
render() {
const { currentValue, invalidFilter, styles } = this.state;
return (
<div style={invalidFilter ? styles.invalid : {} //eslint-disable-line
//withStyles HoC doesn't work with ag-grid floating filter component
}
>
<input className='ag-floating-filter-input' onKeyPress={this.keyPressed} onChange={this.valueChanged} value={currentValue} />
</div>
);
}
}
CustomFloatingFilter.propTypes = {
minChars: PropTypes.number,
onFloatingFilterChanged: PropTypes.func
};
export default CustomFloatingFilter;

On refresh react application I need to get from componentWillReceiveProps values for input text

I have the following problem and I really need help on that.
export class DeviceEdit extends React.PureComponent<Props> {
constructor(props) {
super(props);
this.state = {
value: ''
};
this.handleChange = this.handleChange.bind(this);
}
componentDidMount() {
let data = this.props.devices.data.find(device => device.id ===
`${deviceID}`) || {};
this.setState({ value: data.name })
}
componentWillMount() {
let data = this.props.devices.data.find(device => device.id ===
`${deviceID}`) || {};
this.setState({ value: data.name })
}
componentWillReceiveProps(newProps) {
let data = newProps.devices.data.find(device => device.id ===
`${deviceID}`) || {};
this.setState({ value: data.name })
}
handleChange(event) {
this.setState({value: event.target.value});
}
render() {
const { error } = this.props;
return (
<FormLabel>Internal ID</FormLabel>
<input type="text" defaultValue={this.state.value} onChange= .
{this.handleChange} />
</Form.Label>)
}
}
So what I want is that when I refresh the page, I want to get the the this.state.value on my input.. which in this case I am not able to do that. So I would like to know what I am doing wrong here. If I set it on value on the input I did get what I want, but then I have an warning like that:
A component is changing an uncontrolled input of type checkbox to be controlled. Input elements should not switch from uncontrolled to controlled (or vice versa). Decide between using a controlled or uncontrolled input element for the lifetime of the component
What can I do?
Actually, you should handle changes there and you can use just value on the input field instead of defaultValue.
For example:
export class AdminDeviceEdit extends React.PureComponent<Props> {
constructor(props) {
super(props);
this.state = {
value: '',
// if it comes from props by default
// you can use, if not just leave as it is
value: props.value
};
}
handleChange = e => {
this.setState({value: e.target.value});
}
render() {
const { error } = this.props;
return (
<form>
<FormLabel>Internal ID</FormLabel>
<input type="text" value={this.state.value} onChange={this.handleChange} />
</form>
)
}
}
Hope it will helps.
So from what I understand you want to make controlled input but use props.value as a default value. What if you do:
export class AdminDeviceEdit extends React.PureComponent<Props> {
constructor(props) {
super(props);
this.state = {
value: props.value,
};
this.handleChange = this.handleChange.bind(this);
}
componentWillReceiveProps(newProps) {
if(this.props.value !== newProps.value) {
this.setState({ value: newProps.value }) // reset input value
}
}
handleChange(event) {
this.setState({value: event.target.value});
}
render() {
const { error } = this.props;
return (
<FormLabel>Internal ID</FormLabel>
<input type="text" value={this.state.value} onChange={this.handleChange} />
</Form.Label>)
}
}
Certainly get rid of componentWillMount and componentDidMount. You don't need them here.

How to pass data dynamic child component in react

I am creating dynamic child components for a table.
Parent Component
class SimpleView extends Component {
constructor(props) {
super(props);
this.onAutoChange = this.onAutoChange.bind(this);
this.state = {
columns: this.createcolumns(clone(this.props.tableInfo.columns)),
dataList: this.props.data,
result: []
};
}
createcolumns(columns) {
const editColumnRender = (text, record, index) =>
<AssingCell
index={index}
columnsKey={columns[3].key}
onAutoChange={this.onAutoChange}
/>;
columns[3].render = editColumnRender;
return columns;
}
onAutoChange(value){
this.props.fetchDrivers('',value);
}
componentWillReceiveProps(nextProps){
if(nextProps.driversData && nextProps.driversData.message === 'SUCCESS' && i<1)
{
this.setState({driversResult: nextProps.driversData.data});
i=i+1;
}
}
render() {
const { columns, dataList, loading } = this.state;
return (
<TableWrapper
columns={columns}
dataSource={dataList}
/>
);
}
}
Here is a child component named AssingCell. There is a modal button inside the button. There is also one autocomplete in Modal. This.props.onAutoChange is called during every call. In this section, data is fetched from the server. How can I send this data to the child component?
Or how else can I do this?

How can I use props to auto-populate editable redux-form fields in React?

I'm new to React so I've tried to show as much code as possible here to hopefully figure this out! Basically I just want to fill form fields with properties from an object that I fetched from another API. The object is stored in the autoFill reducer. For example, I would like to fill an input with autoFill.volumeInfo.title, where the user can change the value before submitting if they want.
I used mapDispatchtoProps from the autoFill action creator, but this.props.autoFill is still appearing as undefined in the FillForm component. I'm also confused about how to then use props again to submit the form. Thanks!
My reducer:
import { AUTO_FILL } from '../actions/index';
export default function(state = null, action) {
switch(action.type) {
case AUTO_FILL:
return action.payload;
}
return state;
}
Action creator:
export const AUTO_FILL = 'AUTO_FILL';
export function autoFill(data) {
return {
type: AUTO_FILL,
payload: data
}
}
Calling the autoFill action creator:
class SelectBook extends Component {
render() {
return (
....
<button
className="btn btn-primary"
onClick={() => this.props.autoFill(this.props.result)}>
Next
</button>
);
}
}
....
function mapDispatchToProps(dispatch) {
return bindActionCreators({ autoFill }, dispatch);
}
export default connect(mapStateToProps, mapDispatchToProps)(SelectBook);
And here is the actual Form where the issues lie:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { reduxForm } from 'redux-form';
import { createBook } from '../actions/index;
class FillForm extends Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
}
onSubmit(props) {
this.props.createBook(props)
}
handleChange(event) {
this.setState({value: event.target.value});
}
render() {
const { fields: { title }, handleSubmit } = this.props;
return (
<form {...initialValues} onSubmit={handleSubmit(this.onSubmit.bind(this))}>
<input type="text" className="form-control" name="title" {...title} />
<button type="submit">Submit</button>
</form>
)
}
export default reduxForm({
form: 'AutoForm',
fields: ['title']
},
state => ({
initialValues: {
title: state.autoFill.volumeInfo.title
}
}), {createBook})(FillForm)
I think you're mixing up connect and reduxForm decorators in the actual form component. Currently your code looks like this (annotations added by me):
export default reduxForm({
// redux form options
form: 'AutoForm',
fields: ['title']
},
// is this supposed to be mapStateToProps?
state => ({
initialValues: {
title: state.autoFill.volumeInfo.title
}
}),
/// and is this mapDispatchToProps?
{createBook})(FillForm)
If this is the case, then the fix should be as simple as using the connect decorator as it should be (I also recommend separating this connect props to their own variables to minimize confusions like this):
const mapStateToProps = state => ({
initialValues: {
title: state.autoFill.volumeInfo.title
}
})
const mapDispatchToProps = { createBook }
export default connect(mapStateToProps, mapDispatchToProps)(
reduxForm({ form: 'AutoForm', fields: ['title'] })(FillForm)
)
Hope this helps!

Dynamically include files (components) and dynamically inject those components

Looking around the next I could not find the answer: How do I dynamicly include a file, based on prop change per say: here some sudo code to intrastate what I'm trying to do!
class Test extends React.Component {
constructor(props){
super(props)
this.state = { componentIncluded: false }
includeFile() {
require(this.props.componetFileDir) // e.g. ./file/dir/comp.js
this.setState({ componentIncluded: true });
}
render() {
return(
<div className="card">
<button onClick={this.includeFile}> Load File </button>
{ this.state.componentIncluded &&
<this.state.customComponent />
}
</div>
)
}
}
so this.props.componetFileDir has access to the file dir, but I need to dynamically include it, and can't really do require() as its seems to running before the action onClick get called. Any help would be great.
Em, Your code looks a bit wrong to me. So I created a separate demo for dynamic inject components.
While in different situation you can use different React lifecycle functions to inject your component. Like componentWillReceiveProps or componentWillUpdate.
componentDidMount() {
// dynamically inject a Button component.
System.import('../../../components/Button')
.then((component) => {
// update the state to render the component.
this.setState({
component: component.default,
});
});
}
render() {
let Button = null;
if (this.state.component !== null) {
Button = this.state.component;
}
return (
<div>
{ this.state.component !== null ? <Button>OK</Button> : false }
</div>
);
}
After you edited your code, it should be something similar to below:
class Test extends React.Component {
constructor(props){
super(props)
this.state = { customComponent: null }
this.includeFile = this.includeFile.bind(this);
}
includeFile() {
System.import(this.props.componetFileDir)
.then((component) => {
this.setState({ customComponent: component.default });
});
}
render() {
return(
<div className="card">
<button onClick={this.includeFile}> Load File </button>
{
this.state.customComponent
}
</div>
)
}
}