How to specify keys in React Bootstrap table - reactjs

Using React Bootstrap table, I'm getting the warning Warning: Each child in a list should have a unique "key" prop. I've read about how this is necessary for lists, but not sure where I'm supposed to set a key for a Table? My table looks something like this
<Table size="sm" responsive="sm" bordered hover striped>
<thead>
<tr>
<th>Col1</th>
<th>Col2</th>
<th>Col3</th>
<th>Col4</th>
</tr>
</thead>
<tbody>
{ histories.map((h) => (
<tr>
<th>{ h.col1} </th>
<th> { h.col2}</th>
<th> { h.col3}</th>
<th>{ h.col4}</th>
</tr>
)) }
</tbody>
</Table>

This would work is there's an id for histories.
{ histories.map((h) => (
<tr key={h.id}>
<th>{ h.col1} </th>
<th> { h.col2}</th>
<th> { h.col3}</th>
<th>{ h.col4}</th>
</tr>
)) }
The key can really be anything (even h.col1 if you like), as long as it's unique within that list. It's not super important to have (hence the warning instead of error), but it's definitely is good practice when you're iterating over some data and rendering a list from it, in order to prevent some unpredictable behavior, and to help React do its thing properly.

Related

How to find children elements in Jest?

I have a table like this:
<table data-test='container-component-table'>
<tr data-test='container-component-table-column-names'>
<th>Firstname</th>
<th>Lastname</th>
<th>Age</th>
</tr>
</table>
I have tried to get the children of container-component-table-column-names by writing
expect(wrapper.find('container-component-table-column-names').children().length).toBe(3)
but it not working. It found zero children elements. Anyone know why?

display data angular 4 (converting obj to array)

I'm trying to display an object of an object in an array, I've been hitting my head against the wall since I cant change the backend.
this is what I got so far, M01, M02, M03... might refer to months since we are November there are 11 however if it was February id be only M01 and M02. since I got a property of an object I cant loop it on a second for and I'm having a lot of trouble with it
this is my view
<div *ngIf="estados" class="table-responsive col-lg-12 tablilla">
<table class="table table-bordered table-striped table-responsive">
<thead>
<tr>
<th></th>
<th *ngFor="let month of listaMonthsNames">{{month}}</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let estado of estados">
<td>{{estado.nom_item}}</td>
<td *ngFor="let month of estado.M[0]">{{month}}</td>
</tr>
</tbody>
</table>
</div>
I think this will help you :
There is no direct way to access Object from the Template side so,
All you need to do is provide Object.keys access to the Template side by this way from Component :
// Component Side :
objectKeys = Object.keys;
// Template Side :
<td *ngFor="let key of objectKeys(estado.M)">
Key: {{key}}, value: {{estado.M[key]}}
</td>
You can read more about the Object.keys HERE

ng repeat dynamic with key objet json AngularJS

I have a small problem I would like to set up a ng-repeat dynamic with the values I receive from my JSON object,
First, i made my th from my table with the keys
Secondly, i would like to do my td in dynamic (without putting the name of the key ex: obj.NOM, obj.TYPE ...)
I managed to do something with an Object.keys but logic is not good so I need some help
this is my JSON object ( i show you just the little piece of code that I have a problem )
"HEADER":[
{"NOM":"API-APP","TYPE":"string","DESCRIPTION":"Code application"},
{"NOM":"API-SIGNATURE","TYPE":"string","DESCRIPTION":"Signature de la requete API"},
{"NOM":"API-TIMESTAMP","TYPE":"integer","DESCRIPTION":"Timestamp en microseconde"}]
and this is my ng repeat
<span><b>HEADER</b></span>
<br>
<br>
<table class="table">
<th ng-repeat ="(key, itemHeader) in itemHead.HEADER[0] track by $index">{{key}}</th>
<tr ng-repeat ="(key, itemHeader) in itemHead.HEADER track by $index" >
<td>{{getFirstPropertyValue(itemHeader,$index)}}</td>
</tr>
</table>
I explain i made first a ng-repeat for th with the keys and I would like put my data (3 data per row) in td without put ( .NOM .TYPE .DESCRIPTION)
So I took the function object.key which works very well but that makes me just one element per row but I need 3 elements per row
this is my scope for the function object.key
$scope.getFirstPropertyValue = function(obj,index){
return obj[Object.keys(obj)[index]];
}
and this my result
thanks in advance for your help
<table class="table">
<thead>
<tr>
<th ng-repeat="(key, itemHeader) in itemHead.HEADER[0]">
{{key}}
</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="row in itemHead.HEADER">
<td ng-repeat="column in row">
{{column}}
</td>
</tr>
</tbody>
</table>

change class name on click and remove class on other click - Angular 4

Can some one help me to resolve this. I have table with different columns (TD). I want to select one cell and change its classname. when i click on other cell, i want to restore the classname in previously cell and change the classname on newly selected cell..
Please note: each cell have different classname. So i have to keep track of pervious class and selected element.
This is Angular 4 application.
my table:
<table class="table package-table stats">
<tbody>
<tr *ngIf="deptStatsModel.length>0">
<th (click)="setStatsActByDept($event,dt2,null)" class="st-th">ORG</th>
<th (click)="setStatsActByDept($event,dt2,'OD')" class="OverDue">Over Due</th>
<th (click)="setStatsActByDept($event,dt2,'NA')" class="NeedAttention">Need Att</th>
<th (click)="setStatsActByDept($event,dt2,'IA')" class="InProgress">In Prog</th>
<th (click)="setStatsActByDept($event,dt2,'CP')" class="Comp">Complete</th>
</tr>
<tr *ngFor="let model of deptStatsModel">
<td (click)="setActivitiesData($event,model, 'all','DPT')">{{model.deptName}}</td>
<td (click)="setActivitiesData($event,model, 'OD','DPT')">{{model.overDue}}</td>
<td (click)="setActivitiesData($event,model, 'NA','DPT')">{{model.needAtt}}</td>
<td (click)="setActivitiesData($event,model, 'IP','DPT')">{{model.inProg}}</td>
<td (click)="setActivitiesData($event,model, 'CP','DPT')">{{model.complete}}</td>
</tr>
<tr *ngIf="deptStatsModel.length==0">
<td style="text-align: left" colspan="5">No records found</td>
</tr>
</tbody>
</table>
I have on click as below:
setStatsActByDept(event,dt,type)
{
var target = event.target || event.srcElement ||
event.currentTarget;
this.prevDeptCss=target.cloneNode();
target.className="selected";
.........
}
I dont know what to do next..help please.
You're thinking about it in the wrong way. The code shouldn't modify the DOM. It should modify the state of the component. The template is the one responsible to apply CSS classes to DOM elements based on the state of the component.
Assuming, as your code seems to imply, that you want to select the header cells. Your code should simply look like the following.
In your component:
public selectedHeader: string;
In your view:
<th (click)="selectedHeader = 'ORG'" [ngClass]="selectedHeader === 'ORG' ? 'selected' : 'st-th'">ORG</th>
<th (click)="selectedHeader = 'OverDue'" [ngClass]="selectedHeader === 'OverDue' ? 'selected' : 'OverDue'">Over Due</th>
...

ng-init miscalculates aliased index after array.splice

I have encountered a strange behavior related to ng-init, any help would be appreciated.
I have a model object which has a flats property that is an array of flat objects. Each flat object has rooms property which is an array of room objects.
I'm trying to display flat and rooms as follows;
<table ng-repeat="flat in model.flats" ng-init="flatIndex = $index">
<thead>
<tr>
<td>{{flatIndex+1}}. {{flat.name}}</td>
</tr>
</thead>
<tbody>
<tr ng-repeat="room in flat.rooms" ng-init="roomIndex = $index">
<td>{{roomIndex+1}}. {{room.name}}</td>
</tr>
</tbody>
</table>
If i delete a flat or room by using array.splice flatIndex and roomIndex variables doesn't seem to update properly even though $index and ui updates properly.
You can see the problem here in action.
Try to delete 1st, 2nd or 3rd flat or room object by clicking the delete link. Deleting last object from the array doesn't really expose the problem.
Any workarounds would also be appreciated.
This is a known behavior when you use ng-init, the scope property values set by ng-init are not watched and they don't update when you remove items from array to reflect the refreshed index position. So don't use ng-init, instead just use $index (deleteFlat($index)) and flat object reference (to get hold of rooms deleteRoom(flat,$index)).
<table ng-repeat="flat in model.flats track by flat.id">
<thead>
<tr>
<td colspan="2">{{$index+1}}. {{flat.name}}</td>
<td>DELETE FLAT</td>
</tr>
</thead>
<tbody>
<tr ng-repeat="room in flat.rooms track by room.id">
<td> </td>
<td>{{$index+1}}. {{room.name}}</td>
<td>DELETE ROOM</td>
</tr>
</tbody>
</table>
and
$scope.deleteFlat = function(flatIndex){
$scope.model.flats.splice(flatIndex,1);
};
$scope.deleteRoom = function(flat,roomIndex){
flat.rooms.splice(roomIndex,1);
};
Plnkr
Or better off use the ids itself, deleteFlat(flat.id) and deleteRoom(room.id, flat).
<table ng-repeat="flat in model.flats track by flat.id">
<thead>
<tr>
<td colspan="2">{{$index + 1}}. {{flat.name}}</td>
<td>DELETE FLAT</td>
</tr>
</thead>
<tbody>
<tr ng-repeat="room in flat.rooms track by room.id">
<td> </td>
<td>{{$index+1}}. {{room.name}}</td>
<td>DELETE ROOM</td>
</tr>
</tbody>
</table>
and
$scope.deleteFlat = function(flatId){
$scope.model.flats.splice(_getItemIndex(flatId, $scope.model.flats), 1);
};
$scope.deleteRoom = function(roomId, flat){
flat.rooms.splice(_getItemIndex(roomId, flat.rooms), 1);
};
function _getItemIndex(imtId, itms){
var id ;
itms.some(function(itm, idx){
return (itm.id === imtId) && (id = idx)
});
return id;
}
Plnkr2

Resources