How to set className for selected child component in ReactJS - javascript

New to ReactJs - I have had a look at the documentation here and here but I am a bit confused.
So I have a component that creates several table rows according to the JSON data.
I am trying to make it so once a radio button is selected, the class of the parent <td> is set to 'success'. But at the moment all the rows with that column get the same class name.
var SearchResult = React.createClass({
getInitialState: function () {
return {
site: '',
address: '',
data: [],
checked: ''
};
},
onSiteChanged: function (e) {
this.setState({
site: e.currentTarget.value,
checked: 'success'
});
},
render: function () {
var resultRows = this.props.data.map(function (result) {
return (
<tr>
<td className={this.state.checked}>
<input type="radio" name="site_name"
value={result.SITE_NAME}
onChange={this.onSiteChanged}
key={result.id}/>{result.SITE_NAME}</td>
<td>
<input type="radio" name="address"
value={result.ADDRESS}
onChange={this.onAddressChanged} />{result.ADDRESS}</td>
</tr>
);
}, this);
return (
<table className="table table-hover table-condensed">
<thead>
<tr>
<th>Name</th>
<th>Address</th>
</tr>
</thead>
<tbody>
{resultRows}
</tbody>
<tfoot>
<tr>
<td></td>
<td>{this.state.site}</td>
<td>{this.state.address}</td>
</tr>
</tfoot>
</table>
);
}
});
What is the best ReactJS way to proceed to make sure the selected result get the selected class name?
Thank you.

To modify values passed to classSet property React has special addon: React.addons.classSet. It is very handy when you are changing multiple different classes but in your case it can be usefull, too:
var SearchResult = React.createClass({
getInitialState: function () {
return {
site: '',
address: '',
checked: false,
data: [],
};
},
onSiteChanged: function (selected) {
this.setState({
site: selected.SITE_NAME,
checked: selected.id,
});
},
render: function () {
var resultRows = this.props.data.map(function (result) {
var cx = React.addons.classSet({
success: (this.state.checked === result.id)
});
return (
<tr key={result.id}>
<td className={cx}>
<input type="radio" name="site_name"
value={result.SITE_NAME}
onChange={this.onSiteChanged.bind(this, result)}
/>{result.SITE_NAME}</td>
<td>
<input type="radio" name="address"
value={result.ADDRESS}
onChange={this.onAddressChanged} />{result.ADDRESS}</td>
</tr>
);
}, this);
return (
<table className="table table-hover table-condensed">
<thead>
<tr>
<th>Name</th>
<th>Address</th>
</tr>
</thead>
<tbody>
{resultRows}
</tbody>
<tfoot>
<tr>
<td></td>
<td>{this.state.site}</td>
<td>{this.state.address}</td>
</tr>
</tfoot>
</table>
);
}
});

Related

How include multiple criteria in COUNT ROWS with javascript

I have the next HTML code:
<table border="1">
<tr>
<th>Nº</th>
<th>NOMBRE</th>
<th>AREA</th>
</tr>
<tbody id="curso">
<tr>
<td>1</td>
<td>Jose</td>
<td>Gramática</td>
</tr>
<tr>
<td>2</td>
<td>Luis</td>
<td>Gramática</td>
</tr>
<tr>
<td>3</td>
<td>Andrea</td>
<td>Gramática</td>
</tr>
<tr>
<td>4</td>
<td>Andrea</td>
<td>Idiomas</td>
</tr>
</tbody>
</table>
<p id="Cantidad"></p>
</body>
This code can count the number of rows using a criteria in the AREA field:
<script>
function ContarFila() {
var cantidadFilas = document.getElementById("curso").rows.length;
let resultados = {};
let elementos = document.querySelectorAll(
"table tbody tr > td:nth-child(3)"
);
elementos.forEach(elemento => {
if (resultados.hasOwnProperty(elemento.innerText)) {
resultados[elemento.innerText]++;
} else {
resultados[elemento.innerText] = 1;
}
});
console.log(resultados);
for (let indice in resultados) {
document.getElementById("Cantidad").innerHTML =
resultados['Gramática'];
};
}
window.onload=ContarFila();
</script>
When loading the page and using the 'Gramática' criteria of the 'AREA' field, the result is 3.
How do I include MULTIPLE CRITERIA with the 'NOMBRE' and 'AREA' field at the same time?
Example:
Using Criteria 1: 'Grammar'
Using Criteria 2: 'Luis'
RESULT: 1
THAK YOU!
If I understood you correctly, then perhaps this example below can help you:
function getResult(table, search = {}) {
const tableHeadCells = Array.from(table.tHead.rows[0].cells);
const tableBodyRows = Array.from(table.tBodies[0].rows);
const indexes = tableHeadCells.map((el) => el.dataset["label"]); // <= // ['index', 'nombre', 'area']
const count = tableBodyRows.reduce((acc, row) => {
isSearched = indexes.every(
(key, i) => !search[key] || search[key] === row.cells[i].innerText
);
return isSearched ? ++acc : acc;
}, 0);
return count;
}
const table = document.querySelector('table');
console.log('1 => ', getResult(table, {
area: 'Gramática'
}));
console.log('2 => ', getResult(table, {
nombre: 'Luis',
area: 'Gramática'
}));
console.log('3 => ', getResult(table, {
index: '3',
nombre: 'Andrea'
}));
<table border="1">
<thead>
<tr>
<th data-label="index">Nº</th>
<th data-label="nombre">NOMBRE</th>
<th data-label="area">AREA</th>
</tr>
</thead>
<tbody id="curso">
<tr>
<td>1</td>
<td>Jose</td>
<td>Gramática</td>
</tr>
<tr>
<td>2</td>
<td>Luis</td>
<td>Gramática</td>
</tr>
<tr>
<td>3</td>
<td>Andrea</td>
<td>Gramática</td>
</tr>
<tr>
<td>4</td>
<td>Andrea</td>
<td>Idiomas</td>
</tr>
</tbody>
</table>
Note that in the header of the table, the columns are indicated by data-attributes data-label in order to understand which column belongs to which keyword. And then, we just count the number of elements in the loop, which completely match the specified requirements for all columns

How can i get data-id value(id) store in Array using JavaScript?

how can i get id number(data-id) using JavaScript. I'm using sortable.min.js for drag & drop. i want to get the td ID(data-id) which is inside of #drop table and store it into a array(sort)?
table.html
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>Story</th>
</tr>
</thead>
<tbody id="drop" class="sortables">
<tr>
<td data-id="67">67</td>
<td>this is test post for (news2)d</td>
</tr>
<tr>
<td data-id="59">59</td>
<td>how to use custom fonts in dja</td>
</tr>
<tr>
<td data-id="51">51</td>
<td>how can i merge two forms fiel</td>
</tr>
</tbody>
</table>
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>Story</th>
</tr>
</thead>
<tbody id="drag" class="sortables">
</tbody>
</table>
script.js
new Sortable(drag, {
group: '.sortables',
animation: 150,
});
new Sortable(drop, {
group: '.sortables',
animation: 150,
onChange: function (e, tr) {
sort = [];
$("#drog").children().each(function () {
sort.push({ 'id': $(this).data('id') })
});
console.log(sort)
},
});
As pointed out, you have a Typo in your Selector:
$("#drog")
Should be:
$("#drop")
You can also consider the following.
new Sortable(drag, {
group: '.sortables',
animation: 150,
});
new Sortable(drop, {
group: '.sortables',
animation: 150,
onChange: function (e, tr) {
var sort = [];
$("#drop > tbody > tr").each(function (i, row) {
sort.push({ 'id': $("td:first", row).data('id') });
});
console.log(sort);
},
});
Your previous code was targeting the children of #drop, which are <TR> elements and do not have the Data attribute.
The new code targets the 1st <TD> element of each row. This element has the Data attribute.

Implement check all checkbox in react && angular

I'm trying to implement check all feature on my checkbox element but I can't manage to do that.Can someone help ?
var FormattedDate = ReactIntl.FormattedDate;
var DiaryTable = React.createClass({
getInitialState: function() {
return {
items : this.props.item,
globalChecked: false
};
},
changeSelection:function (i) {
var state = this.state.items.map(function (element) {
return {
start:element.start,
end:element.end,
hours:element.hours,
selected:(element === this.state.items[i] ? !element.selected:element.selected)
};
});
},
render: function(){
var arrayItems = this.state.items.map(function (item,i) {
return (
<tr key={i}>
<td><input type="checkbox" checked={item.selected} onChange={this.changeSelection(i).bind(this)}/></td>
<td><FormattedDate value={item.start}/></td>
<td><FormattedDate value={item.end}/></td>
<td>{item.hours}</td>
<td>
<button className="editButton"></button>
</td>
<td>
{this.state.items[i].selected}
</td>
</tr>
);
}.bind(this));
return (
<table className="myTable">
<thead>
<tr>
<th><input type="checkbox"/></th>
<th>Start Date:</th>
<th>End Date:</th>
<th id="hoursField">Hours:</th>
<th id="editField">Edit:</th>
<th>selected:</th>
</tr>
</thead>
<tbody>
{arrayItems}
</tbody>
<tfoot>
<tr>
<td colSpan="4">
<button className="myButton" id="addPeriodButton">Add period</button>
<button className="myButton">Remove period</button>
<button className="myButton">Set result from merge</button>
</td>
</tr>
</tfoot>
</table>
);
}
});
I', taking data from my controller:
app.controller('MainCtrl', function ($scope) {
$scope.resultProps = {
item:[]
}
$scope.firstArrayProps = {
item:[{start:new Date(),end:22,hours:3,selected:false},{start:22,end:33,hours:44,selected:false}]
}
$scope.secondArrayProps = {
item:[{start:22,end:33,hours:44,selected:false}]
}
..... more code here
and index.html..
<body ng-app="app" ng-controller="MainCtrl as mainCtrl">
<!--<div id="diaryWrapper">-->
<!--<!–<diary-template props="firstArrayProps" result="resultProps" ></diary-template>–>-->
<!--<!–<div class="mergeWrapper">–>-->
<!--<!–<button class="myButton" id="mergeButton" ng-click="runMerge()">Merge diaries</button>–>-->
<!--<!–</div>–>-->
<!--<!–<diary-template props="secondArrayProps" result="resultProps" ></diary-template>–>-->
<!--</div>-->
<div class="tableWrapper">
<react-component name="DiaryTable" props="firstArrayProps" />
</div>
<div class="tableWrapper">
<react-component name="DiaryTable" props="secondArrayProps" />
</div>
If I'm doing wrong something else please feel free to tell me . Thank you !
The code for handleSelectAll should be:
handleSelectAll: function(e) {
var items = this.state.items.slice();
items.forEach(function(item) {
item.selected: e.target.checked,
});
this.setState({ items: items });
}

React unexpected token { } when trying to loop inside render

I was following the example on the react website on how to loop inside render I've got what I wanted to accomplish done, but I have
var AdminForumContainer = React.createClass({
getInitialState: function() {
return { containers: [] }
},
componentDidMount: function() {
$.ajax({
method: 'GET',
url: '/admin/manage/forum/populate',
success: function(data) {
console.log(data);
}
})
},
render: function() {
return (
{this.state.containers.map(function(container) {
return (
<table className="containers">
<caption>{container.containername}</caption>
<thead className="containerTitle">
<tr>
<td colspan="2">Main Threads</td>
</tr>
</thead>
<thead>
<tr>
<td>Thread Name</td>
<td>Delete</td>
</tr>
</thead>
<tbody>
{
container.mainthreads.map(function(mainthread) {
return (
<tr>
<td>{mainthread.threadname}</td>
<td><button className="button alert">Delete</button></td>
</tr>
)
})
}
<tr>
<td><input type="text"/></td>
<td><button className="button" onclick={this.createMainThread(container.containerid)}>Create</button></td>
</tr>
</tbody>
<thead>
<tr>
<td colspan="2">Sub Threads</td>
</tr>
</thead>
<tbody>
{
container.mainthreads.map(function(subthread) {
return (<tr>
<td>{subthread.threadname}</td>
<td><button className="button alert">Delete</button></td>
</tr>)
})
}
<tr>
<td><input type="text"/></td>
<td><button className="button" onclick={this.createSubThread(container.containerid)}>Create</button></td>
</tr>
</tbody>
</table>
)
})}
)
}
});
but I get
Uncaught SyntaxError: http://localhost:8080/static/js/admin.jsx: Unexpected token (16:8)
14 | render: function() {
15 | return (
> 16 | {this.state.containers.map(function(container) {
| ^
17 |
18 | <table className="containers">
19 | <caption>{container.containername}</caption>
not sure what is wrong here. Thanks.
That line looks OK. It's the next line that's an issue. Your loop function needs a return statement. i.e.
{this.state.containers.map(function(container) {
return (
<table className="containers">
Same goes for the other functions passed to Array#map.
UPDATE: I've got it. Remove the surrounding braces. They're only needed inside a JSX container. i.e.
UPDATE Mk II: In fact you need a container since React components must have a single root element. So put the whole thing in a wrapper div. i.e.
render: function () {
return (
<div>
{this.state.containers.map(function(container) {

React : Render returns createElement

I just started to learn React and I'm using it with a Rails backend.
In my view I have :
<%= react_component 'Products', { data: #products } %>
It works fine with this static code :
var Products = React.createClass({
getInitialState: function () {
return {products: this.props.data};
},
getDefaultProps: function() {
return {products: []};
},
render: function () {
return (
<div className="products">
<h2 className="title">List of products</h2>
<table className="table table-bordered">
<thead>
<tr>
<th>Name</th>
<th>Company</th>
<th>RRP</th>
</tr>
</thead>
<tbody>
<tr>
<td>AAA</td>
<td>BBB</td>
<td>CCC</td>
</tr>
</tbody>
</table>
</div>
);
}
});
I've got my table displayed well.
The next step is to have the same result but with each line representing a new product's element. So I start to create a new React Class in the same file :
var ProductLine = React.createClass({
render: function () {
return (
<tr>
<td>AAA</td>
<td>BBB</td>
<td>CCC</td>
</tr>
);
}
});
My problem is, how can I render this ProductLine in my table ? Because if I do this :
<tbody>
React.createElement ProductLine
</tbody>
The line is considered as plain text and not rendered...
Actually I found the solution just after posting this question.
This post called Thinking in React from Pete Hunt is very useful, especially for a React newbie. Also, the example is almost the same as my situation...
var ProductRow = React.createClass({
render: function () {
return (
<tr>
<td>{this.props.product.name}</td>
<td>{this.props.product.company_id}</td>
<td>{this.props.product.price}</td>
</tr>
);
}
});
var ProductTable = React.createClass({
render: function () {
var rows = [];
this.props.data.forEach(function(product) {
rows.push(<ProductRow product={product} key={product.id} />);
});
return (
<div className="products">
<h2 className="title">List of products</h2>
<table className="table table-bordered">
<thead>
<tr>
<th>Name</th>
<th>Company</th>
<th>RRP</th>
</tr>
</thead>
<tbody>
{rows}
</tbody>
</table>
</div>
);
}
});
I could be wrong but <ProductLine /> is how you would instantiate a component within the render function of another parent component i.e.:
<tbody>
<ProductLine />
</tbody>

Categories