Conditionally render lyrics based off track index? - mysql

I'm trying to create a track list. I want to render the track lyrics based off of the track name that was clicked on for the specified id. However, I'm having some trouble doing so.
The data is being fetched from MySQL.
Here is my code:
Model:
var db = require("../dbconnection");
var music = {
insertmusicTracks: function(data, callback) {
db.query(
"insert music_tracks set track_music_id=?, track_user_id=?, trackName=?, trackLyrics=?",
[data.albumId, data.userId, data.songName, data.songLyrics],
callback
);
},
selectmusicTracks: function(data, callback) {
db.query(
"select mo.track_music_id, mo.trackName, mo.trackLyrics, mt.authorName, mt.trackTitle, mt.trackYear, mt.trackcoverImg from music_tracks mo left join music_topics mt on mt.music_id=mo.track_music_id where mo.track_music_id=?",
[data.trackmusicId],
callback
);
}
};
module.exports = music;
View:
import React from "react";
import { Link } from "react-router-dom";
import { Modal, Button } from "react-bootstrap";
import Headericons from "../common/header-icons";
import Header from "../common/header";
import Footer from "../common/footer";
import Addtracklist from "../components/addmusictrack";
import dataTip from "data-tip";
import appController from "../../controllers/appController";
import musicService from "../../services/musicService";
class Musictracks extends React.Component {
constructor(props) {
super(props);
this.state = {
userId: "",
isAdmin: false,
albumName: "",
musicId: this.props.match.params.musicid,
trackData: []
};
}
handleClose = () => {
this.setState({ show: false });
};
handleShow = () => {
this.setState({ show: true });
};
selectTracks = async () => {
const selectmusicTracks = await musicService.selectmusicTracks({
trackmusicId: this.props.match.params.musicid
});
this.setState({
trackData: selectmusicTracks
});
console.log(this.state);
};
showLyrics = async trackId => {
this.setState({
lyricId: trackId
});
console.log(this.state);
};
async componentDidMount() {
if (appController.isAdmin().role_id === 3) {
await this.setState({
userId: appController.isAdmin().userID,
isAdmin: true
});
}
this.setState({
albumName: this.props.match.params.title
});
await this.selectTracks();
await this.showLyrics();
}
render() {
return (
<div className="fluid-container">
<Headericons />
<Header />
<div className="container" id="musictrackContainer">
<h1>{appController.removeHyphen(this.state.albumName)}</h1>
<div className="row">
<Link className="btn btn-primary" id="previouspage" to="/music">
← Go Back
</Link>
</div>
{this.state.isAdmin === true ? (
<div className="row" id="superAdmin">
<div className="col-md-12">
<i
className="far fa-plus-square fa-2x"
onClick={this.handleShow}
/>
</div>
<div className="static-modal">
<Modal show={this.state.show} onHide={this.handleClose}>
<Modal.Header closeButton>
<Modal.Title>Add Track</Modal.Title>
</Modal.Header>
<Modal.Body>
<Addtracklist
albumId={this.state.musicId}
userId={this.state.userId}
closeModal={this.handleClose}
/>
</Modal.Body>
</Modal>
</div>
</div>
) : null}
<div className="row">
<div className="col-md-4">
<div className="trackContainer">
<ol>
{this.state.trackData.map((rows, index) => (
<div
className="trackName data-tip-right"
data-tip={"View " + rows.trackName}
key={rows.trackName + "-" + rows.track_music_id}
onClick={e => this.showLyrics(index)}
>
<li tabIndex={index}>
{index + 1 + ". " + rows.trackName}
<i className="fas fa-arrow-right" />
</li>
</div>
))}
</ol>
</div>
</div>
<div className="col-md-8">
// This is where I'm stuck I'm not sure how I can render lyrics based off of the track name.
{this.state.trackData.map((row, index) =>
this.state.lyricId === index ? (
<div className="trackLyrics">{row.trackLyrics}</div>
) : null
)}
</div>
</div>
</div>
<Footer />
</div>
);
}
}
export default Musictracks;
The above snippet is my attempt to try and render the lyrics based off of track name that the user clicks on.

Nevermind I figured it out. I made a small error in my code. I simply had to replace row.index with index and it worked. Edited my question.

Related

how to Dynamic add field post with reactjs and axios post

I am working on Dynamic add field data submit with reactjs and axios. Its working fine but only on one filed when i want to add more field then the field added but when i put my data and want to post data then only one field working. i am using react and axios post for submit my form.
My code
import React from 'react';
import axios from 'axios';
import { Grid, Button } from "#material-ui/core/";
import Alert from '#material-ui/lab/Alert';
import CloseIcon from "#material-ui/icons/Close";
import TextField from "#material-ui/core/TextField";
import AddIcon from '#material-ui/icons/Add';
class FaqPage extends React.Component<{},any>{
constructor(props) {
super(props)
this.state = {
faqList:[{index: Math.random(), question:'', answer: ''}],
// question: '',
// answer: '',
questions: ['hello']
}
this.state = { values: [{question: '',response: ''}] };
this.handleSubmit = this.handleSubmit.bind(this);
}
componentDidUpdate(){
setTimeout(() => this.setState({errorMessage:''}), 40000);
setTimeout(() => this.setState({sucessMessage:''}), 40000);
}
uploadDocument = (e) => {
console.log(e);
}
handlequestionChange = event => {this.setState({ question: event.target.value })}
handleanswerNameChange = event => {this.setState({ answer: event.target.value })}
handleSubmit = event => {
event.preventDefault();
event.target.reset()
// const openDate = {userid: this.state.openDate};
// const closeDate = {fullname: this.state.closeDate};
// const listingDate = {usergroup: this.state.listingDate};
axios.post('https://api.com/api/faqs',
{
ipoId: '328',
faqList:[
{ question: this.state.question,
answer: this.state.answer,
}
]
}
)
.then(res => {
console.log(res);
console.log(res.data);
console.log('thank you')
this.setState({sucessMessage: res.data});
})
.catch(err => {
this.setState({errorMessage: err.message});
})
}
createUI(){
return this.state.values.map((el, i) =>
<div key={i} className="commonInput">
<div className="formW">
<TextField type="text" label="question" name="question" onChange={this.handlequestionChange}/>
</div>
<div className="formW">
<TextField type="text" label="answer" name="answer" onChange={this.handleanswerNameChange}/>
</div>
{
i ?
<button type="button" className="button remove" onClick={() => this.removeClick(i)}><CloseIcon /></button>
: null
}
</div>
)
}
handleChange (i,event) {
let values = [...this.state.values];
values[i][event.target.id] = event.target.value;
this.setState({ values });
}
addClick(){
this.setState(prevState => ({ values: [...prevState.values, {question: '',response: '',}]}))
}
removeClick(i){
let values = [...this.state.values];
values.splice(i,1);
this.setState({ values });
}
componentDidMount() {
axios.get(`https://api.com/api/get/all`)
.then(res => {
const posts = res.data;
this.setState({ posts });
})
}
render() {
return (
<Grid className="CoomonT">
<div className="clapse ">
<form onSubmit={this.handleSubmit}>
<br/>
{this.createUI()}
<input type='button' value='add more' onClick={this.addClick.bind(this)}/>
{/* <div className="form-btn formW">
<Button
size="small"
variant="contained"
className=""
color="primary"
onClick={this.addClick.bind(this)}
>
<AddIcon/>
</Button>
</div> */}
{/* <div>file<TradeImportComponent/></div> */}
{/* <button type="submit" color="primary">Add</button> */}
<div className="form-btn formW">
<Button
size="small"
variant="contained"
className=""
color="primary"
type="submit"
disableElevation
>
Submit
</Button>
</div>
</form>
</div>
</Grid>
)
}
}
export default FaqPage;
Screenshot
Why are you using this.state two times? Each class component in React has only 1 state. So first of all, you should correct your state definition. Moreover, Your values state is an Array. So when you want to edit your question/answer or post data via axios, you should use the whole values array.
There are also some questions that you should answer to yourself to have a cleaner code. I implemented some general changes and commented those questions in the below code. Answer them and change code based on their answer, so that your code works.
import axios from 'axios';
import React from 'react';
import { Grid, Button } from "#material-ui/core/";
import Alert from '#material-ui/lab/Alert';
import CloseIcon from "#material-ui/icons/Close";
import TextField from "#material-ui/core/TextField";
import AddIcon from '#material-ui/icons/Add';
class FaqPage extends React.Component<{},any>{
constructor(props) {
super(props)
// What is defference between faqList and values? Could'nt you use just one of them? and build the other one from another one (whenever needed)?
this.state = {
faqList:[{index: Math.random(), question:'', answer: ''}],
values: [{question: '',response: ''}]
}
this.handleSubmit = this.handleSubmit.bind(this);
}
componentDidUpdate(){
setTimeout(() => this.setState({errorMessage:''}), 40000);
setTimeout(() => this.setState({sucessMessage:''}), 40000);
}
uploadDocument = (e) => {
console.log(e);
}
handleQuestionChange = (event, index) => {
const faq = this.state.values
faq[index].question = event.target.value
this.setState(faq)
}
handleAnswerNameChange = (event, index) => {
const faq = this.state.values
faq[index].answer = event.target.value
this.setState(faq)
}
handleSubmit = event => {
event.preventDefault();
event.target.reset()
// What is ipoId? Is it different from the `index` field in `this.state.faqList`?
axios.post('https://api.com/api/faqs',
{
ipoId: '328',
faqList:this.state.value
}
)
.then(res => {
console.log(res);
console.log(res.data);
console.log('thank you')
this.setState({sucessMessage: res.data});
})
.catch(err => {
this.setState({errorMessage: err.message});
})
}
createUI(){
return this.state.values.map((el, i) =>
<div key={i} className="commonInput">
<div className="formW">
<TextField type="text" label="question" name="question" onChange=(e, i) => {this.handleQuestionChange(i)}/>
</div>
<div className="formW">
<TextField type="text" label="answer" name="answer" onChange=(i) => {this.handleAnswerNameChange(e, i)}/>
</div>
{
i ?
<button type="button" className="button remove" onClick={() => this.removeClick(i)}><CloseIcon /></button>
: null
}
</div>
)
}
addClick(){
this.setState(prevState => ({ values: [...prevState.values, {question: '',response: '',}]}))
}
removeClick(i){
let values = [...this.state.values];
values.splice(i,1);
this.setState({ values });
}
componentDidMount() {
axios.get(`https://api.com/api/get/all`)
.then(res => {
const posts = res.data;
this.setState({ posts });
})
}
render() {
return (
<Grid className="CoomonT">
<div className="clapse ">
<form onSubmit={this.handleSubmit}>
<br/>
{this.createUI()}
<input type='button' value='add more' onClick={this.addClick.bind(this)}/>
{/* <div className="form-btn formW">
<Button
size="small"
variant="contained"
className=""
color="primary"
onClick={this.addClick.bind(this)}
>
<AddIcon/>
</Button>
</div> */}
{/* <div>file<TradeImportComponent/></div> */}
{/* <button type="submit" color="primary">Add</button> */}
<div className="form-btn formW">
<Button
size="small"
variant="contained"
className=""
color="primary"
type="submit"
disableElevation
>
Submit
</Button>
</div>
</form>
</div>
</Grid>
)
}
}
export default FaqPage;

How can i redirect to full post after click on title

I did data display from json with titles from all posts and now i need to do redirect to page with title and body after click on title, any ideas? Thanks for help
import "./style.css";
class Card extends React.Component {
state = {
loading: true,
posts: [],
};
async componentDidMount() {
const url = "https://jsonplaceholder.typicode.com/posts";
const response = await fetch(url);
const posts = await response.json();
this.setState({ posts, loading: false });
}
render() {
return (
<div>
{this.state.loading || !this.state.posts.length === 0 ? (
<div> loading...</div>
) : (
<div>
{this.state.posts.map((post) => (
<div key={post.id} className="post-header">
{post.title}
</div>
))}
</div>
)}
</div>
);
}
}
export default Card;```
I would recommend you to use Functional component as it would make your code short and much more readable.
But as per your code you can simply get the desired results by the making the following changes in your code.
import { useHistory } from 'react-router-dom';
class Card extends React.Component {
const history = useHistory();
render() {
return (
<div>
{this.state.loading || !this.state.posts.length === 0 ? (
<div> loading...</div>
) : (
<div>
{this.state.posts.map((post) => (
<div key={post.id} className="post-header">
<div onClick={() => history.push(post.title)}>
{post.title}
</div>
</div>
))}
</div>
)}
</div>
);
}
}
import "./style.css";
class Card extends React.Component {
state = {
loading: true,
posts: [],
};
async componentDidMount() {
const url = "https://jsonplaceholder.typicode.com/posts";
const response = await fetch(url);
const posts = await response.json();
this.setState({ posts, loading: false });
}
gotoPage=(data)=>()=>{ //write this function above render
this.props.history.push('/'+data);
}
render() {
return (
<div>
{this.state.loading || !this.state.posts.length === 0 ? (
<div> loading...</div>
) : (
<div>
{this.state.posts.map((post) => (
<div key={post.id} className="post-header">
<span onClick={this.gotoPage(post.title)}>{post.title}</span> // You can use this function, when user user click on title, navigate page to that title
</div>
))}
</div>
)}
</div>
);
}
}
export default Card;```

TypeError: links.map is not a function React

I'm working with reactjs typescript and cannot seem to prevent this error when trying to display JSON data from the server:
import React, { useRef, useState } from "react";
import useHttp from "../hooks/usehttp";
const HomePage: React.FC = () => {
const [links, setLinks] = useState([]);
const ref = useRef<HTMLInputElement>(null);
const { request } = useHttp();
const pressHandler = async (event: React.KeyboardEvent) => {
if (event.key === "Enter") {
try {
const data = await request(
"http://localhost:5000/api/link/generate-guest",
"POST",
{ from: ref.current!.value },
{}
);
alert(data.message);
console.log(data.link.to); // the link => localhost:5000/jshdadsa
setLinks(data.link.to);
console.log(links); // shows undefined ?????
} catch (error) {
alert(error);
}
}
};
return (
<>
<div className="row">
<div className="col s8 offset-s2" style={{ paddingTop: "2rem" }}>
<div className="input-field">
<input
placeholder="Enter link"
id="link"
type="text"
ref={ref}
onKeyPress={pressHandler}
/>
<label htmlFor="link">Enter link</label>
</div>
<div>
{ {links.map((link: any) => {
return (
<ul className="collection with-header">
<li className="collection-item">{link}</li>
</ul>
);
})} }
</div>
</div>
</div>
</>
);
};
export default HomePage;
Not sure what i am missing.
Use this code in order to update the array of link in your example:
setLinks([...links, data.link.to])

My dialog box component is not Showing in Reactjs

I have a component name dialog Box and i want to show it on click over all other components . I have a main component as
class ImageEditor extends Component {
constructor() {
super();
this.state = { images: [], redirect: 'no', imageId: '', isDialogOpen: 'no' };
}
componentDidMount() {
let promise = apiGateway.getImages();
promise.then((images) => {
this.setState({ images: images });
});
}
openDialog = () =>{
this.setState({ isDialogOpen : 'yes' });
}
closeDialog = () =>{
this.setState({ isDialogOpen: 'no' });
}
deleteImage = (id) => {
apiGateway.removeImage(id);
}
setRedirect = (id) => {
this.setState({ redirect: 'yes', imageId: id });
}
renderImage(image,index){
return(
<div key={index}>
<p>Title: {image.title}</p>
<p>Description: {image.description}</p>
<button onClick={(e)=> this.deleteImage(image._id)}>DELETE</button>
<button onClick={(e)=> this.setRedirect(image._id)}>UPDATE</button>
<button onClick={this.openDialog}>SHARE</button>
<img className='image' src={image.link} width='100' height='100' alt='nature'/>
<br/><br/>
</div>
);
}
render() {
const { redirect , isDialogOpen } = this.state;
if(redirect === 'yes'){
return <Redirect to={`/update/${this.state.imageId}`}/>
}
if(isDialogOpen === 'yes'){
<DialogBox /> ????????
}
return(
<div>
<div>{
this.state.images.map((image,index)=>{
return this.renderImage(image,index);
})
}
</div>
</div>
);
}
}
export default ImageEditor;
When a person clicks on SHARE , I want Dialog Box to Open.I donot know the way i am doing i.e loading component with dialogBox is right or wrong. So every Advice or any suggestion will definitely help me. Here is my dialogue component(Right now i am getting a error as :Expected an assignment or function call and instead saw an expression no-unused-expressions)
class DialogBox extends Component {
render() {
return(
<div>
<Dialog title="Dialog Title" modal={true} onClose={this.handleClose} buttons={ [{ text: "Close", onClick: () => this.handleClose() }] }>
<h1>Dialog Content</h1>
<p>More Content. Anything goes here</p>
</Dialog>
</div>
);
}
}
You can do this:
return (
<div>
<insert your other components>
{this.state.isDialogOpen === 'yes' && <DialogBox />}
<div>
)
I'd advise using boolean instead of string for isDialogOpen.

ReactJS - How to prevent duplicate data from displaying when consuming json file using fetch

My react page consist of three dropdown list, each dropdown has it own respective set of data, which is being pulled from a json file. My issue is, one of the dropdown list repeats the client's name several times (the clients name comes up more then once in the dropdown). Is there a way to prevent the client's name from duplicating?
this is my code:
import React, { Component } from 'react';
class Ast extends Component {
constructor(){
super();
this.state = {
data: [],
cfmRateFactor: "10",
};
} //end constructor
change = (e) => {
this.setState({
[e.target.name]: e.target.value
});
}; //end change
removeDuplicates(arr) {
let data = arr.filter(function(elem, index, self) {
return index == self.indexOf(elem);
});
return unique_array
}
componentWillMount() {
fetch('https://api.myjson.com/bins/b1i6q', {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-type': 'application/json',
},
/*body: JSON.stringify({
username: '{userName}',
password: '{password}'
})*/
}) /*end fetch */
.then(results => results.json())
.then(data => this.setState({ data: data })
)
} //end life cycle
render() {
console.log(this.state.data);
return (
<div>
<div className="container">
<div>
<form>
<div>
<h2>Memeber Selection:</h2>
{['clientName', 'siteName', 'segmentName'].map(key => (
<div className="dropdown-padding">
<select key={key} className="custom-select">
{this.state.data.map(({ [key]: value }) => <option key={value}>{value}</option>)}
</select>
</div>
))}
</div>
<div className="txt_cfm">
<label for="example-text-input">Modify CFM Rate Factor:</label>
<input class="form-control" type="textbox" id="cfmRateFactor" name="cfmRateFactor" value={this.state.cfmRateFactor} onChange={e => this.change(e) } />
</div>
<div>
<div>
<button type="submit" className="btn btn-primary">Submit</button>
</div>
</div>
</form>
</div>
</div>
</div>
);
}
}
export default Ast