React Table dynamic columns and rows from Json Data - javascript

So here is my question. How can I display the header names and its respective rows dynamically? I am using a simple react table right now.
I have hardcoded the names as you can see in the table (2017-8, 2017-9, .....) from the image.
the columns should be label and rows should be its respective value from the referencePoints array.

Just place a code block in the table header as follows:
<th>{header}</th>
You can receive your header from props or state in the render method. If you are receiving it from Redux your render method might contain:
const {header} = this.props;
return(
<table>
<tr> <th>{header}</th>...</tr>
...
</table>
)
You might also loop through your headers if you want:
<tr> {headers.map((head, i)=>(<th key={i}>{head}</th>))} </tr>
Make sure to add a key to items added with an array. React will warn you if you don't.

You can write a loop across your table headers like
header = [];
Dates.forEach(date => {
header.push(<td>{date.value}</td>
});
you can render like
<th>
{header}
<th>
The code is just a representation and not actual code

Related

html table is duplicating defaultValue's for no apparent reason

I have some data that is displayed in a table. When I add a table data cell (td) with JS the defaultValue and innerText of the previous table data cell (td) is being copied in the new table data (td). I don't understand why this happens? I just add a new html element which, in essence, has nothing to do with the already existing element I would say.
const [dataSet, setDataSet] = useState([
{
City: "Amsterdam",
Provence: "North-Holland"
},
{
City: "Rotterdam",
Provence: "South-Holland"
}
]);
const newCity = () => {
const city = [
{
City: "Groningen",
Provence: "Groningen"
}
];
setDataSet(city);
};
<button onClick={newCity}>Add city</button>
<table>
<tr>
<th>City</th>
<th>Provence</th>
</tr>
{dataSet.map(city => (
<tr>
<td>
<input defaultValue={city.City}/>
</td>
<td>
<input defaultValue={city.Provence}/>
</td>
</tr>
)}
</table>
So when I click on the 'newCity button' a new table row (tr) is added, but instead of populating the table data cells (td) with the correct data (City: 'Groningen', Provence: 'Groningen') it populates the td with the data from the previous table row (tr) (City: 'Amsterdam', Provence: 'North-Holland'). This seems really odd to me, since I only add a new html element that has no relation to the table row (tr) before it exempt for it being in the same table.
Here is a codebox link to see the behavior in action:
https://codesandbox.io/s/dry-water-rss2m8?file=/src/App.js
Why does it behave like this?
There are two important things to take into consideration here.
First, your program is outputting a warning:
Warning: Each child in a list should have a unique "key" prop.
Always deal with warnings. They are there for a reason!
Second, you are dealing with a default (as opposed to current) value.
When you replace the array with a new array, React generates new JSX and compares it to the existing DOM.
The first row has the same (lack of) key so it changes the default values of the existing row. (The second row no longer exists so it removes it).
Changing the default values doesn't have any effect through: The inputs already have values, which they continue to display.
You could give the generated rows keys:
<tr key={something}>
… but you will need to figure out what the something is.
You might use the city name, but it seems like that is a piece of data which might change — so changing the city name would make it look like a new row and not an update to an existing row.
You might consider using the uuid module to generate a unique ID when the object is created.
You could also make the inputs controlled by passing them values instead of default values. This would require that you update the value you pass to them as they are edited.
You need to set a key on the item
{dataSet.map((city) => (
<tr key={city.City}>
...
etc
I guess it is because you are working with uncontrolled components.
If you want your input values to reflect state changes you need to use the value and not the defaultValue, and you also probably want to have an onChange handler.
<input value={city.City} />
First, the native Input element doesn't have defaultValue attribute. Look at the attributes list in MDN. It has only value and placeholder.
Secondly, if you want to add new city to the dataSet, you must merge the city-object to the array, not replace it.
setDataSet(currentDataSet => {
return [...currentDataSet, city]
})

How to add field type as button in reactable library

I am using reactable to draw table in my react app.
I get data from server in json object and pass this data to Table
render(){
return(
<Table className="table" data= {this.state.content}
defaultSort={{column: 'account_status', direction: 'desc'}}
/>
)}
This works fine and draws the table like this.
Now i want to add 2 buttons with each row, Approve/reject.
I want to know the possibility of adding buttons with each row when using reactable

How to insert a new row in Material-UI?

I'm developing a contacts application where all data is stored on client-side temporarily. I've used material-ui table to display the contacts.
When add new contact button on the bottom right is clicked it displays a Dialog with a form in it. When save button is clicked the data is saved in the state. But the problem I'm facing is how to insert a new row within the table with the form data in it. I searched for it but I couldn't find even a single query regarding the same. The add new contact button is in AddContact component and table is in Contacts component but both have same parent component which is in Main. So in a nutshell I'm not able to display the new contact in the table.
Maintain an array in state variable, when you click on submit in Dialog, push that data in state array. Use the array to generate the rows dynamically, like this:
<Table>
<TableHeader>
<TableRow>
/*Define the headers*/
</TableRow>
</TableHeader>
<TableBody>
{this._generateRows()}
</TableBody>
</Table>
Write the _generateRows function like this to generate the rows:
_generateRows(){
return this.state.data.map(el => {
return <TableRow>
<TableRowColumn>{el.a}</TableRowColumn>
<TableRowColumn>{el.b}</TableRowColumn>
<TableRowColumn>{el.c}</TableRowColumn>
</TableRow>
})
}
Reference : Material-UI table.
Note: Replace el.a, el.b, el.c with the original data.
I see you are using react. This means that when you bind a list of items to the
row components in your render function.
{list.map(item => <RowComponent key={item.id}/>)}
Now when you click the button all you have to do is push to this list and your new row is rendered on screen.

Views and appending table rows in backbone.js

I am trying to create a code using backbone.The user inputs text into two fields Item and price. This info then is appended to a table and creates a new row for every input pair entered.
I've created a template for the table. My question when creating my view since the data from the text fields of item and price need to be sorted into the corresponding cells, how do I append the new rows correctly. Can I just make a view for the row? Or do I need to do it for each cell?
<div id="container">
<script id="grocery-list-template" type="text/template">
<table>
<thead>
<tr>
<th>Item</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<tr>
<td><%=something to get item%></td>
<td><%=something to get the price%></td>
<td></td>
<td><button class="complete"></button><button class="remove"></td>
</tr>
</tbody>
</table>
</script>
</div>
This is essentially what Im trying to do, but I dont know how to specify the row AND the cell? Do I have to make a view for each cell using tagname: td or can I just keep tagname: tr and route the data into the apropriate cells? I found an example that just appended a list using li elements so I was trying to adapt some of it to my code
var TableView = Backbone.View.extend({
tagname: "tr",
classname: "itemAndprice",
template:_.template($("grocery-list-template").html()),
render: function() {
this.$el.html(this.template(this.model.toJSON()));
this.$el.attr("id", this.model.id);
if (this.model.get('done')) this.$el.addClass('done');
$("#GroceryList").append(this.$el);
return this;
},
You can create a view for the whole row. For each row you would need a row-model with item and price attributes which you would pass into the row-view's constructor. This pretty much looks like the TableView in your code (except I would expect that to be called RowView instead, the TableView being a different, 'parent' view)
Given that your model contains item and price attributes, the row-view-template should contain
....
<td><%=item%></td>
<td><%=price%></td>
....
Then this.model.toJSON() would give you a hash with item and price attributes which would be passed into this.template, populating <%=item%> and <%=price%> with the relevant values.
You can also take a look at underscore's template function for further information.
Note however that the row-view and the table-view should be two different views. From your code it seems that you have a template appropriate for a table-view (which also contains a single row that shouldn't be there) and a view appropriate as a row-view.
Having two views you would pass a collection of row-models in the table-view which would iterate over the collection and add a row(-view) for each model. When the user creates a new item you'd add a model into the collection and re-render the table.
Hope this helps.

Delete multiple ng-repeat elements on click of a single button

I have a table showing project names as shown in below image ,
On delete button click, I am passing the selected check-boxes data as array of objects to my controller
[{id:1,name:'Name 8'},{id:2,name:'Name 7'}]
Then deleting the names from the table at the server side. This all works fine but how do i remove the rows from DOM after deleting them?? I went through this post which says how to remove ng-repeat elemets from DOM but in that case the elements are removed one at a time, by passing the $index to the splice() function
In my case i need to remove multiple rows. If ill have to use the splice function in my controller how do i get the index from the selected rows object? Or is there any better way of doing it.
Hope my question is clear!
Update: jsFiddle
Solution: Well i had to modify #wickY26 answer a bit to suite my scenario. Here is my update jsFiddle
What i did was , in the delete() change code to
angular.forEach($scope.projects, function (row, index) {
if($scope.projects[index].checked) {
$scope.projects.splice(index,1);
}
});
You can keep selected rows on an object via binding checkbox with ng-model,
so example table html should be like this
HTML
<table class="table table-bordered">
<tbody>
<tr ng-repeat="row in data" ng-class="{'success' : tableSelection[$index]}">
<td>
<input type="checkbox" ng-model="tableSelection[$index]" />
</td>
<td ng-repeat="cell in row">
{{cell}}
</td>
</tr>
</tbody>
</table>
and if you define a function in your controller which travel through your data and splice array depends on tableSelection object boolean values...
UPDATE
after your comment I debug my code and see I cannot remove multiple rows same time, so I look at my code and change some part of it...
at my example you cannot delete multiple rows same time because everytime you splice an element from data array you shift indexes of array for rest, so right way to do it starting from last index,
Here new CONTROLLER
$scope.removeSelectedRows = function() {
//start from last index because starting from first index cause shifting
//in the array because of array.splice()
for (var i = $scope.data.length - 1; i >= 0; i--) {
if ($scope.tableSelection[i]) {
//delete row from data
$scope.data.splice(i, 1);
//delete rowSelection property
delete $scope.tableSelection[i];
}
}
};
I update my PLUNKER added comments and some other functionallty as well...

Categories