Right now I have a UI that allows users to load files from their computer to a list of the files, an input that puts a photo in the area, and text field for the title, date, and description.
Here's my code:
class RBD extends Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
this.onDragEnd = this.onDragEnd.bind(this);
this.state = {
files: [],
};
}
handleClick = event => {
// Helper code to read file and return promise
const readFile = (file) => {
// const fileList = [];
const fileReader = new FileReader();
// create the promise and return it
return new Promise((resolve, reject) => {
// if file reader has an error, report it
fileReader.onerror = (error) => {
reject({ error })
}
// if success, resolve the promise
fileReader.onload = (e) => {
resolve({
name: file.name.replace( /_|\.mp3/gi, " "),
link: e.target.result
})
}
// start reading the file
fileReader.readAsDataURL(file);
})
}
// create all the file reader promises
// create an array from the files list and use map to generate
// an array of promises
const allReaders = Array.from(event.target.files).map(readFile)
// Now handle the array of promises we just created
Promise.all(allReaders)
.then(fileList => {
console.log(fileList)
// set the state that we have all the files
this.setState({ files: fileList });
})
.catch(error => {
console.error(error)
});
}
render() {
return (
<div className="downloadMusic">
<div className="input">
<input
accept="audio/*"
onChange={this.handleClick}
id="upload-file"
className="inputName"
type="file"
multiple
ref={this.inputRef}
/>
</div>
<div>{this.state.files.length > 0 && <Downloaded/>}</div>
<DragDropContext onDragEnd={this.onDragEnd}>
<Droppable droppableId="droppable">
{(provided, snapshot) => (
<div
{...provided.droppableProps}
ref={provided.innerRef}
style={getListStyle(snapshot.isDraggingOver)}
>
{this.state.files.map((file, index) => (
<Draggable key={file.name} draggableId={file.name} index={index}>
{(provided, snapshot) => (
<div
ref={provided.innerRef}
{...provided.draggableProps}
style={getItemStyle(
snapshot.isDragging,
provided.draggableProps.style
)}
>
<div className="handle">
<Handle {...provided.dragHandleProps}/>
</div>
<div>
<form>
<label>
<p> <input type="text" defaultValue={file.name} name="name" style={{width:'600px', height:'30px', fontSize: '16px'}} /></p>
</label>
</form>
</div>
<div className="delete">
<LIDelete onClick = {() => this.removeItem(index)}/>
</div>
</div>
)}
</Draggable>
))}
{provided.placeholder}
</div>
)}
</Droppable>
</DragDropContext>
</div>
);
}
}
export default RBD;
const Downloaded = (props) => {
return(
<div className="main-content">
<div className="container">
<div className="downloaded">
<div className="image"><ImageUpload/></div>
<form className="downloaded-form" action="/action_page.php">
<label>
Title:
<input className="title" type="text" name="downloaded-name" placeholder="Title"/>
</label>
<br/>
<br/>
<label>
Release Date:
<input type="date" name="date" />
</label>
<br/>
<br/>
<textarea rows="12" cols="50" placeholder="Add Description"/>
</form>
</div>
</div>
</div>
);
};
export default Downloaded;
class ImageUpload extends React.Component {
constructor(props) {
super(props);
this.state = { file: null };
this.onChange = this.onChange.bind(this);
}
onChange(event) {
this.setState({
file: URL.createObjectURL(event.target.files[0])
});
}
resetFile(event) {
event.preventDefault();
this.setState({ file: null });
}
render() {
return (
<div>
<label>
Choose Cover:
<input type="file" accept="image/*" onChange={this.onChange} />
</label>
<div className="image" style={{ width: '300px', height: '300px',
border: '1px dotted black', position: 'absolute'}}>
{this.state.file && (
<img style={{ width: "300px", height: "300px"}} src={this.state.file} />
)}
</div>
{this.state.file && (
<div>
<button style={{marginTop: '300px'}} onClick={this.resetFile}>Remove File</button>
</div>
)}
</div>
);
}
}
export default ImageUpload;
So my question is how do I take this information and store it on a feed with the photo, title, and description and also in the users profile with all the above and also the list into a playlist (I think I know how to write the playlist I just need to know how to transfer the information. I'm guessing by using props but how?).
Related
I have a tab component with 2 tabs. The first tab contains a list of employees and a button that transfers you in the second tab (contact form) containing the data of the selected employee. In the first tab I create an object of an employee, send it in the second tab and in the second tab i set the state.name, state.surname with the object values.
The problem is that in order to load the data in the form I need to change back in the first tab and go to the second tab again.
The tabs component
import React from 'react';
function TabPanel(props) {
const { children, value, index, ...other } = props;
return (
<div
role="tabpanel"
hidden={value !== index}
id={`simple-tabpanel-${index}`}
aria-labelledby={`simple-tab-${index}`}
{...other}
>
{value === index && (
<Box p={3}>
<Typography>{children}</Typography>
</Box>
)}
</div>
);
}
TabPanel.propTypes = {
children: PropTypes.node,
index: PropTypes.any.isRequired,
value: PropTypes.any.isRequired,
};
function a11yProps(index) {
return {
id: `simple-tab-${index}`,
'aria-controls': `simple-tabpanel-${index}`,
};
}
var importErg = new Boolean(false);
export function getImport(){
return importErg;
}
export const globalErg = {
onoma: "",
epitheto: ""
}
export function getGlobalErg(){
return globalErg;
}
async function getErgByeID(ErgEid){
globalErg.onoma = ""
globalErg.epitheto = ""
await fetch(URL+"/ergazomenoi?eid=eq."+ErgEid)
.then(response => {if(response.ok){
return response.json()
}
else {
alert('Something went wrong')
throw new Error('Something went wrong');
}
})
.then(data => {
globalErg.onoma = data[0].onoma
globalErg.epitheto = data[0].epitheto
}
)
}
export default function SimpleTabs() {
const [value, setValue] = React.useState(0);
const handleChange = (event, newValue) => {
setValue(newValue);
};
function more(ergID){
setValue(1);
getErgByeID(ergID);
}
}
return (
<div className="main">
<AppBar position="static" id = "topbar">
<Tabs value={value} onChange={handleChange}>
<Tab label="Employees" {...a11yProps(0)}/>
<Tab label="Contact" {...a11yProps(1)} />
</Tabs>
</AppBar>
<TabPanel value={value} index={0}>
<Table />
<Button style={{color: "#fff", background: "#111", marginRight: "2.5px", marginLeft:"2.5px", marginTop:"5px"}} onClick={() => more()}>
Contact
</Button>
</TabPanel>
<TabPanel value={value} index={1} id = 'tab'>
<Contact/>
</TabPanel>
</div>
);
}
the form component
import React, { Component, useEffect } from "react";
import {getGlobalErg} from "./Proswpiko-tabs";
class Personal_info extends Component {
constructor(props){
super(props);
let erg = getGlobalErg();
this.state = {
onoma: erg.onoma,
epitheto: erg.epitheto,
};
}
onomaChangeHandler = (event) => {
this.setState({onoma: event.target.value});
}
epithetoChangeHandler = (event) => {
this.setState({epitheto: event.target.value});
}
render() {
return (
<form onSubmit = {this.SubmitHandler}>
<div >
<p id = "topText" align = "center">
<h2>Contact info</h2>
</p>
<img id="top" src="top.png" alt=""></img>
<div id="form_container">
<form id="form" class="appnitro" method="post" action="">
<div class="form_description">
<h2>Personal info</h2>
</div>
<ul>
<li id = "li_3">
<label class="description" for="element_3" >Όνομα </label>
<span>
<input type ="text" id="nameInput" name= "nameInput" class="element text" maxLength="255" size="15" onChange={this.onomaChangeHandler} value = {this.state.onoma} required/>
<label>Name</label>
</span>
<span>
<input type ="text" id="surNameInput" name= "surNameInput" class="element text" maxLength="255" size="14" onChange={this.epithetoChangeHandler} value = {this.state.epitheto} required/>
<label>Surname</label>
</span>
</li>
</ul>
</form>
<div id="footer">
</div>
</div>
<img id="bottom" src="bottom.png" alt=""></img>
</div>
</form>
);}}
export default Personal_info;
It seems that since the setState func is async It didnt had time to fill the imput boxes.
Solution: Added setTimeout and now everything works fine
What I am trying to do is clear my container div when the user hits the search button so all the existing search results are removed.
The problem is I am using innerHTML to clear the container div but it only works for the first time.
If you search for something for the second time then you will see no results are rendered.
I've just started learning reactjs.
Here is my code (I have removed the API key and the id just FYI).
import React from "react";
import Recipe from "./Recipe";
import "./styles.css";
export default class App extends React.Component {
constructor() {
super();
this.state = {
searchQuery: "Icecream",
searchData: [],
error: false,
loader: false
};
this.handleSubmit = this.handleSubmit.bind(this);
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
this.setState({
[e.target.name]: e.target.value
});
}
handleSubmit(e) {
e.preventDefault();
document.querySelector(".control.field").classList.add("is-loading");
this.setState({
error: false,
loader: true
});
document.querySelector(".columns").innerHTML = "test";
fetch(
`https://api.edamam.com/search?q=${
this.state.searchQuery
}&app_id=id&app_key=key`
)
.then(response => response.json())
.then(data => {
this.setState({
searchData: data.hits
});
})
.catch(err => {
this.setState({
error: true
});
})
.finally(() => {
document.querySelector(".control.field").classList.remove("is-loading");
this.setState({
loader: false
});
});
}
renderIngredients = arr => arr.map((el, index) => <li key={index}>{el}</li>);
render() {
let result;
result = this.state.searchData.map((el, index) => (
<Recipe
key={index}
image={el.recipe.image}
title={el.recipe.label}
ingredients={this.renderIngredients(el.recipe.ingredientLines)}
/>
));
return (
<div>
<form className="px-3 py-3" onSubmit={this.handleSubmit}>
<div className="field is-grouped">
<p className="control field is-expanded">
<input
className="input is-rounded"
type="text"
placeholder="Find a recipe"
name="searchQuery"
value={this.state.searchQuery}
onChange={this.handleChange}
/>
</p>
<p className="control">
<button className="button is-primary">Search</button>
</p>
</div>
</form>
{this.state.loader ? (
<div className="spinner-box">
<div className="three-quarter-spinner" />
</div>
) : (
""
)}
{this.state.error ? (
<div className="px-3 py-3">
<div className="notification is-danger">
Some error occured. Unable to fetch
</div>
</div>
) : (
<div className="columns is-multiline px-3 py-3 is-mobile">
{result}
</div>
)}
</div>
);
}
}
Recipe component :
import React from "react";
export default class Recipe extends React.Component {
render() {
return (
<div className="column is-one-quarter-desktop is-half-mobile">
<div className="card">
<div className="card-image">
<figure className="image is-4by3">
<img src={this.props.image} alt="" />
</figure>
</div>
<div className="card-content">
<p className="title is-6">{this.props.title}</p>
<ul>{this.props.ingredients}</ul>
</div>
</div>
</div>
);
}
}
What do you think about using new state for that?
What I mean is that:
this.state = {
...,
focusSearch: false
}
const handleFocus = () => {
this.setState({ ...this.state, focusSearch: true});
}
<input
className="input is-rounded"
type="text"
placeholder="Find a recipe"
name="searchQuery"
value={this.state.searchQuery}
onFocus={this.handleFocus}
onChange={this.handleChange}
/>
render() {
return (
{
focusSearch ? <div></div> : <></>;
}
)
}
I figured it out this morning. It can be done easily using conditional rending and ternary operator.
Thank you, everyone.
I'm having weird problem in React JS. I have two classes named as Notes.js and DataTables.js
I'm using DataTables in Note.js like this
<DataTables
keyField="id"
columns={columns}
url={this.state.url}
useCallBack={true}
onEdit={this.onEdit}
/>
Please Note that DataTables.js is my own custom created DataTable.js not react-datatable.
All the work like fetching data from URL and showing it in tabular form is in DataTables.js file.
Note.js Code:
import React, { Component } from "react";
import { Constant } from "../shared/Constants";
import DataTables from "../shared/DataTables";
import { Modal, Button } from "react-bootstrap";
import BreadCrumb from "../shared/BreadCrumb";
import "../Style.css";
const columns = Constant.notes;
export class Notes extends Component {
constructor(props) {
super(props);
this.state = {
isLoading: true,
url: "notes/get_notes",
showModal: false,
note: [],
};
this.onEdit = this.onEdit.bind(this);
this.onAdd = this.onAdd.bind(this);
this.onUpdate = this.onUpdate.bind(this);
this.saveNote = this.saveNote.bind(this);
}
onUpdate(key, value) {
let noteData = this.state.note;
noteData[key] = value;
this.setState({
note: noteData,
});
}
saveNote(e) {
e.preventDefault();
}
onEdit(n) {
this.setState({
note: n,
showModal: true,
});
}
onAdd() {
this.setState({
note: [],
showModal: true,
});
}
render() {
return (
<>
<Modal
show={this.state.showModal}
aria-labelledby="example-modal-sizes-title-lg"
onHide={() => this.setState({ showModal: false })}
>
<form method="post" onSubmit={this.saveNote}>
<Modal.Header>
<Modal.Title>My Note</Modal.Title>
</Modal.Header>
<Modal.Body>
<div className="row">
<div className="col-sm-12">
<div className="form-group">
<label className="text-muted">Note Title</label>
<input
type="text"
placeholder="Note Title"
className="form-control"
ref="title"
value={this.state.note.title}
onChange={(e) => this.onUpdate("title", e.target.value)}
/>
</div>
<div className="form-group">
<label className="text-muted">Content</label>
<textarea
onChange={(e) => this.onUpdate("content", e.target.value)}
className="form-control"
style={{ height: "250px" }}
placeholder="Content"
>
{this.state.note.content}
</textarea>
</div>
</div>
</div>
</Modal.Body>
<Modal.Footer>
<Button
variant="secondary"
onClick={() => this.setState({ showModal: false })}
>
Close
</Button>
<Button type="submit" variant="primary">
Save Note
</Button>
</Modal.Footer>
</form>
</Modal>
<BreadCrumb
title="My Notes"
useCallBack={true}
onAdd={this.onAdd}
active_link="Notes"
link=""
link_text="Add New"
/>
<div className="row">
<div className="col-sm-12">
<div className="card">
<div className="card-body">
<div className="card-title">Notes</div>
<DataTables
keyField="id"
columns={columns}
url={this.state.url}
useCallBack={true}
onEdit={this.onEdit}
/>
</div>
</div>
</div>
</div>
</>
);
}
}
export default Notes;
I'm having Problem in Note.js on onUpdate function
onUpdate(key, value) {
let noteData = this.state.note;
noteData[key] = value;
this.setState({
note: noteData,
});
}
Problem: When I update a field in Modal as you can see in my code, then my Table in DataTable.js automatically gets updated, I'don't why :/
Here is DataTables.js function where I'm sending data to onEdit function
const TableData = () => {
return (
<tbody>
{tableData.length === 0 ?
<tr>
<td className="text-center" colSpan="5"><strong>No Data Found</strong></td>
</tr>
:
tableData.map((tData) => (
<tr key={tData[this.props.keyField]}>
{this.props.columns.map((item, index) => (
<td key={index} className="table-content">
{index === 0 ?
[(useCallback === true ? <span key={"sub_"+index} className="link" onClick={() => this.props.onEdit(tData)}>{tData[item.dataField]}</span> :
<Link
to={
this.props.edit_link +
"/" +
tData[this.props.edit_key_first] + (this.props.edit_key_second ? "/" +
tData[this.props.edit_key_second] : '')
}
>
{tData[item.dataField]}
</Link>
)]
: (
tData[item.dataField]
)}
</td>
))}
</tr>
))}
</tbody>
);
};
Please check gif image below so you can understand it :P
You have an onChange function that is updating the content
onChange={(e) => this.onUpdate("content", e.target.value)}
If you don't want to change the content while typing then you will have to remove this.
Ok so here's my code:
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
var uuid = require("uuid-v4");
// Generate a new UUID
var myUUID = uuid();
// Validate a UUID as proper V4 format
uuid.isUUID(myUUID); // true
var questionNum = 0;
class App extends Component {
constructor(props) {
super(props);
this.state = {
key: uuid(),
title: "",
author: "",
questions: [],
answers: []
};
this.handleChange = this.handleChange.bind(this);
this.addQuestion = this.addQuestion.bind(this);
this.removeItem = this.removeItem.bind(this)
}
componentDidMount() {
// componentDidMount() is a React lifecycle method
this.addQuestion();
}
handleChange(event) {
const target = event.target;
const value = target.type === "checkbox" ? target.checked : target.value;
const name = target.name;
this.setState({
[name]: value
});
}
removeItem (index) {
questionNum--;
this.setState(({ questions }) => {
const mQuestions = [ ...questions ]
mQuestions.splice(index, 1)
return { questions: mQuestions }
})
this.setState(({ answers }) => {
const mAnswers = [ ...answers]
mAnswers.splice(index, 4)
return { answers: mAnswers}
})
console.log(
"answers",
this.state.answers,
"questions",
this.state.questions,
questionNum,
this.state.title,
this.state.author
);
}
addQuestion() {
questionNum++;
this.setState(previousState => {
const questions = [
...previousState.questions,
<input
type="text"
onChange={this.handleChange}
name="question"
key={uuid()}
/>
];
const answers = [
...previousState.answers,
];
for (var i = 0; i < 4; i++) {
answers.push(
<input
type="checkbox"
name={uuid()}>
<input
type="text"
onChange={this.handleChange}
name={uuid()}
/>
</input>
);
}
return { questions, answers };
});
console.log(
"answers",
this.state.answers,
"questions",
this.state.questions,
questionNum,
this.state.title,
this.state.author
);
}
render() {
return (
<div className="App">
<div>
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h1 className="App-title">Quiz Form 3.0</h1>
</header>
<p className="App-intro">
To get started, edit <code>src/App.js</code> and save to reload.
</p>
</div>
<div className="formDiv">
<form>
<div className="Intro">
Give your Quiz a title:{" "}
<input
type="text"
value={this.state.title}
onChange={this.handleChange}
name="title"
/>
<br />
Who's the Author?{" "}
<input
type="text"
value={this.state.author}
onChange={this.handleChange}
name="author"
/>
<br />
<br />
</div>
<div className="questions">
<div className="questions">
Now let's add some questions... <br />
<ol>
{this.state.questions.map(question => {
return (
<li>
<div key={uuid()}>
Question
{question}<br />
Answer Choices<br />
{Array.from({ length: 4 }, () => (
<input type="text" key={uuid()} onChange={this.handleChange} />
))}
</div>
</li>
);
})}
</ol>
</div>
{
// This is what it would look like for the structure
// I proposed earlier.
// this.state.questions.map((question) {
// return (
// <div>{question.quesion}</div>
// {
// question.answers.map((answer) => {
// return (<div>{answer}</div>);
// })
// }
// );
// })
// This would output all questions and answers.
}
</div>
</form>
<button id="addQuestionButton" onClick={this.addQuestion}>Add Question</button>
{ this.state.questions.map((question, index) => {
return <button key={uuid()} onClick={ () => this.removeItem(index) }>Remove Question</button>
}) }
</div>
</div>
);
}
}
export default App;
Ok so here's a link to a quick video demonstrating what it does as of now. In the video you can see the Remove Question buttons that are created (at the bottom of the form) each time a question is added. I would like to have each question's Remove Question button be next to it/in the same div. I'm not entirely sure how I would go about doing this. Any thoughts?
UPDATE: Ok so I have put the buttons inside of the same div with the actual question, but I realized that i am adding a button for each object in the array. Which means that when a question is added a button to remove it is added to every question on the form. I need to make it so it does not .map this. I'm not entirely sure what other function I will do for this, maybe I don't even need a function. I will try my best to work it out. Here's the updated code (some of it):
<div className="questions">
Now let's add some questions... <br />
<ol>
{this.state.questions.map(question => {
return (
<li>
<div key={uuid()}>
Question
{question}<br />
{
this.state.questions.map((question, index) => {
return <button key={uuid()} onClick={ () => this.removeItem(index) }>Remove Question</button>
})
}
Answer Choices<br />
{Array.from({ length: 4 }, () => (
<div>
<input type="checkbox" />
<input type="text" key={uuid()} onChange={this.handleChange} />
</div>
))}
</div>
</li>
);
})}
</ol>
</div>
Something like this...
<ol>
{this.state.questions.map((question, index) => {
return (
<li>
<div key={uuid()}>
Question
{question}<br />
<button onClick={ () => this.removeItem(index) }>
Remove Question
</button>
Answer Choices<br />
{Array.from({ length: 4 }, () => (
<div key={uuid()}>
<input type="checkbox" />
<input type="text" onChange={this.handleChange} />
</div>
))}
</div>
</li>
);
})}
</ol>
I'm trying to build a back-office where you can add / update / delete projects for a showroom.
When you want to add a new project, I have a model which open and display 4 languages.
Each language is a collapsing div onClick.
So I instantiate them this way in the render method of my main component:
<Modal
isOpen={this.state.addIsOpen}
onAfterOpen={this.afterOpenModal}
onRequestClose={this.closeModal}
style={customStyles}
contentLabel="Example Modal"
>
<h2 ref="subtitle">Add a new Inspiration</h2>
{
languages.map((lang, i) => {
return (
<FormLanguage
key={i}
lang={lang}
/>
);
})
}
<button onClick={this.closeModal}>Finish!</button>
</Modal>
The form language, another container is then instantiated this way:
render() {
return (
<form onSubmit={this.addProject} style={{marginTop: 35, marginBottom: 50}}>
<h2 onClick={this.expand}>{this.props.lang} language</h2>
<div style={{display: this.state.showMore ? "block" : "none"}}>
<label>
Title:<br />
<textarea value={this.state.titles.lang} onChange={this.handleTitle} />
</label>
<br />
<label>
Description:<br />
<div style={{marginTop: 20, marginBottom: 20}}>
<RichEditorExample />
</div>
</label>
<br />
<input type="submit" value="Submit" />
</div>
</form>
);
}
But then, when I try to type text, I figured out that all my textEditor are filling at the same time.
The render method of the texteditor (draftjs):
return (
<div className="RichEditor-root">
<BlockStyleControls
editorState={editorState}
onToggle={this.toggleBlockType}
/>
<InlineStyleControls
editorState={editorState}
onToggle={this.toggleInlineStyle}
/>
<div className={className} onClick={this.focus}>
<Editor
blockStyleFn={getBlockStyle}
customStyleMap={styleMap}
editorState={editorState}
handleKeyCommand={this.handleKeyCommand}
onChange={this.onChange}
onTab={this.onTab}
ref="editor"
spellCheck={true}
/>
</div>
</div>
);
With the constructor in charge of the onChange:
constructor(props) {
super(props);
this.focus = () => this.refs.editor.focus();
this.onChange = (editorState) => {
const { dispatch } = this.props;
dispatch(updateText(editorState));
};
So, I'm like "damn, what am I missing here?".
Should I iterate inside of the form instead of doing it in the parent?
EDIT:
As asked in the question, I'm following the Redux pattern, so here are the action / reducer methods:
export const UPDATE_TEXT = 'UPDATE_TEXT';
export function updateText(editorState) {
return {
type: UPDATE_TEXT,
editorState
};
};
And the reducer:
export function editorText(state = {}, action) {
switch (action.type) {
case UPDATE_TEXT:
return action.editorState;
default:
return state;
};
};