How to sort HTML Table in ReactJS - html

I have array of Objects and I add my data to HTML Table. Now I need to sort my data by version. How can I do something like that in React?
render() {
return (
<div>
<div>
<Label> We got {this.state.count} elements in our database. </Label>
</div>
<div>
<Table hover striped bordered responsive size="sm" >
<thead>
<tr>
<th>VERSION</th>
<th>DATE</th>
<th>UUID</th>
</tr>
</thead>
<tbody>
{this.state.results.map(result =>
<tr key={result.fileId}>
<td>{result.VERSION}</td>
<td>{result.ORIGIN}</td>
<td>{result.UUID}</td>
</tr>
)}
</tbody>
</Table>
</div>
</div>
);
}
}
Maybe I can use some js script, but tell me how to use it, I'm new with ReactJS. My version for is 0.26.8 for example.

I would use lodash's sortBy() function here:
https://lodash.com/docs/4.17.4#sortBy
const sorted = _.sortBy(this.state.results, 'VERSION')
Then map over sorted instead of the this.state.results

Simply make sure this.state.results is sorted correctly before rendering.
The simplest approach would likely be similar to the following:
{this.state.results.sort((a, b) => a.VERSION - b.VERSION).map(result =>
<tr key={result.fileId}>
<td>{result.VERSION}</td>
<td>{result.ORIGIN}</td>
<td>{result.UUID}</td>
</tr>
)}
Edit: Since you stated that the version is not a numeric value, but rather a semantic versioning string, your sort function needs to be a bit more complex. I suggest you have a look at this SO question, or use one of the many available libraries covering that use case.

const sorted = results.sort((x,y) => {
return parseInt(x.VERSION) - parseInt(y.VERSION);
});
sorts in Ascending order

Related

How to use CSS grid with a dynamic number of columns and rows?

I'm trying to create a table in Angular with a dynamic number of columns and rows. I've found this easy to accomplish using the HTML table element by doing something like this:
<table class="html-table">
<tr class="headers">
<th>Name</th>
<th>Age</th>
<th>Sex</th>
<th *ngIf="columns == 4">Species</th>
</tr>
<tr>
<td>Ryan</td>
<td>30</td>
<td>M</td>
<td *ngIf="columns == 4">Human</td>
</tr>
</table>
In this example there might be some button that toggles the value of columns between 3 and 4.
Every explanation I have looked at online involves changing CSS variables, which seems like a somewhat hacky way to accomplish something that should be simple. Is there some way I can specify that something should be a new column in CSS grid rather than that having to specify the number of columns in grid-template-columns?
In Angular you can use ng-repeat to have a dynamic table
A typical example could be
<table ng-table="tableParams" class="table table-striped">
<tr ng-repeat="data in datas">
<td title="Title_Of_First_Variable">{{data.variable1}}</td>
<td title="Title_Of_Second_Variable">{{data.variable2}}</td>
<td title="Title_Of_Third_Variable">{{data.variable3}}</td>
...
</tr>
</table>
Of course with your controller you should pass your dynamic data into the correct $scope, in this case should be $scope.datas (usually an object)...maybe something like this, using NodeJS:
$http.post('route_of_your_method')
.success(function (result) {
$scope.datas = result;
})
.error(function (err) {
...
});
I explained fastly but i hope this is enough

Angular checkbox gets updated even though ngModel doesn't

I'm working on a shift arrangement app. In it I'm trying to create two tables that show which possible shifts each user has selected.
Both tables display the same data, but arrange it differently. Each table cell has a number of check-boxes that display the possible shifts for each person (in table 1) or the possible people for a shift (in table 2). A checkbox from table 1 that displays shift A option for person X will have the same data-bind as its equivalent checkbox in table 2, which displays person X option for shift A.
The purpose of this is to update the equivalent data in both tables simultaneously when the user couples a person with a shift. The problem: when a checkbox in table 1 is checked/unchecked, all of the check-boxes in table 2 gets checked/unchecked, as shown below:
Here is my template:
<div class="table-container" dir="ltr">
<h3>People</h3>
<table>
<thead>
<th>Name</th>
<th>Options</th>
</thead>
<tbody>
<tr *ngFor="let user of userPreferences">
<td>{{user.name}}</td>
<td>
<div *ngFor="let selection of userYesses[user.name]">
<mat-checkbox class="option-checkbox" dir="ltr" [(ngModel)]="selection.isSelected" name="usc">{{selection.option}}</mat-checkbox>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<div class="table-container" dir="ltr">
<h3>Shifts</h3>
<table>
<thead>
<th>Time</th>
<th>Options</th>
</thead>
<tbody>
<tr *ngFor="let shift of totalShifts">
<td dir="ltr">{{shift.time}}</td>
<td>
<div *ngFor="let selection of shiftYesses[shift.time]">
<mat-checkbox class="option-checkbox" [(ngModel)]="selection.isSelected" name="syc">{{selection.name}}</mat-checkbox>
</div>
</td>
</tr>
</tbody>
</table>
</div>
And here is relevant component code:
this.userPreferences.forEach(u => {
this.userYesses[u.name] = [];
u.preferences.shifts.forEach(week => {
week.forEach(day => {
if (!day.shifts) return;
day.shifts.forEach(shift => {
if (!this.shiftYesses[`${day.date} ${shift.time}`]) this.shiftYesses[`${day.date} ${shift.time}`] = [];
if (shift.isSelected) {
let selection = new Selection(`${day.date} ${shift.time}`, u.name);
this.userYesses[u.name].push(selection);
this.shiftYesses[`${day.date} ${shift.time}`].push(selection);
}
});
});
});
});
The code seems alright to me, am I missing anything? Maybe it's a bug in Angular?
Thanks in advance!
In case anyone else experiences this issue -
After a few days of struggling with this, I stumbled upon this issue from Angular's git - https://github.com/angular/angular/issues/9230
I've read the following in kara's answer:
In the case that you don't want to register a form control, you currently have a few options:
1 - Use ngModel outside the context of a form tag. This will never throw.
<input [(ngModel)]="person.food">
After reading this, I switched the <form> tag into a <div> and everything works as expected now.

How to add the background-color for data in table using bootstrap-classes and angularjs?

I want to do a small E-commerce application. After done the order by the user, admin got orders and order item consist of order id, itemname, price, status, btnclass.
Default status of the order is pending and value of btnclass is label-warning, After editing the order pending to delivered the value of the btnclass change to the label-success. but i don't know how to do this
btnclass is for storing the bootstrap class.
<table>
<th>order id</th>
<th>item name</th>
<th>price</th>
<th>status</th>
<th>total</th>
<tr ng-repeat="item in orders">
<td>{{item.orderid}}</td>
<td>{{item.itemname}}</td>
<td>{{item.price}}</td>
<td><p class="label {{list.btnclass}}">{{item.status}}</p></td>
<td>{{item.total}}</td>
</tr>
</table>
My array is like this:
[
{
"orderid":1,
"itemname":"rice",
"price":10,
"status":"pending",
"btnclass":"label-warning",
"total":10
},
{
"orderid":2,
"itemname":oils,
"price":50,
"status":"deliverd",
"btnclass":"label-success",
"total":50
}
Please help me how to provide classes for the table data..
ng-class is useful for that. You can create 2 CSS classes for the status, for example .delivered or .pending. And use ng-class directive as such :
<td><p ng-class="{'deliverd' : item.status === 'delivered', 'pending' === 'item.status === 'pending'}">{{item.status}}</p></td>
It's actually very easy, you have to use ng-class.
With ng-class you can pass a group of classes and conditions that determine if the classes should be applied or not, the syntaxis is this
<any ng-class="{'my-class':condition===true, 'my-second-class': someFunction()}" />
notice that the parameter passed to ng-class is a js object, where the keys are the name of the classes to apply, and the values are the conditions, if a condition resolves to true then the class used as key will be applied, otherwise it will be ignored. As you can see you can either use expressions like in the first case (condition===true) or you can call functions like I did in the second example (someFunction()) try to use this to solve your problem, and, if you can't feel free to ask for further assistance.

How to filter the object values when an input is given?

HTML
<input type="search" placeholder="Filter" ng-model="searchstr" ng-change="details()">
<table style="width:831px;overflow:auto">
<tr ng-repeat="d in details" ng-if="$index%3==0">
<td style="height:232px;width:164px;" ng-if="details[$index]">{{details[$index].CourseName}}<br>{{details[$index].Professor}}<br>{{details[$index].CourseDuration}}</td>
<td style="height:232px;width:164px;" ng-if="details[$index+1]">{{details[$index+1].CourseName}}<br>{{details[$index+1].Professor}}<br>{{details[$index+1].CourseDuration}}</td>
<td style="height:232px;width:164px;" ng-if="details[$index+2]">{{details[$index+2].CourseName}}<br>{{details[$index+2].Professor}}<br>{{details[$index+2].CourseDuration}}</td>
</tr>
</table>
js file
$scope.data=function()
{
$scope.details=$filter("filter")($scope.details,$scope.searchstr);
}
I have tried like above but only for the first time its displaying
I got it.I just changed the slight logic in js file.I am posting it as it may be helpful to somebody else.
First i just copied the $scope.details to d and filtered with the temp variable d.
$scope.searchstr="";
var d=$scope.details;
$scope.data=function()
{
$scope.details=$filter("filter")(d,$scope.searchstr);
}
You don't need the $scope.data function. You use the builtin angular filter like
<tr ng-repeat="d in details | filter:searchstr" ng-if="$index%3==0">

Inserting HTML code when passing values to templates for given conditions

I have a table I am creating that looks like this:
<table>
<thead>
<tr>
<th>Value1</th>
<th>Value2</th>
<th>Value3</th>
<th>Value4</th>
</tr>
</thead>
<tbody>
{{#each []}}
<tr>
<td>{{this.val1}}</td>
<td>{{this.val2}}</td>
<td>{{this.val3}}</td>
<td>{{this.val4}}</td>
</tr>
{{/each}}
</tbody>
I want it to be the case that if val1, for instance, is greater than some value X, it will appear red.
How can I pass HTML into the template once some pre-defined condition - like the above example - is satisfied?
Ideally you should be driving this functionality using your models.
You could achieve the desired functionality using Marionette CollectionView. Each model in the collection should look something like:
var Model = Backbone.Model.extend({
initialize: function(){
/* On initialize, we call our method to set additional computed properties */
this.setProperty();
}
setProperty: function() {
if (this.get("someProperty") > x) {
this.set("className", "css-class")
}
}
});
Then from within your ItemView template you should be able to set the class on your table row item
<tr class="{{this.className}}">
<td>{{this.val1}}</td>
<td>{{this.val2}}</td>
<td>{{this.val3}}</td>
<td>{{this.val4}}</td>
</tr>