class ProductTheme extends Component{
constructor(props){
super(props);
this.state = { activePage : 1 , formValues: {}, totalPages:10}
}
render(){
const {handleSubmit} = this.props;
const page = this.state.totalPages;
return(
<div><ThemesNavBar/>
<div className="container" id="PTConatiner">
<h2>Product Explainer Information</h2>
<div className = "container">
<form className="form-inline" onSubmit = {handleSubmit(this.onSubmit.bind(this))}>
<Field label="Meet" value={this.state.formValues["cname"]} onChange={this.handleChange.bind(this, 'svgObject','cname', 'cprofession')} name="cname" component={ this.renderField}/>
<Field label="He's" value={this.state.formValues["cprofession"]} onChange={this.handleChange.bind(this, 'svgObject','cname', 'cprofession')} name="cprofession" component={ this.renderField}/>
</form>
</div>
<object type="image/svg+xml" ref="svgObject" data={require("./images/svg files/Scene_01.svg")} id='svgObject' ></object>
<div id="screenPage02">
<Field label="He's Struggling To" value={this.state.formValues["struggling"]} onChange={this.handleChange.bind(this)} name="struggling" component={ this.renderField}/>
<object type="image/svg+xml" ref="svgObject01" data={require("./images/svg files/Scene_02.svg")} id='svgObject01' ></object>
</div>
{divData.map((data)=>{
console.log(data);
})}
<Pagination
prev
next
first
last
boundaryLinks
items={page}
maxButtons={2}
activePage={this.state.activePage}
onSelect={this.handleSelect.bind(this)}
/>
</div></div>
);
};
};
Hi , when user clicks on a particular no in pagination it should change to the div which is related to it how to do it with React ? i had a look at some NPM modules but those are not working for me ?
I guess you approach is not correct you must not load a new component or div each time , either you can go for changing div content as page changes only content must change that you can do with keeping data in state and load limited data what required for first page , once page changes , change div with that slot of data.
You should store your curent page data in component state or in Redux store.
Your source code is too short to understand your case. I don't know which Pagination library you use.
If you want similar solution with source check:
Demo
Github
Related
I am new to React/JS and have been trying for a few days to figure out how to keep track of which Collection below is selected.
I want the user to be able to click on the collection div and trigger the selected badge (commented out in the code, but I've included it in the screenshots) for that specific collection div. Upon clicking on a new div, the original div should have the badge remove and the newly clicked upon div should have the new badge. In other words, only one collection should have the badge at any point in time. I want to keep track of this in the Collection component's state (unless there is a better way).
For more reference, each collection div is a card that is highlighted upon hover. The site is also deployed at https://gatsby-client.rishipr.now.sh/practice.
Collection.js
import React, { Component } from "react"
class Collection extends Component {
render() {
return (
<div className="collection">
<div className="collection-name">
{this.props.name}{" "}
{/* <span className="collection-selected-badge">SELECTED</span> */}
</div>
<div className="collection-description">{this.props.description}</div>
<div className="collection-description">
{this.props.numQuestions} questions
</div>
</div>
)
}
}
export default Collection
CollectionList.js
import React from "react"
import Collection from "./collection"
const CollectionList = props => {
return (
<div className="collections">
<Collection
name="All Questions"
description="All questions (technical & behavioral)"
numQuestions="400"
/>
<Collection
name="Top Behavioral"
description="The most common behavioral questions to prepare for"
numQuestions="21"
/>
<Collection
name="Outside the Guide"
description="Questions from outside BIWS 400 and WSO"
numQuestions="12"
/>
<Collection
name="20 Must Know Questions"
description="The 20 must-know interview questions"
numQuestions="20"
/>
<Collection
name="Real IB Interview Questions"
description="Questions from real interviews at various banks"
numQuestions="16"
/>
<Collection
name="Brain Teasers"
description="Common brain teasers"
numQuestions="4"
/>
</div>
)
}
export default CollectionList
Add state to your CollectionList component, storing the name of the selected Collection:
const CollectionList = props => {
const [selected, setSelected] = useState(null);
return (
// ...
)
}
Pass the selected and setSelected props to all of your Collection component:
<Collection
name="All Questions"
description="All questions (technical & behavioral)"
numQuestions="400"
selected={selected}
setSelected={setSelected}
/>
Add an onClick method to the outer div of your Collection component, which sets the selected state value to the name of the current Collection:
<div
className="collection"
onClick={() => this.props.setSelected(this.props.name)}
>
// ...
</div>
Check if the selected prop is the same as the current collection's name in your Collection component. If true display the selected badge:
{this.props.selected === this.props.name && (
<span className="collection-selected-badge">SELECTED</span>
)}
Here's a codesandbox example, though not as pretty as the image you provided.
Help needed please,
I am currently learning react and I ran into an issues of some sort while creating a blog app.
I nested components within each other, however updated data is not received in subcomponent unless I refresh the page of the nested-component. Below is snippet of my codeWithin the AccountOverview component is another component(container) that handles a form. Once the form submits data and the backend processes the data, i expect that the AccountOverview component will render new info. However if i then go back to the parent (dashboard) and make an edit the AccountOverview component does't display newly created data except on a full-page refresh.
class Dashboard extends Component {
state = {}
componentDidMount(){
this.props.getCurrentProfile();
}
render() {
const { user } = this.props.auth;
const { profile, loading } = this.props.profile;
return (
<div style={{margin: "0", padding: "0"}}>
<Header title="Account Dashboard" />
<section id="accountPage" className="">
<div className="container">
<div className="row">
<Sidebar />
<main className="col-sm-9 col-md-9 account">
<div className="dashboard">
<AccountOverviewPanel
user={user} profile={profile} loading={loading}
/>
<PostTablePanel />
</div>
</main>
</div>
</div>
</section>
</div>
);
};
};
Is your submit action casusing your components to unmount.
I tried cloning your code. it seems to miss a file for keys hence couldn't run it
I have a React project that generates some DOM elements "dynamically" within JSX:
<div className='ui form'>
<h2 className="header">{subtype}</h2>
{
subtypes[subtype].fields.map((field) =>
<div className='field' key={field.name}>
<label>{field.label}</label>
<input name={field.name}
value={entity[field.name]}
onChange={onInputChange}/>
</div>
)
}
</div>
For a specific component, the generated input fields don't ever change during the life of the application (only their props change), so it is just a way to generate forms that are actually static.
So it is exactly equivalent to this "static" JSX:
<div className='ui form'>
<h2 className="header">{subtype}</h2>
<div className='field' key='field1'>
<label>Field 1</label>
<input name='field1'
value={entity['field1']}
onChange={onInputChange}/>
</div>
<div className='field' key='field2'>
<label>Field 2</label>
<input name='field2'
value={entity['field2']}
onChange={onInputChange}/>
</div>
</div>
If I used the first code snippet, then the HTML DOM elements get recreated on every change to state / props. If I use the second snippet, then the HTML appears to be unchanged and only the field values are updated (React can detect in the second instance that the virtual DOM elements are still the same, but not in the first instance)
Is there a way for me to create the "dynamic" virtual DOM in the first code example in a way that it can be cached and reused so that React sees it as being the same on each render?
Many thanks
Where is subtypes coming from? From what I understand you are receiving this in the component's props. If that is the case, you need to store this variable in this component's state. Then, you need to update it's state in it's componentWillReceiveProps lifecycle function.
The thing is, your component will only re-render when it's setState function is called. Hence, the components will not re-render when it's props change (after it has already been mounted).
class SimpleCom extends React.Component {
constructor(props) {
super(props);
this.state = {
subtypes: props.subtypes
}
}
componentWillReceiveProps(props) {
this.setState({
subtypes: props.subtypes
});
}
render() {
const subtypes = this.state.subtypes;
return (
<div className='ui form'>
<h2 className="header">{subtype}</h2>
{
subtypes[subtype].fields.map((field) =>
<div className='field' key={field.name}>
<label>{field.label}</label>
<input name={field.name}
value={entity[field.name]}
onChange={onInputChange}/>
</div>
)
}
</div>
);
}
}
Let's say I have a Card that contains a login Form
<Card>
<LoginForm/>
</Card>
How do I access the nodes from the Form within the Card render function?
<Form >
<input type="text" name="email"/>
<input type="password" name="password"/>
<input type="submit"/>
</Form>
Because what i´d like to do is to render the submitbutton not within the props.children context but render it wrapped outside of the given child!
render () {
return (
<div className="card">
<div className="inner">
{/* render Children */}
{this.props.children != undefined ?
<div className="childrenWrapper">
{this.props.children}
</div>
: ""
}
</div>
{/* render submit from login form here, not above */
</div>)
There are some components which actually do what I want. For example the Tabs component from react-toolbox. They somehow manage to render what's within the Tab (children) somewhere else
Just for instance
<Tabs index={this.state.inverseIndex} onChange={this.handleInverseTabChange} inverse>
<Tab label='First'><small>First Content</small></Tab>
<Tab label='Second'><small>Second Content</small></Tab>
<Tab label='Third'><small>Third Content</small></Tab>
<Tab label='Disabled' disabled><small>Disabled Content</small></Tab>
</Tabs>
Which will lead to the following html
As you can see the children from the tab where rendered within their own section
I do not want to change anything on the Form to solve this problem, I would like to pass the Form into the Card and let the Card decide how the Form will be rendered within the card render function.
Since I'm trying to implement the Google Material Design Card component and just use it as a template there are more elements coming which will need to be split up and placed at the positions I want them to be. The thing is I could actually place the relevant HTML around the Form to get it as the Card I want it to be, but then I wouldn't need the component at all.
There are some decent answers here, but none of them directly answer your question. Therefore, even though you should refactor your code (as elucidated below), I am going to provide you a working solution:
class Card extends React.Component {
constructor() {
super();
this.state = {};
}
render() {
console.log(typeof this.props.children)
return (
<div>
{typeof this.props.children === 'object'
? React.cloneElement(this.props.children, { ref: (n) => this.form = n })
: null}
<button onClick={(e) => console.log(this.form.data)}>submit</button>
</div>
);
}
}
class Form extends React.Component {
constructor() {
super();
this.onChange = this.onChange.bind(this);
this.state = {};
}
onChange(e) {
this.data = e.target.value;
}
render() {
return (
<form>
<input type="text" onChange={this.onChange} />
</form>
);
}
}
ReactDOM.render(
<Card><Form /></Card>,
document.getElementById('container')
);
https://jsbin.com/fohehogozo/edit?js,console,output
By setting a property on the instance, you can then access that property from children by using a ref. I checked for typeof === object here, because there was only one child.
WARNING: this code is NOT PRODUCTION READY. Do not ever run this in production. The code I have demonstrated is a terrible hack, and you should never try this at home.
If you are trying to submit a form, maybe look at passing down an onChange event and storing the value (based on the name of the field) in the state of the Card. Then attach the onChange event on the inputs so as soon as they're updated, the data will be passed back up to the container for you to submit.
If you would like to split up the childrens passed, you can simply filter the children array to split up the children, however your childrens seem to be nested.
Why dont you let the cards children handle the separation between your inner container and other content?
I think restructuring in this case is more suitable than modifying the passed children property.
Also, pulling the submit button out of the actual form tags, would break your form as it would no longer submit without some custom connection between the button and the actual form.
Don't try to manipulate the DOM; it's generally an anti-pattern in React (though there are a few valid use cases). In your case, rather than literally trying to move the elements, I'd simply hide the button in the form and add it to the parent.
Assuming you have access to the internals of <LoginForm>, you can add a prop to hide the button:
const button =
<div class="flatbuttonWrapper">
<input type="submit"/>
</div>;
<Form>
<input type="text" name="email"/>
<input type="password" name="password"/>
{!this.props.hideButton && button}
</Form>
Add the button to the Card component:
render() {
return (
<div className="card">
<div className="inner">
{this.props.children != undefined ?
<div className="childrenWrapper">
{this.props.children}
</div>
: ""
}
</div>
<div class="flatbuttonWrapper">
<input type="submit"/>
</div>
</div>
);
}
Finally, in your parent:
<Card>
<LoginForm hideButton />
</Card>
All that said, it really feels like you need to structure your code better and break some of these components up into smaller, more reusable pieces. For example, the Card component probably shouldn't be affecting the button's style or conditionally rendering children; it should just add a frame around any children. Then you can create a more complex component that composes these simpler sub-components to to whatever you need.
I have for example this code below :
<AjaxForm>
<input type="hidden" name="xxx" value="xxx" />
<div className="grid">
<div className="gdcol-xs-11">
[[SUBMIT_BUTTON]]
</div>
<div className="gdcol-xs-11">
[[CANCEL_BUTTON]]
</div>
</div>
</AjaxForm>
And I would like, for example, be able in the AjaxForm component to replace the tag placeholder 'SUBMIT_BUTTON' by this :
<a href="javascript:void(0);" onClick={this.handleSubmit}>VALIDATE</a>
Is there a way to do this by iterating on this.props.children in the AjaxForm component ?
Is this possible to find some text pattern by crawling all the children ?
Should I have to use refs or a key ?
Thank you in advance !
---- EDIT
To add some informations, this is the render of the AjaxForm Component
return (
<form action="" method="post" ref={this.ajaxRef} id={this.props.id} onSubmit={this.onSubmit}>
<input type="hidden" name="form_id" value={this.props.id} />
{this.props.children}
<input type="submit" value="" className="fake-submit" />
<div id={("ajax-") + this.props.id + ("-messages-container")} className="ajax-form-messages"></div>
</form>
)
I think I understand your issue now. You're generating a component inside AjaxForm and you want to be able to place that component dynamically. In that case you should create another component called AjaxFormContents (or whatever your specific form should be called) which receives your generated component via props and places it wherever you want.
// AjaxForm.js
...
render() {
return React.cloneElement(this.props.children, {
submitButton: this.generateSubmitButton() // or however you're doing it
})
}
...
Now whatever component you put as a child will have access to this component.
// AjaxFormContents.js
...
render() {
return ( // arrange your form contents however you like!
<div>
<input />
{ this.props.submitButton }
</div>
)
}
Then in your parent component:
// Parent.js
...
render() {
return (
<AjaxForm>
<AjaxFormContents />
</AjaxForm>
)
}
This should work, however another approach -- using a higher order component (HOC) would be a nice solution here as well, because your AjaxForm doesn't display anything, it just wraps your form contents.. instead AjaxForm can be an HOC which passes a generated submit button component to the wrapped component.
var ajaxForm = function (WrappedComponent) {
return React.createClass({
generateSubmitButton() {
return <a>your special submit button </a>
},
render() {
<WrappedComponent submitButton={ this.generateSubmitButton() } />
}
})
}
Then you can have the exact same AjaxFormContents component as above and when you export it:
// or module.exports, whichever one you're using.
export default ajaxForm(AjaxFormContents)