Pass function in props Griddle custom component - ReactJS - javascript

I have the following code:
var RiderComponent = React.createClass({
updater: function(){
this.props.metadata.update();
},
render: function () {
return (
<a href="#" onClick={this.updater}>
click!
</a>
);
}
});
var RiderList = React.createClass({
columnMeta: [
{
"columnName": "action",
"displayName": "",
"cssClassName": "buy",
"order": 6,
"customComponent": RiderComponent,
"update": this.update
}
],
update: function () {
this.props.update();
},
render: function () {
return <Griddle results={this.props.data}
useGriddleStyles={false}
showFilter={true}
columnMetadata={this.columnMeta}
columns={['action']}
resultsPerPage={18}
initialSort={'value'}
initialSortAscending={false}
noDataMessage={'Geen wielrenners gevonden.'}
/>
}
});
I want to run the update() function from RiderList in my RiderComponent when I click on an item. However I keep getting: 'Uncaught TypeError: this.props.metadata.update is not a function'.
What is the correct way to execute the update function in my RiderComponent?
RiderList is rendered in TeamManager:
var TeamManager = React.createClass({
getInitialState: function () {
return {
results: [],
activeRiders: [],
extraRiders: [],
availablePositions: []
}
},
componentWillMount: function () {
this.getExternalData();
},
getExternalData: function () {
var race_id = 1; // TODO: this is hardcoded
request = Api.getRidersPageUrl(race_id);
$.get(request, function (rsp) {
var data = rsp;
var activeRiders = []; // Riders with position 0..8
var extraRiders = []; // Riders with position 9..14
var availablePositions = Array.apply(null, {length: 9}).map(Number.call, Number); // Array 0..8;
if (data) {
// set data to arrays here
}
this.setState({
results: data,
activeRiders: activeRiders,
extraRiders: extraRiders,
availablePositions: availablePositions
});
}.bind(this));
},
render: function () {
return (
<RiderList update={this.getExternalData} data={this.state.results}/>
)
}
});
module.exports = TeamManager;
Here this.getExternalData just reloads the data in this.state.results.
EDIT: I got something working while using onRowClick={this.update} in RiderList render . However this fires when I click the row and not a specific button IN the row.

Updated answer based upon question new info,
var RiderComponent = React.createClass({
render: function () {
return (
<a onClick={this.props.metadata.update}>
click!
</a>
);
}
});
var RiderList = React.createClass({
getColumnMeta: function(){
return[
{
"columnName": "action",
"displayName": "",
"cssClassName": "buy",
"order": 6,
"customComponent": RiderComponent,
"update": this.update
}
]
},
update: function () {
this.props.update();
},
render: function () {
return <Griddle results={this.props.data}
useGriddleStyles={false}
showFilter={true}
columnMetadata={this.getColumnMeta()}
columns={['action']}
resultsPerPage={18}
initialSort={'value'}
initialSortAscending={false}
noDataMessage={'Geen wielrenners gevonden.'}
/>
}
});

Related

Cannot read the json object in react

I am trying to make a json webapp which reads from apis and prints the result into a list.
The problem is that i cannot read the complete json object on render.
console.log(this.state.coinInfo);
coinInfo is a json object looking like:
quantstamp: {id: "quantstamp", name: "Quantstamp", symbol: "QSP", rank: "107", price_usd: "0.446127", …},
vechain: {id: "vechain", name: "VeChain", symbol: "VEN", rank: "30", price_usd: "5.80186", …}
writing:
this.state.coinInfo["vechain"] works, but
this.state.coinInfo["vechain"].id says undefined.
I would love to get the coinInfo informations into the element on render.
Here is the full code:
var Dashboard = React.createClass({
getInitialState: function() {
return {
coinListJson: "json/coinlist.json",
coinList: [],
coinInfo: {}
}
},
createDashboard: function(event) {},
componentDidMount: function() {
// Is there a React-y way to avoid rebinding `this`? fat arrow?
var th = this;
var coinListBuffer;
var coinInfoBuffer = {};
this.serverRequest = axios.get(this.state.coinListJson).then(function(result) {
coinListBuffer = result.data.coins;
th.setState({
coinList: result.data.coins
})
}).then(function() {
//alert("geht "+coinListBuffer[1].id);
coinListBuffer.map(function(val, index) {
var url = "https://api.coinmarketcap.com/v1/ticker/" + val.id + "/?convert=EUR";
th.serverRequest = axios.get(url).then(function(result) {
coinInfoBuffer[val.id] = result.data;
console.log(result.data[0]);
var coinInfoBufferString = coinInfoBuffer;
th.setState({
coinInfo: coinInfoBufferString
})
})
})
})
},
render: function() {
var th = this;
console.log(this.state.coinInfo);
return (
<ul>
{
this.state.coinList.map(function(val, index) {
return (
<li key={index}>
{val.id}
</li>);
})
}
</ul>
)
}
});

How to load another component inside a onChange function in ReactJS

I have this following code
var SelectOption = React.createClass({
getInitialState: function() {
return {
data: []
};
},
handleemployeeChange: function() {
alert('sssss');
},
loadOptionfromServer: function() {
$.ajax({
url: this.props.url,
dataType: 'json',
cache: false,
success: function(data) {
this.setState({
data: data
});
console.log(data);
}.bind(this),
error: function(xhr, status, err) {
console.error(this.props.url, status, err.toString());
}.bind(this)
});
},
componentDidMount: function() {
alert('sssss');
this.loadOptionfromServer();
//setInterval(this.loadCommentsFromServer, this.props.pollInterval);
},
render: function() {
return ( < SelectOptionList data = {
this.state.data
}
/>
);
}
});
var SelectOptionList = React.createClass({
render: function() {
var commentNodes = this.props.data.map(function(list) {
return ( < Addcontenttoselect id = {
list.emp_ide_id
}
option = {
list.emp_name
} >
< /Addcontenttoselect>
);
});
return ( < select id = "select1"
className = "form-control"
data - placeholder = "Basic Select2 Box"
onChange = {
this.handleemployeeChange
} > {
commentNodes
} < /select>
);
}
});
var Addcontenttoselect = React.createClass({
render: function() {
return ( < option value = "{this.props.id}" > {
this.props.option
} < /option>);
}
});
ReactDOM.render( < div className = "col-md-3" > < h3 > Select Employee to Review < /h3><SelectOption url="/appraisal / employeelist " pollInterval={70000} /></div>, document.getElementById('select-box'));
So this component creates a Select Tag in the browser , I want to take the Value of the selected option and Call another component which will create a Table from a data got from API
Any leads please let me know
Thanks
With react you have multiple ways to pass around data to your components, it depends heavily on the use and the complexity of your application.
If you have a lot of components which need to know about the state/data of another component you should look at application architectures like flux or redux. Facebooks Flux
For some applications a full data flow architecture can be overkill so it depends on how you design your components. A common pattern is to have one component who handles the state/interactivity of your application.
Your main component will hold all the business logic of your app and pass down functions to its child to e.g. change state.
You can read more about this here Facebook thinking react
I did a little fiddle which adresses your challenge:
Fiddle
var Select = React.createClass({
render: function() {
var selectOptions = this.props.options.map(function(optionData) {
return (
<option key={optionData.id} value={optionData.id}>
{optionData.name}
</option>
);
});
return (
<select
id="select1"
className="form-control"
placeholder="Basic Select2 Box"
onChange={this.props.onChange}
>
{ selectOptions }
</select>
);
}
});
var SelectApp = React.createClass({
// The main component holds the data
getInitialState: function() {
return {
data: [],
currentData: null
}
},
componentDidMount: function () {
this.loadOptions();
},
loadOptions: function () {
var _this = this;
return setTimeout(function() {
_this.setState({data: [
{
id: 1,
name: 'Foo Bar'
},
{
id: 2,
name: 'Bar Foo'
}
]});
}, 2000);
},
onChange: function (e) {
var employeeId = e.target.value,
_this = this,
mockedData = [
{
id: 1,
data: 'Good employee'
},
{
id: 2,
data: 'Not so good employee'
}
];
// Mocking an additional data fetch
setTimeout(function () {
var result = mockedData.find(function (employeeData) {
return (employeeData.id == employeeId);
});
_this.setState({
currentData: result
});
}, 2000);
},
renderResult: function () {
if (this.state.currentData) {
return (
<div>
<h4>Employee:</h4>
<p>{this.state.currentData.data}</p>
</div>
);
}
return;
},
render: function() {
return (
<div>
<div>
<h3> Select Employee to Review </h3>
<Select url={this.props.url} options={this.state.data} onChange={this.onChange}/>
</div>
{this.renderResult()}
</div>
);
}
});
ReactDOM.render(<SelectApp url="/appraisal / employeelist " pollInterval={70000} />, document.getElementById('container'));
Edit:
renderResult: function () {
if (this.state.currentData) {
return (
<loadUserAppraisal url="something" empid={this.state.currentData.id} />
);
}

How to parse data with React.js?

I have 2 request
html: <div>{{name}}</div>
json {"name": "Vasya"}
How with React parse this data and return <div>Vasya</div> ?
module.exports = React.createClass({
getInitialState: function () {
return {
previewData: {}, // {"name":"Vasya"}
previewHtml: {} // "<div>{{name}}</div>"
},
getTemplateDataStore: function (event, previewData) {
this.setState({
previewData: previewData
});
},
getTemplateHTMLStore: function (event, previewHtml) {
this.setState({
previewHtml: previewHtml
});
},
render: function () {
return // ?????????? need return <div>Vaysa</div>?
}
},
});

Simulating drag drop with react testutils not working

I'm try to test my ReactJS mixin for drag and drop functionality using jasmine, karma and React TestUtils.
No exception is thrown but when debugging it seems that the function bound to the event listener not being executed when the event is simulated.
You can clone the it here:
https://github.com/itsh01/react-dragdrop/tree/testing-simutale-events
Thank you very much in advance.
Here is my test:
beforeEach(function () {
var CompDrag = React.createClass({
mixins: [DragDropMixin],
dragDrop: function dragDrop() {
return {
draggable: true,
dropType: 'test',
dataTransfer: {
test: true
}
};
},
render: function render() {
return React.createElement('div', {});
}
});
var CompDrop = React.createClass({
mixins: [DragDropMixin],
dragDrop: function dragDrop() {
var self = this;
return {
droppable: true,
acceptableTypes: ['test'],
drop: function (data) {
self.setState(data);
}
};
},
render: function render() {
return React.createElement('div', {});
}
});
elementDrag = React.createElement(CompDrag, {});
elementDrop = React.createElement(CompDrop, {});
});
...
it('should attach drop functionality when configured', function () {
var renderedDrag = TestUtils.renderIntoDocument(elementDrag);
var renderedDrop = TestUtils.renderIntoDocument(elementDrop);
var nodeDrag = renderedDrag.getDOMNode();
var nodeDrop = renderedDrop.getDOMNode();
var mockEvent = {
preventDefault: function () {},
dataTransfer: {
types: ["objtopass"],
setData: function () {},
getData: function () {
return JSON.parse({
dropType: 'test',
data: {
test: true
}
});
}
}
};
TestUtils.SimulateNative.dragStart(nodeDrag, mockEvent);
TestUtils.Simulate.dragOver(nodeDrop, mockEvent);
TestUtils.Simulate.drop(nodeDrop, mockEvent);
expect(renderedDrop.state).not.toBeNull();
});
Here is the mixin:
'use strict';
var _ = lodash;
var DragDropMixin = {
/*
* usage:
*
* mixins: [DragDropMixin],
* dragDrop: function () {
*
* return {
*
* // when dragging an item
* draggable: true,
* dropType: 'myItem',
* dataTransfer: { myItemData: property }
*
* // when dropping an item:
* droppable: true,
* acceptableDrops: ['myItem'],
* drop: function (myItem) {},
* };
* }
*
*/
isAttrEnabled: function (attr) {
return this.dragDropData && this.dragDropData[attr];
},
isDroppable: function () {
return this.isAttrEnabled('droppable');
},
isDraggable: function () {
return this.isAttrEnabled('draggable');
},
componentDidMount: function () {
var node = this.getDOMNode();
this.dragDropData = this.dragDrop();
if (this.isDroppable()) {
node.addEventListener('dragover', this.handleDragOver, this);
node.addEventListener('drop', this.handleDrop, this);
}
if (this.isDraggable()) {
node.draggable = true;
node.addEventListener('dragstart', this.handleDragStart, this);
}
},
componentWillUnmount: function () {
var node = this.getDOMNode();
if (this.isDroppable()) {
node.removeEventListener('dragover', this.handleDragOver);
node.removeEventListener('drop', this.handleDrop);
}
if (this.isDraggable()) {
node.removeEventListener('dragstart', this.handleDragStart);
}
},
handleDragOver: function (e) {
e.preventDefault();
},
handleDrop: function (e) {
var jsonData = e.dataTransfer.getData('objToPass'),
passedObj = JSON.parse(jsonData),
acceptableDrops = this.dragDropData.acceptableDrops;
e.preventDefault();
if (!this.dragDropData.drop) {
throw new Error('Must define drop function when using droppable');
}
if (_.includes(acceptableDrops, passedObj.dropType)) {
this.dragDropData.drop(passedObj.data);
}
},
handleDragStart: function (e) {
var objToPass = {
data: this.dragDropData.dataTransfer,
dropType: this.dragDropData.dropType
};
e.dataTransfer.setData('objToPass', JSON.stringify(objToPass));
}
};
Thanks again.
OK, got it.
I was actually listening to native events and simulating React synthetic events.
Fixed it by changing the mixin:
componentDidMount: function () {
var node = this.getDOMNode();
this.dragDropData = this.dragDrop();
if (this.isDroppable()) {
node.ondragover = this.handleDragOver;
node.ondrop = this.handleDrop;
}
if (this.isDraggable()) {
node.draggable = true;
node.ondragstart = this.handleDragStart;
}
},
And testing by triggering a native event
nodeDrag.ondragstart(mockEvent);
nodeDrop.ondragover(mockEvent);
nodeDrop.ondrop(mockEvent);
expect(DragDropMixin.handleDrop).toHaveBeenCalled();
expect(renderedDrop.state).toBeNull();

How to refresh/update data source in a specific interval

This script's purpose is to load the data source into table first,
And then there is a search box to search data.
The dataSource only load at the first time page load,
How to make it reload the data source every 30 seconds, thanks
<TableSorter dataSource={"/welcome/get_winner_list"} config={CONFIG} />
Here's the whole script
/** #jsx React.DOM */
var CONFIG = {
sort: { column: "_id", order: "desc" },
filterText: "",
columns: {
_id: { name: "獎次"},
name: { name: "獎品"},
can_accept_prize_now: { name: "現領"},
staff_name: {name: "姓名"},
staff_id: {name: "工號"},
}
};
var TableSorter = React.createClass({
getInitialState: function() {
return {
items: this.props.initialItems || [],
sort: this.props.config.sort || { column: "", order: "" },
columns: this.props.config.columns,
filterText:this.props.config.filterText
};
},
componentWillMount: function() {
this.loadData(this.props.dataSource);
},
loadData: function(dataSource) {
if (!dataSource) return;
$.get(dataSource).done(function(data) {
console.log("Received data");
this.setState({items: data});
}.bind(this)).fail(function(error, a, b) {
console.log("Error loading JSON");
});
},
handleFilterTextChange: function (event){
this.setState({filterText:event.target.value})
},
editColumnNames: function() {
return Object.keys(this.state.columns);
},
receive_click:function(event){
name_staff=event.target.name.split(',')
dataSource='/take/'+name_staff[0]+'/'+name_staff[1];
$.getJSON(dataSource).done(function() {
console.log("Input success");
}.bind(this)).fail(function(error, a, b) {
console.log("Error :Input Prize");
});
itemsColumn=_.find(this.state.items,function(column){return column['_id']==name_staff[0]});
itemsColumn['taken_at']=true;
this.setState()
},
render: function() {
var rows = [];
var columnNames = this.editColumnNames();
var filters = {};
columnNames.forEach(function(column) {
var filterText = this.state.filterText;
filters[column] = null;
if (filterText.length > 0 ) {
filters[column] = function(x) {
if(x)
return (x.toString().toLowerCase().indexOf(filterText.toLowerCase()) > -1);
};
}
}, this);
var filteredItems = _.filter(this.state.items, function(item) {
return _.some(columnNames, function(c) {
return (!filters[c] || filters[c](item[c]));
}, this);
}, this);
var sortedItems = _.sortBy(filteredItems, this.state.sort.column);
if (this.state.sort.order === "desc") sortedItems.reverse();
var cell = function(x) {
return columnNames.map(function(c) {
if (c == 'taken_at') {
if (x[c])
return <td>
<span className="btn btn-shadow btn-danger" disabled="disabled">已領取</span>
</td>;
else
return <td>
<button name={x['_id']+','+x['staff_id']} className="btn btn-shadow btn-success" onClick={this.receive_click}>未領取</button>
</td>;
}
else if (c == 'can_accept_prize_now') {
if (x[c] )
return <td>
<img src="/images/check.png"></img>
</td>;
else
return <td>
<img src="/images/cross.png"></img>
</td>;
}
else
return <td>{x[c]}</td>;
}, this);
}.bind(this);
sortedItems.forEach(function(item) {
rows.push(
<tr key={item.id}>
{ cell(item) }
</tr>
);
}.bind(this));
var header = columnNames.map(function(c) {
return <th >{this.state.columns[c].name}</th>;
}, this);
return (
<div className="table">
<form>
<fieldset>
<input type="text" name="s" id="s" placeholder="搜尋方式:部分工號、部分姓名、部分獎次,皆可查詢。 Eg: 林 or 726 "
value={this.state.value} onChange={this.handleFilterTextChange}/>
</fieldset>
</form>
<p/>
<table cellSpacing="0" className="table table-striped table-advance table-hover prizes">
<thead>
<tr>
{ header }
</tr>
</thead>
<tbody>
{ rows }
</tbody>
</table>
</div>
);
}
});
var QueryString = function () {
// This function is anonymous, is executed immediately and
// the return value is assigned to QueryString!
var query_string = {};
var query = window.location.search.substring(1);
var vars = query.split("&");
for (var i=0;i<vars.length;i++) {
var pair = vars[i].split("=");
// If first entry with this name
if (typeof query_string[pair[0]] === "undefined") {
query_string[pair[0]] = pair[1];
// If second entry with this name
} else if (typeof query_string[pair[0]] === "string") {
var arr = [ query_string[pair[0]], pair[1] ];
query_string[pair[0]] = arr;
// If third or later entry with this name
} else {
query_string[pair[0]].push(pair[1]);
}
}
return query_string;
} ();
var App = React.createClass({
render: function() {
return (
<div>
<TableSorter dataSource={"/welcome/get_winner_list"} config={CONFIG} />
</div>
);
}
});
$( document ).ready(function() {
console.log( "ready!" );
if(document.getElementById("searchWinner")){
React.render(<App />, document.getElementById("searchWinner"));
}
});
Update
I got the Uncaught TypeError: Cannot read property 'interval' of null
by the following code
getInitialState: function() {
return {
interval: 5,
items: this.props.initialItems || [],
sort: this.props.config.sort || { column: "", order: "" },
columns: this.props.config.columns,
filterText:this.props.config.filterText
};
},
componentDidMount: function() {
setInterval(function() {
this.setState({
interval: this.state.interval + 1
});
}.bind(this), 1000);
},
componentWillMount: function() {
this.loadData(this.props.dataSource);
},
var App = React.createClass({
render: function() {
return (
<div>
<TableSorter key={this.state.interval} dataSource={"/welcome/get_winner_list"} config={CONFIG} />
</div>
);
}
});
I suppose TableSorter is external component, so I suggest to force component to re-render using key property from parent component. Something like
componentDidMount: function() {
setInterval(function() {
this.setState({
interval: this.state.interval + 1
});
}.bind(this), 1000);
},
render: function() {
return <TableSorter key={this.state.interval} dataSource={"/welcome/get_winner_list"} config={CONFIG} />
}
Minus is that will reset any state inside TableSorter (paging, selected rows) after interval.
i can use this script:
setInterval(function() {
alert("alert every 3 second");
}, 3000);
EXAMPLE

Categories