Update select react from another select option - reactjs

I'm trying to update my city select from the selected state, but the city does not update when I change the state:
Here is the part of my render code:
<div>
<label for="state">state:</label>
<SelectInput items="RO-DF-RS-SP-RJ-MG-PR" onChange={this.handleChange} name="state"/>
</div>
{!!this.state.stt &&
(
<div>
<label for="city">city:</label>
<SelectInput url="/static/json/" filename={this.state.stt} onChange={this.props.onChange} name="city"/>
</div>
)
}
<div>
this.props.onChange is just a handler to get the value of the input to save the data at database
And the code:
handleChange(event){
if(event.target.name == "state"){
this.setState({
stt: event.target.value
});
}
if(this.props.onChange) {
this.props.onChange(event);
}
}
sets the correct state (this.state.stt)
Here is my SelectInput:
class SelectInput extends React.Component{
constructor(props){
super(props);
this.state = {
select: "",
items: [],
filename: this.props.filename
}
this.handleChange = this.handleChange.bind(this)
}
componentDidMount(){
if(this.props.filename){
console.log(this.props.filename);
}
if(this.props.items){
this.setState({
items: this.props.items.split("-")
})
}
else if(this.props.url && this.props.filename){
$.ajax({
type: 'GET',
url: `${this.props.url}${this.props.filename}.json`,
headers: { 'Authorization': "Token " + localStorage.token },
success: (result) => {
this.setState({
items: result.child
})
},
error: function (cb) { console.log(cb) }
});
}
}
handleChange(event){
this.setState({
select: event.target.value
});
if(this.props.onChange) {
this.props.onChange(event)
}
}
render(){
return (
<select name={this.props.name} value={this.state.select} onChange={this.handleChange}>
<option value=""></option>
{this.state.items && this.state.items.map(item =>
<option value={item}>{item}</option>
)}
</select>
)
}
}
export default SelectInput
Any idea to solve my problem?

Since you are setting filename dynamically you need to implement componentWillReceiveProps that will make ajax request to load new file.
componentWillReceiveProps({ filename }) {
if(filename !== this.props.filename) {
this.loadItems(filename)
}
}
loadItems(filename) {
$.ajax({
type: 'GET',
url: `${this.props.url}${filename}.json`,
headers: {
'Authorization': "Token " + localStorage.token
},
success: (result) => {
this.setState({
items: result.child
})
},
error: function(cb) {
console.log(cb)
}
});
}

Related

400, message: "No search query" in Spotify API

I am trying to obtain a reply (a track list (json)) from the spotify API but I keep getting this error: {status: 400, message: "No search query"} this is my function in my spotify.api module:
search(term) {
const accessToken = Spotify.getAccessToken();
return fetch(`https://api.spotify.com/v1/search?type=TRACK&q=${term}`, {
headers: {
Authorization: `Bearer ${accessToken}`,
},
}).then(response => {
return response.json();
}).then(jsonResponse => {
if (!jsonResponse.tracks) {
return [];
}
return jsonResponse.tracks.items.map(track => ({
id: track.id,
name: track.name,
artist: track.artists[0].name,
album: track.album.name,
}));
});
},
This is app.js (main container component) where the state is at; these are within the class react constructor:
search(term) {
Spotify.search(term).then(searchResults => {
this.setState({
searchResults: searchResults
})
})
}
render() {
return (
<div>
<div className = "App" >
< SearchBar onSearch={this.search} />
<div className="App-playlist">
< SearchResults searchResults={this.state.searchResults}
onAdd={this.addTrack} />
< Playlist playlistName={this.state.playlistName}
playlistTracks={this.state.playlistTracks}
onRemove={this.removeTrack}
onNameChange={this.updatePlaylistName}
onSave={this.savePlaylist} />
</div>
</div>
</div>);
}
}
This is the searchBar.js component, where the input (or track) will be requested:
search() {
this.props.onSearch(this.state.term);
}
handleTermChange(event) {
this.setState = { term: event.target.value };
}
render() {
return (
<div className="SearchBar">
<input
onChange={this.handleTermChange}
placeholder="Enter A Song, Album, or Artist"
/>
<button className="SearchButton" onClick={this.search}>SEARCH</button>
</div>
);
}
}
Try changing this
handleTermChange(event) {
this.setState = { term: event.target.value };
}
To
handleTermChange(event) {
this.setState({ term: event.target.value });
}
Since you were not using the setState method correctly, you were calling the Spotify API with an empty term value, then you get the http 400 error.

Condtional Renderin React using If-else not working

i'm new at React, i want to ask about contidional recndering, i'm making project about sending message, and i use validation to check all field is not empty, when one field is empty it should show error message that message not send. I using if-else to render the error message, but it doesn't work.
Here i add my code
....
export default class Message extends React.Component {
constructor(props){
super(props);
this.state = {
isLoggedIn: SystemStore.isLoggedIn(),
profile: ProfileStore.getProfile(),
fullName: SystemStore.systemUser().fullName,
site: '',
email: '',
phone: '',
subject: '',
description: '',
type: '',
errorMessage: '',
errorDialog: '',
isSubmited: false,
successMessage: '',
submitting: false
};
this.clearForm = this.clearForm.bind(this);
this.handleProfileChange = this.handleProfileChange.bind(this);
this.handleSubjectChange = this.handleSubjectChange.bind(this);
this.handleMessageChange = this.handleMessageChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.handleSubmitComplete = this.handleSubmitComplete.bind(this);
this.handleSubmitError = this.handleSubmitError.bind(this);
}
componentDidMount(){
ProfileStore.addProfileChangeListener(this.handleProfileChange);
if(!this.state.profile){
ProfileActions.reload()
}
MessageStore.addSubmitMessageChangeListener(this.handleSubmitComplete);
MessageStore.addSubmitMessageFailChangeListener(this.handleSubmitError);
}
componentWillUnmount(){
ProfileStore.removeProfileChangeListener(this.handleProfileChange);
MessageStore.removeSubmitMessageChangeListener(this.handleSubmitComplete);
MessageStore.removeSubmitMessageFailChangeListener(this.handleSubmitError);
}
render(){
return(
<Layout>
<div className='hs-dashboard row'>
<div className='col-md-12'>
<div className='col-xs-12 col-sm-6 col-md-5'>
<div className='col-xs-12 hs-message-form'>
<div className='row hs-message-form-head'>
<div className='hs-message-form-logo-container'>
<img className='col hs-message-form-logo' src='../../images/gii-logo-black.png'/>
<text className='hs-message-form-logo-label'>{T.translate('gii')}</text>
</div>
<div className='hs-message-form-label'>
{ T.translate('message.title') }
</div>
<div className='hs-message-form-label-1'>
{ T.translate('message.subtitle') }
</div>
</div>
<div className='row hs-message-form-body'>
<form className='hs-message-form-body-content'>
<label>
{ T.translate('message.type') }
</label>
<select
id="subject"
value={ this.state.subject }
onChange={ this.handleSubjectChange }
className="form-control"
required="true"
>
<option value="">{ T.translate('placeholder.selectSubject') }</option>
<option value="PRAYER">{ T.translate('message.pray') }</option>
<option value="ADDRESS">{ T.translate('message.address') }</option>
<option value="VISIT">{ T.translate('message.visit') }</option>
</select>
<label>
{T.translate('message.message')}
</label>
<textarea
type="text"
id="description"
className="form-control"
width=''
placeholder={ T.translate('placeholder.message') }
onChange={ this.handleMessageChange }
value={ this.state.description }
required
/>
{ this.state.errorDialog &&
<div className='hs-message-empty'>
{ this.state.errorDialog }
</div>
}
{ this.state.isSubmited === true ?
<div className='hs-message-success'>
{ this.state.successMessage }
</div> :
<div className='hs-message-error'>
{ this.state.errorMessage }
</div>
}
<LaddaButton
loading={ this.state.submitting }
onClick={ this.handleSubmit }
data-spinner-size={ 30 }
data-style={ SLIDE_RIGHT }
>
{ T.translate('action.send') }
</LaddaButton>
</form>
</div>
</div>
</div>
</div>
</div>
</Layout>
)
}
clearForm(){
this.setState({ subject: '', description: '' });
}
handleProfileChange(){
this.setState({
site: ProfileStore.getProfile().primarySite.name,
email: ProfileStore.getProfile().emailAddresses[0].email,
phone: ProfileStore.getProfile().contactNumbers[0].countryCode + ProfileStore.getProfile().contactNumbers[0].number
});
}
handleSubjectChange(evt){
this.setState({ subject: evt.target.value }, () => {
if(this.state.subject === 'PRAYER') {
this.setState({ type: 'REQUEST' });
} else if(this.state.subject === 'ADDRESS') {
this.setState({ type: 'INFORMATION' });
} else if(this.state.subject === 'VISIT'){
this.setState({ type: 'REQUEST' });
}
});
}
handleMessageChange(evt){
this.setState({ description: evt.target.value });
}
handleSubmit(evt) {
evt.preventDefault();
var errorDialog;
if(this.state.subject === ''){
errorDialog = 'Error:' + T.translate('msg.subjectRequired');
} else if(this.state.description === ''){
errorDialog = 'Error:' + T.translate('msg.mailDescriptionRequired');
}
this.setState({errorDialog: errorDialog});
this.handleProfileChange();
this.handleSubjectChange(evt);
this.handleMessageChange(evt);
var messageInfo = {
fullName: this.state.fullName,
site: this.state.site,
email: this.state.email,
phone: this.state.phone,
subject: this.state.subject,
description: this.state.description,
type: this.state.type
};
this.setState({ submitting: true }, () => {
MessageActions.sendMessage(messageInfo);
});
console.log(this.state.isSubmited);
}
handleSubmitComplete(){
this.setState({
submitting: false,
isSubmited: true,
errorMessage: null,
successMessage: T.translate('msg.mailSent')
});
this.clearForm();
}
handleSubmitError(){
this.setState({
submitting: false,
isSubmited: false,
errorMessage: T.translate('msg.mailSentFailed'),
successMessage: null
});
}
}
//updated code
This is my store.js
....
var MessageStore = assign({}, EventEmitter.prototype, {
emitSubmitMessageChange: function(){
this.emit(SUBMIT_MESSAGE);
},
addSubmitMessageChangeListener: function(callback){
this.on(SUBMIT_MESSAGE, callback);
},
removeSubmitMessageChangeListener: function(callback){
this.removeListener(SUBMIT_MESSAGE, callback);
},
emitSubmitMessageFailChange: function() {
this.emit(SUBMIT_MESSAGE_FAILED);
},
addSubmitMessageFailChangeListener: function(callback) {
this.on(SUBMIT_MESSAGE_FAILED, callback);
},
removeSubmitMessageFailChangeListener: function(callback) {
this.removeListener(SUBMIT_MESSAGE_FAILED, callback);
}
});
Dispatcher.register(function(action) {
switch(action.actionType){
case MessageConstants.PERFORM_SEND_MESSAGE:
MessageStore.emitSubmitMessageChange();
break;
case MessageConstants.PERFORM_SEND_MESSAGE_FAIL:
MessageStore.emitSubmitMessageFailChange();
break;
default:
//noop
}
})
export default MessageStore;
And this is my action.js
.....
function _sendMessage(messageInfo, callback) {
jQuery.ajax({
method: 'POST',
url: api('supportTickets'),
contentType: 'application/json',
data: JSON.stringify(messageInfo)
})
.done(function(messageInfo) {
callback(null, messageInfo);
})
.fail(function(err){
console.error('Failed to send message : ' + JSON.stringify(err));
callback(err, null);
});
}
var MessageActions = {
sendMessage: function(messageInfo) {
_sendMessage(messageInfo, function(err, messageInfo) {
if(err) {
Dispatcher.dispatch({
actionType: MessageConstants.PERFOM_SEND_MESSAGE_FAIL
});
}
Dispatcher.dispatch({
actionType: MessageConstants.PERFORM_SEND_MESSAGE,
messageInfo
});
});
}
};
module.exports = MessageActions;
Your form should be responsible for handling errors. You should know your errors at the time of submission of the form.
handleSubmit(evt) {
evt.preventDefault();
var errorDialog;
if(this.state.subject === ''){
errorDialog = 'Error:' + T.translate('msg.subjectRequired');
} else if(this.state.description === ''){
errorDialog = 'Error:' + T.translate('msg.mailDescriptionRequired');
}
if (errorDialog) {
this.setState({
// set your error here
})
return;
}
this.handleProfileChange();
this.handleSubjectChange(evt);
this.handleMessageChange(evt);
var messageInfo = {
fullName: this.state.fullName,
site: this.state.site,
email: this.state.email,
phone: this.state.phone,
subject: this.state.subject,
description: this.state.description,
type: this.state.type
};
this.setState({ submitting: true }, () => {
MessageActions.sendMessage(messageInfo);
});
console.log(this.state.isSubmited);
}
Your component seems to be a little complex. Think about breaking your component into smaller components. Using functional components I would do this task in a way something like that.
function validateForm() {
// validate form logic here. If it's ok, returns true, otherwise, returns false
}
function Message({ form }) {
if (!validateForm(form)) {
return (
<div>Please, fill the empty fields!!</div>
)
}
return (
<div>All good. Submit the form!!</div>
)
}

Load data into inputs when entering the code

I have updated the Code.
Here I have a functional Select Autocomple showing the list of records from DB "Register". When selecting a Code, the Name value is automatically renamed.
The same thing I want to do but with the not with , I want to call more than two values like this in the image and in select is only Label and Value
Capture: [1]: https://i.stack.imgur.com/ELf1a.png
class Register extends Component {
state = {
status: "initial",
data: [],
name:'',
code:''
}
componentDidMount = () => {
this. getInfo()
}
getInfo= async () => {
try {
const response = await getAll('register')
console.log(response.data)
this.setState({
status: "done",
data: response.data
});
} catch (error) {
this.setState({
status: "error"
});
}
};
handleChange = (selectedOption) => {
this.setState({
selectedOption,
name: selectedOption.value
});
render() {
//show Name and code on Select from Register
const data = this.state.data.map( st => ({value: st.Name, label: st.Code}));
return (
<Container>
<RowContainer margin="1px" >
<ColumnContainer margin="10px">
<h3>Info</h3>
<label>Code</label>
<Select
width='215px'
value={selectedOption}
onChange={this.handleChange}
options={data}
name={"Code"}
/>
<label>Name</label>
<Input
width='150px'
type="text"
name={"Name"}
placeholder="Name"
value={this.state.name} />
</ColumnContainer>
</RowContainer>
</Container>
)
}
};
export default Register;
You want to know how change the state for <input/>
try this
constructor(props){
super(props)
this.state = {
status: "initial",
data: [],
codigo: "",
nombre: ""
}
}
handleChange(event){
let stateUpdate = this.state;
stateUpdate[event.target.name] = event.target.value}
this.setState(stateUpdate);
}
render() {
const data = [...this.state.data];
return (
<Container>
<RowContainer margin="1px" >
<ColumnContainer margin="10px">
<h3>Info</h3>
<label>Codigo</label>
<Input
name="codigo"
width='150px'
type="text"
placeholder="Digite el codigo"
value={data.codigo } ref="codigo" />
<label>Nombre</label>
<Input
name="nombre"
width='150px'
type="text"
placeholder="Nombre completo"
value={this.state.nombre} />
</ColumnContainer>
</RowContainer>
</Container>
)
}

react update screen after changing values in the state

I am new to react and I am working on a project where I was ask to reset a form to its defaults.
I created a function that gets call after I click the reset button
<input id="reset_button"
type="button"
name="reset"
value="Reset"
onClick={this.resetSearch}/>
This is my function:
resetSearch: function() {
this.setState({ID: 'Moo'});
},
I do see the ID change value in the console but it does not update on the screen.
Other things that I have tried
# when I do this the element despairs from then screen
resetSearch: function() {
var values = this.fields.state.values;
this.setState({
defaultValues: {
values
},
ignoreDefault: false
});
}
#render function
render: function() {
return (
<div className="card-body with-padding-bottom-0">
<form id={this.formId}>
<div id="sn-fields" className="usa-grid-full sn-search">
<SNFields ref={(fields) => { this.fields = fields; }} ddl_id='sn_search_card_type' snOptions={ this.getProp('snOptions')} fields={this.getProp('fields')} updateParentState={this.updateStateByField} defaultFieldValues={this.getProp('defaultValues')} ignoreDefault={this.state.ignoreDefault}></SNFields>
</div>
<div className="usa-grid-full with-margin-top-10 validation-div">
<div id="sn_search_card_search_button_container" className="usa-width-one-whole">
<label htmlFor="system_validator"></label>
<input hidden name="system_validator" id="system_validator"/>
<input id="search_button" type="button" name="search" value="Search" onClick={this.personSearch}/>
<input id="reset_button" type="button" name="reset" value="Reset" onClick={this.resetSearch}/>
</div>
</div>
</form>
</div>
);
}
I was able to find a class SNFields
var SNFields = React.createClass({
filterFields: function(searchVal) {
console.log('PCQSFields - filterFields ')
var filterLabels = [];
//filter in this component since the filtering can't be done on the ruby side
switch(searchVal) {
case 'APPLICATION_ID':
case 'ENUMERATOR':
case 'ENCOUNTER_ID': {
filterLabels = ['ID'];
break;
}
case 'NAME_AND_DOB': {
filterLabels = ['Date of Birth', 'Last Name', 'Date Range', 'First Name'];
break;
}
default: {
break;
}
}
var fields = this.props.fields.slice();
for (var i = fields.length - 1; i > -1; i--) {
if (filterLabels.indexOf(fields[i].label) < 0) {
fields.splice(i, 1);
}
}
return fields;
},
render: function() {
console.log('NSFields - render ')
return (
<div>
<div className="usa-width-one-third">
<label htmlFor={this.props.ddl_id} className="card-label bold">Search Type</label>
<Dropdown id={this.props.ddl_id} onChange={this.updateFields} selectableArray={this.props.nsOptions} classes="" selectedOption={this.state.ddl}/>
</div>
<div className="flex-container" style={{'flexWrap': 'row'}}>
{this.nsFieldsHelper(this.state.fields)}
</div>
</div>
);
}
});
I guess what I really want to do is when I press the reset to call
SNFields.filterFields('NAME_AND_DOB')
but when I try that I get a message in the console that reads: Uncaught TypeError: NSFields.filterFields is not a function
How does your componentDidMount() and componentWillReceiveProps(newProps) look like?
This is how I have done an Input component:
import React, { Component } from 'react';
export default class Input extends Component {
displayName: 'Input';
constructor(props) {
super(props);
this.state = {
value: this.props.value,
disabled: this.props.disabled,
checked: this.props.checked,
className:this.props.className,
maxLength:this.props.maxLength,
placeholder:this.props.placeholder,
id:this.props.id,
name:this.props.name,
type:this.props.name,
oldValue:this.props.value,
backgroundColor:''
};
this.handleBlur = this.handleBlur.bind(this);
this.handleChange = this.handleChange.bind(this);
};
componentWillReceiveProps(nextProps) {
if (this.state.value !== nextProps.value) {
this.setState({ value: nextProps.value});
};
if (this.state.disabled !== nextProps.disabled) {
this.setState({ disabled: nextProps.disabled});
};
if (this.state.checked !== nextProps.checked) {
this.setState({ checked: nextProps.checked});
};
if (this.state.className !== nextProps.className) {
this.setState({ className: nextProps.className});
};
if (this.state.maxLength !== nextProps.maxLength) {
this.setState({ maxLength: nextProps.maxLength});
};
if (this.state.placeholder !== nextProps.placeholder) {
this.setState({ placeholder: nextProps.placeholder});
};
};
componentDidMount() {
this.setState({ value: this.props.value,
disabled: this.props.disabled,
checked: this.props.checked,
className:this.props.className,
maxLength:this.props.maxLength,
placeholder:this.props.placeholder
});
};
handleBlur(event) {
if ((this.props.checkError===null)||(this.props.checkError(event,false) === true)) {
this.setState({ value: event.target.value,
oldValue: event.target.value
})
}
else
{
this.setState({ value: this.state.oldValue })
}
this.setState({ backgroundColor: ''})
};
handleChange(event) {
if (this.state.value !== event.target.value) {
this.setState({ value: event.target.value })
if ((this.props.checkError!==null)&&(this.props.checkError(event,true) === false)) {
this.setState({ backgroundColor: 'red'})
}
else
{
this.setState({ backgroundColor: ''})
}
}
if (this.props.onClick!==null) {
this.props.onClick();
}
};
render() {
return <input value={this.state.value}
maxLength={this.state.maxLength}
placeholder={this.state.placeholder}
className={this.state.className}
id={this.props.id}
name={this.props.name}
type={this.props.type}
disabled={this.state.disabled}
checked={this.state.checked}
onBlur={this.handleBlur}
onChange={this.handleChange}
style={{background:this.state.backgroundColor}}/>
}
};
Input.propTypes=
{
value:React.PropTypes.string,
placeholder:React.PropTypes.string,
maxLength: React.PropTypes.number,
disabled:React.PropTypes.bool,
checked:React.PropTypes.bool,
className:React.PropTypes.string,
id:React.PropTypes.string,
name:React.PropTypes.string,
type:React.PropTypes.string,
checkError: React.PropTypes.func,
onClick: React.PropTypes.func
}
Input.defaultProps =
{
placeholder:'',
maxLength:100,
disabled:false,
checked:false,
value:'',
className:'',
id:'',
name:'',
type:'text',
checkError:null,
onClick:null
}

How to dynamically show/hide a list of items in react

I'm having trouble being able to show/hide certain elements in react. Basically, I have a dynamic list of li's, and within the li, I have an label, when you click on the li I want to hide the label and show an input. Usually with jQuery it's as easy as
$('#element').hide()
$('#element2').show()
I'm not quite understanding how to achieve this with my current layout
class EntriesTable extends React.Component {
constructor(props) {
super(props);
console.log(this.props.plannerId);
this.state = {
tasks: [],
plannerId: this.props.plannerId,
};
var state = this.state;
}
componentDidMount() {
this.getTasks(this.state.plannerId);
}
EditTask(id) {
console.log(id);
var spanEl = id + 'taskSpan';
var inputEl = id + 'taskInput';
//hide this span
//show input
$(spanEl).hide();
$(inputEl).show();
//when save
//hide input
//update task
//show span
}
updateTask(id, name) {
$.ajax({
type: "GET",
url: "/Task/Update",
data: { id: id, name: name },
contentType: "application/json; charset=utf-8",
success: function (data) {
console.log(data);
//this.setState({ tasks: data.ReturnObject, loading: false });
}.bind(this),
error: function (xhr, status, err) {
console.log(err);
}
});
}
createTask(name) {
//make api call to create planner here.
var data = {
Name: name,
PlannerId: model.plannerId,
Status: "Not Complete",
Description: "",
Affiliation: "",
Footprint: "",
Created: new Date(),
Modified: null,
};
$.ajax({
type: "POST",
url: "/Task/Add",
data: JSON.stringify(data),
contentType: "application/json; charset=utf-8",
success: function (data) {
console.log(data);
this.getTasks(model.plannerId);
}.bind(this),
error: function (xhr, status, err) {
console.log(err);
}
});
}
getTasks(id) {
this.setState({ tasks: [], loading: true });
$.ajax({
type: "GET",
url: "/Task/GetAll",
data: { id: id },
contentType: "application/json; charset=utf-8",
success: function (data) {
console.log(data);
this.setState({ tasks: data.ReturnObject, loading: false });
}.bind(this),
error: function (xhr, status, err) {
console.log(err);
}
});
}
render() {
const tasks = this.state.tasks.map((task) => {
var spanId = task.Id + "taskSpan";
var inputId = task.Id + "taskInput";
return (
<li key={task.Id} className="list-group-item" style={{minHeight: '50px'}}>
<div className="pull-left" style={{width: '50%'}}>
<span id={spanId} onClick={this.EditTask.bind(this, task.Id) }>{task.Name}</span>
<input id={inputId} type="text" style={{ display: 'none' } } />
</div>
<div className="pull-right" style={{marginTop: '-5px', width: '50%'}}>
<div className="pull-right">
<button className="btn btn-default">Add</button>
<button className="btn btn-default">Edit</button>
</div>
</div>
</li>
);
});
return (
<div className="table-wrapper">
<div className="task-container">
<h3>{this.props.rowName}</h3>
</div>
<ul id="tasksContainer">
{tasks}
<li className="list-group-item list-group-item-last"><input type="button" value="Add Task" onClick={this.addTask.bind(this)} className="btn btn-success btn-override" /></li>
</ul>
</div>
);
}
};
I did see other SO's which tell you to use a variable and then to show/hide by changing the variable, but I'm not sure if that's doable for my need, since I have a dynamic list it's not just a single element I am trying to show or hide.
class EntriesTable extends React.Component {
constructor(props) {
super(props);
console.log(this.props.plannerId);
this.state = {
editableTasks: [],
tasks: [],
plannerId: this.props.plannerId,
};
var state = this.state;
/* This isn't completely necessary but usually it is recommended you
* bind the class method in the constructor so it isn't bound on each
* render
*/
this.EditTask = this.EditTask.bind(this);
}
componentDidMount() {
this.getTasks(this.state.plannerId);
}
EditTask(id) {
/* So jQuery and react are kind of at odds with each other on fundamentals
* React is supposed to be declarative whereas jQuery is imperative. Using
* jQuery and React together is typically discouraged unless there is a real
* need for it. In React you are supposed to define how you want the UI to render
* based on some variables. You have two options available to you props and state.
* props are passed from the parent and are immutable. state is managed within that
* component and is mutable. So we have added a variable called editableTasks to your
* state that will contain an array of all editable tasks. Instead of trying to hide
* or show items here, we are simply going to add the id of now editable task to that
* array
*
*/
var nextState = this.state;
nextState.editableTasks.push(id);
this.setState(nextState);
}
updateTask(id, name) {
$.ajax({
type: "GET",
url: "/Task/Update",
data: { id: id, name: name },
contentType: "application/json; charset=utf-8",
success: function (data) {
console.log(data);
//this.setState({ tasks: data.ReturnObject, loading: false });
}.bind(this),
error: function (xhr, status, err) {
console.log(err);
}
});
}
createTask(name) {
//make api call to create planner here.
var data = {
Name: name,
PlannerId: model.plannerId,
Status: "Not Complete",
Description: "",
Affiliation: "",
Footprint: "",
Created: new Date(),
Modified: null,
};
$.ajax({
type: "POST",
url: "/Task/Add",
data: JSON.stringify(data),
contentType: "application/json; charset=utf-8",
success: function (data) {
console.log(data);
this.getTasks(model.plannerId);
}.bind(this),
error: function (xhr, status, err) {
console.log(err);
}
});
}
getTasks(id) {
this.setState({ tasks: [], loading: true });
$.ajax({
type: "GET",
url: "/Task/GetAll",
data: { id: id },
contentType: "application/json; charset=utf-8",
success: function (data) {
console.log(data);
this.setState({ tasks: data.ReturnObject, loading: false });
}.bind(this),
error: function (xhr, status, err) {
console.log(err);
}
});
}
render() {
const tasks = this.state.tasks.map((task) => {
var editable = this.state.editableTasks.filter(id => id === task.Id).length > 0;
/* Now here we are going to check whether this item is editable
* based on id. So we assign a variable that will eval to a bool
* based on whether when you filter editableTasks to see if it contains
* the current items id the length is greater than 0.
*
* Now below instead of applying some id attribute we are going to return either
* the input or the span based on whether it is editable using a ternary operation
*
*/
return (
<li key={task.Id} className="list-group-item" style={{minHeight: '50px'}}>
<div className="pull-left" style={{width: '50%'}}>
{editable ? <input type="text" /> : <span onClick={this.EditTask( task.Id)}>{task.Name}</span>}
</div>
<div className="pull-right" style={{marginTop: '-5px', width: '50%'}}>
<div className="pull-right">
<button className="btn btn-default">Add</button>
<button className="btn btn-default">Edit</button>
</div>
</div>
</li>
);
});
return (
<div className="table-wrapper">
<div className="task-container">
<h3>{this.props.rowName}</h3>
</div>
<ul id="tasksContainer">
{tasks}
<li className="list-group-item list-group-item-last"><input type="button" value="Add Task" onClick={this.addTask.bind(this)} className="btn btn-success btn-override" /></li>
</ul>
</div>
);
}
};
So the above should work for making items editable. Now it doesn't handle actually editing them or returning them to non-editable state. But this should illustrate how you should be accomplishing this the 'react-way'.
I encourage you to drop jQuery. jQuery is going to make your React code harder to manage and make it harder to embrace the react way. If you need something for ajax requests, there are plenty of smaller libraries that just as well suited (superagent is highly recommended but a quick google can lead you to many other)
Let me know if you have any other question.
To show dynamically show/hide a list of items in react implement Visible.js in your file:
import React, { Component } from 'react'
import { Link, Router } from 'react-router';
import { connect } from 'react-redux';
import { Card, CardActions, CardHeader, CardMedia, CardTitle, CardText } from 'material-ui/Card';
import { List, ListItem } from 'material-ui/List';
import Divider from 'material-ui/Divider';
import '../../../static/images/cms-img3.jpg';
import '../../../static/images/cms-img4.jpg';
import '../../../static/images/cms-img5.jpg';
import '../../../static/images/grid-list/vegetables-790022_640.jpg';
import '../../../static/images/grid-list/00-52-29-429_640.jpg';
import '../../../static/images/grid-list/burger-827309_640.jpg';
import '../../../static/images/grid-list/camera-813814_640.jpg';
import '../../../static/images/grid-list/morning-819362_640.jpg';
import '../../../static/images/grid-list/hats-829509_640.jpg';
import '../../../static/images/grid-list/honey-823614_640.jpg';
import '../../../static/images/grid-list/water-plant-821293_640.jpg';
import '../../../static/images/video.mp4';
import '../../../static/images/video123.mp4';
class VisibleData extends Component {
constructor(props) {
super(props);
this.state = {
items: [],
};
this.onTodoClick = this.onTodoClick.bind(this);
}
componentDidMount() {
fetch('http://new.anasource.com/team9/news-api/?operation=view')
.then(result => result.json()
.then(news => {
this.setState({ items: news.news });
})
);
}
componentWillMount() {
window.onpopstate = (event) => {
this.componentDidMount();
};
}
onTodoClick(id) {
this.setState({
items: this.state.items.filter(item => item.news_id == id)
});
}
render() {
return (
<Data show={this.onTodoClick} items={this.state.items} />
)
}
}
class Data extends Component {
onTodoClick(e, id) {
this.props.show(id);
}
render() {
return (
<div>
{this.props.items.map(item => {
const p = item.news_type == "image";
const r = item.news_type == "video";
return <Link to={"todo/#/" + item.news_id} key={item.news_id}>
<Card onClick={(e) => this.onTodoClick(e, item.news_id)} style={{margin:15}}>
<CardTitle title={item.news_title} subtitle={item.news_description}>
<CardMedia>
{p
? <img src={item.news_src_url} />
: null
}
</CardMedia>
<CardMedia>
{r
? <video controls><source src={item.news_src_url} type="video/mp4"/></video>
: null
}
</CardMedia>
<div className='date'>{item.news_created_date}</div>
</CardTitle>
</Card>
</Link>
})
}
</div>
)
}
}
export default VisibleData;

Resources