How to display <td> value based on <th> value - html

I have three arrays which I have to display in the table. The three arrays are as follows:
let array1 = [
{id: 'p1', name: 'Adam', age: 27},
{id: 'p2', name: 'Jack', age: 20}
{id: 'p3', name: 'Jane', age: 21}
{id: 'p4', name: 'Rock', age: 23}
];
let array2 = [
{id: 'p3', occupation: 'Teacher', marital_status: 'Married'},
{id: 'p4', career: 'Wrestler', hobby: 'Gymming'}
];
let headers = [
{index: 1, name: 'id'},
{index: 2, name: 'name'},
{index: 3, name: 'age'},
{index: 4, name: 'occupation'},
{index: 5, name: 'marital_status'},
{index: 6, name: 'career'},
{index: 7, name: 'hobby'},
];
Now I want to display it inside the table. Here's what I've tried so far.
<table>
<thead>
<tr>
<th *ngFor="let head of headers">{{head?.name}}</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let person of array1; index as i">
<td>{{ person?.name ? person?.name : '-' }}</td>
<td>{{ person?.id }}</td>
<td>{{ person?.age }}</td>
<ng-container *ngFor="let header of headers">
<td *ngFor="let item of array2">
<ng-container *ngIf="header.name == item[header.name]">{{ item[header.name]}}</ng-container>
</td>
</ng-container>
</tr>
</tbody>
</table>
I want to display the data based on table header's (th) value

I think you're looking for a result like the one in this stackblitz. You needed to connect the ids between your arrays. The solution in this stackblitz is not a good one, however. You shouldn't put methods in your template as they will run an excessive amount due to change detection. I only created it this way to provide an example solution.
What I would recommend is combining array1 and array2 so that all of your elements have the extra fields in one object, instead of referencing two objects that share the same id. This is the simplest and most efficient solution. Alternatively, you could create a pipe that produces the correct result instead of using a method within the template.

create an unique array
//first create an objct with all the elements
const emptyObj=headers.reduce(a:any,b:any)=>({...a,b.name:''))
//then create an object using spread operator
arrayFull=this.array1.map(x=>{
const el=this.array2.find(y=>y.id==x.id)
return {...emptyObj,...x,...el}
})

Related

Passing JSON data to Laravel view without casting in the model

I have this function that fetches data from a table, paginates the data, and passes it to the view:
public function job_requests(){
$orders = DB::table('orders')
->select('id','order_data','order_status')
->paginate(5);
return view('autorepair/mechanics/job_requests',compact('orders'))
->with('i', (request()->input('page', 1) - 1) * 5);
}
The column order_data contains data of the following format:
{
"personal_data": {
"email": "info#info.com",
"telephone_number": "0999",
"postal_address": "LON",
"car_registration": "GB BHG"
},
"inperson_diagnostic": {
"diagnostic_inspection": "67.30",
"car_wont_start_inspection": "67.30",
"plugin_diagnostic_inspection": "67.30"
},
"tyres": {
"front_wheels": 1,
"rear_wheels": 1,
"wheel_width": 45,
"wheel_profile": 1,
"wheel_rim": 1,
"speed_rating": "w",
"final_price": 90
},
"servicing_and_mot": {
"mot_with_collection_delivery": 75,
"major_service": 304.52,
"full_service": 203.45,
"interim_service": "149.70",
"vehicle_health_check": 50
},
"inspection_services": {
"premium_prepurchase_inspection": 146.38,
"standard_prepurchase_inspection": 104,
"basic_prepurchase_inspection": 86.44
},
"repairs": {
"ABS wheel speed sensor replacement": 964,
"ABS pump replacement": 712,
"Brake pedal switch replacement": 568,
"Air conditioning regas (R1234yf Gas ONLY)": 469
}
}
In my view, I have this:
#if(!$orders->isEmpty())
<table class="table table-bordered">
<tr>
<th>No</th>
<th>Order Status</th>
<th>Order Data</th>
<th width="280px">Action</th>
</tr>
#foreach ($orders as $order)
<tr>
<td>{{ ++$i }}</td>
<td>{{ $order->order_status }}</td>
<td>{{ $order->order_data}}</td>
<td>
<a class="btn btn-info" href="{{ url('/view_product/' . $order->id) }}">Show</a>
<a class="btn btn-primary" href="{{ url('/edit_product/' . $order->id ) }}">Accept</a>
</td>
</tr>
#endforeach
</table>
#else
<p>No orders yet.</p>
#endif
{!! $orders->links() !!}
I can display the JSON data here $order->order_data but I would like to have it decoded first. How can I pass a decoded array sent to the view and be able to keep the pagination links?
You could decode it in the view.
Depending on the format of order_data that is actually passed to the view (forgive me, I don't know off-hand how builder or eloquent retrieves jsonb type), but you can use dd() or gettype() in the view, to help identify what data type order_data is when delivered to the view):
If the content comes into the view as a string, try json_decode() on the order_data value. I think you should be able to iterate over the result of that, if that is your intent.

How to iterate over values of Map values

I would like to fill of this cells, this is initiall view of my app:
-> during app works for each rider rider's score will be fulfilled in such a way:
I have a .ts file where I put values of rider score (it's a map -> key is heat number, value - score of particular rider) (if it will be both string or number depends on further configuration)
export const guests = {
1: new Racer(9, 'Name_1', new Map([['1', 1], ['4', 2], ['7', 4]])),
2: new Racer(10, 'Name_2', new Map([['1', 3], ['3', 4]])),
3: new Racer(11, 'Name_3', new Map([['2', 3], ['6', 2]])),
4: new Racer(12, 'Name_4', new Map([['6', 3], ['10', 3], ['13', 2]]))
};
I would like to get all values of map values in html, however I'm not able to iterate over values of this map.
Further info: There should be all the time displayed all cells (it is designed that there should be exactly the same at the beginning
We don't know how entries for each racer there will be (probably for each rider this will be different)
<table>
<tbody>
<tr *ngFor="let racer of team; let index = index">
<td>{{racer.number}}</td>
<td>{{racer.name}}</td>
<td *ngIf="racer.places">{{racer.places.values().next().value}}</td>
<td *ngIf="racer.places">{{racer.places.values().next().value}}</td>
<td *ngIf="racer.places">{racer.places.values().next().value}}</td>
<td *ngIf="racer.places">{racer.places.values().next().value}}</td>
<td *ngIf="racer.places">{racer.places.values().next().value}}</td>
</tr>
</tbody>
</table>
expected output
instead of only first entry there should be all values from Map
working repo:
https://stackblitz.com/edit/angular-iterate-over-map-values
The way you are initializing the map doesn't create a map after all. Make the following change to guests:
// now it actually contains key-value pairs
const guests = {
1: new Racer(9, "Name_1", { "1": 1, "4": 2, "7": 4 }),
2: new Racer(10, "Name_2", { "1": 3, "3": 4 }),
3: new Racer(11, "Name_3", { "2": 3, "6": 2 }),
4: new Racer(12, "Name_4", { "6": 3, "10": 3, "13": 2 }),
};
now create a new property in the team object called remaining, this holds an array which contains the extra number of columns that are needed for each row. It is dynamically created for each racer.
team = Object.values(guests).map(racer => {
return {
...racer,
remaining: new Array(5 - Object.values(racer.places).length)
}
});
and on the template, iterate over this newly created array for the remaining <td> that should be empty:
<table>
<tbody>
<tr *ngFor="let racer of team">
<td>{{racer.number}}</td>
<td>{{racer.name}}</td>
<td *ngFor="let heat of racer.places | keyvalue">
{{ heat.value }}
</td>
<td *ngFor="let rem of racer.remaining" style="width: 10px;">
</td>
</tr>
</tbody>
</table>
This is some awful data structure to work with.
Simply loop through the range that you need and check for each cell if the data exists with .has() method. Show the data in a ternary expression with .get() method if it exists, or null if it's missing.
Here is the HTML code that should work with your data structure:
<table>
<thead>
<tr>
<td>No.</td>
<td>Racer</td>
<td *ngFor="let p of [1,2,3,4,5]">{{p}}</td>
<td>Sum</td>
<td *ngFor="let p of [6,7]">{{p}}</td>
<td>Sum</td>
</tr>
</thead>
<tbody>
<tr *ngFor="let racer of team; let index = index">
<td>{{racer.number}}</td>
<td>{{racer.name}}</td>
<td *ngFor="let p of [1,2,3,4,5]">{{racer.places.has(""+p) ? racer.places.get(""+p) : null}}</td>
<td>TODO: Sum</td>
<td *ngFor="let p of [6,7]">{{racer.places.has(""+p) ? racer.places.get(""+p) : null}}</td>
<td>TODO: Sum</td>
</tr>
</tbody>
</table>
Unless you are planning to expand the Racer class, I suggest you switch it to an interface and simply use JSON data structure with Objects instead of a Map

Expand only one row in the table

I have a table with rows, where I list the data from json file.
In one row I'm slicing the data to show only 100 symbols.
I want to display full text when user click on the row. I managed to do it, but It opens all rows. How to do it only for the one row, which clicked?
<tr *ngFor="let lfiexport of lfilist | filter:searchText">
<td (click)="fullViewFlag= !fullViewFlag" class="text-left">
<span *ngIf="fullViewFlag">{{lfiexport.desc}}</span>
<span *ngIf="!fullViewFlag">{{lfiexport.desc | slice:0:100}}</span>
</td>
</tr>
You are using same fullViewFlag multiple times, so it will effect all the rows. So, I suggest you maintain different fullViewFlag properties for each object and can try the below code
Working stackblitz
TS file
export class AppComponent {
name = 'Angular ' + VERSION.major;
lfilist = [{
desc: [1, 2, 3, 4, 5, 6]
}, {
desc: [7, 8, 9, 10, 11, 12]
}, {
desc: [13, 14, 15, 16, 17, 18]
}].map(item => {
return {
...item,
fullViewFlag: false
}
});
}
Template file
<tr *ngFor="let lfiexport of lfilist">
<td (click)="lfiexport.fullViewFlag = !lfiexport.fullViewFlag" class="text-left">
<span>{{lfiexport.fullViewFlag ? lfiexport.desc : lfiexport.desc | slice:0:2}}</span>
</td>
</tr>
No need of *ngIf we can use terinary operator ?:

ngStyle table based on arrays value

I want to obtain a table like this:
I have 2 objects
users = [
{ name: 'john', age: '22' },
{ name: 'mike', age: '20' },
{ name: 'dan', age: '12' },
{ name: 'anne', age: '16' },
{ name: 'jenny', age: '42' },
]
names = [
{ name: 'john', color: 'black' },
{ name: 'mike', color: 'black' },
{ name: 'dan', color: 'red' },
{ name: 'anne', color: 'red' },
{ name: 'jenny', color: 'red' },
]
If a name from names is in users, I want it's color to be black inside table, if not, I want it to be red.
This is my html:
<table>
<thead>
<tr>
<th>Name</th>
<th>Age</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let user of users">
<ng-container *ngFor="let x of names">
<ng-container *ngIf="x.name == user.name">
<td [ngStyle]="{ 'color': names.color }">{{ user.name }}</td>
<td [ngStyle]="{ 'color': names.color }">{{ user.age }}</td>
</ng-container>
</ng-container>
</tr>
</tbody>
</table>
But it's not working properly. You can see a working snippet here
How can I achieve what I want? Thank you for your time!
You can either create a method that retrieves the color based on name (that you put in your component)
getColor(name) {
return this.names.find(e => e.name === name).color;
}
and call with
<td [style.color]="getColor(user.name)">{{ user.name }}</td>
<td [style.color]="getColor(user.name)">{{ user.age }}</td>
You don't need your double loop when using it like that, but it still needs to do a lookup loop for every iteration.
Better is to combine the two arrays before and use that
combined = [];
constructor() {
this.combined = this.users.map(e => Object.assign(e, this.names.find(x => x.name === e.name)))
}
usage
<tr *ngFor="let user of combined">
<td [style.color]="user.color">{{ user.name }}</td>
<td [style.color]="user.color">{{ user.age }}</td>
</tr>
You have a typo when referencing color. color is a property of the object, not the array you are looping through:
<td [ngStyle]="{ 'color': names.color }">{{ user.name }}</td>
<td [ngStyle]="{ 'color': names.color }">{{ user.age }}</td>
Should be
<td [ngStyle]="{ 'color': x.color }">{{ user.name }}</td>
<td [ngStyle]="{ 'color': x.color }">{{ user.age }}</td>

Getting data from an array in an array with ReactJS

I'm very new to ReactJS but I think I'm making some headway ...
I think I'm almost there but I've fallen down at what I think is near enough my final hurdle ... here's what I'm trying to achieve;
TV Show - Simpsons
Name: Bart Simpson, Gender: Male
Name: Homer Simpson, Gender: Male
Name: Ned Flanders, Gender: Male
TV Show - Flintstones
Name: Fred Flintstone, Gender: Male
Name: Barney Rubble, Gender: Male
Name: Wilma Flintstone, Gender: Female
I could have hundreds of these so I don't want to just build these in two React elements - so I've organised my data as such which I'm happy with;
var shows = [
{
id: 1,
show: 'Simpsons',
characters: [
{ id: 1, name: 'Bart Simpson', gender: 'Male'},
{ id: 2, name: 'Homer Simpson', gender: 'Male'},
{ id: 3, name: 'Ned Flanders', gender: 'Male'}
]
},
{
id: 2,
show: 'Flintstones',
characters: [
{ id: 1, name: 'Fred Flintstone', gender: 'Male'},
{ id: 2, name: 'Barney Rubble', gender: 'Male'},
{ id: 3, name: 'Wilma Flintstone', gender: 'Female'}
]
}
];
And then I'm building my data with a table as such:
const ShowsTable = (props) => {
return (
<div>
<h1>Show - {props.show}</h1>
<table>
<tr>
<th>Name</th>
<th>Gender</th>
</tr>
<tr>
<td>XXX</td>
<td>YYY</td>
</tr>
</table>
</div>
);
};
I've got this 'working' where I can get the shows name and anything from the main array but I can't get the data from the nested 'characters' child array
So XXX and YYY is where I would like to get the data for the names or gender, in my mind I should be able to do something like ...
{props.characters}
Or maybe getting the nested elements so something like
{props.characters.props.name}
But I can't figure this out or find any documentation for this - so is this a syntax error or am I missing something more fundamental ... maybe I'm asking the wrong question? I'm really not sure
If someone can point me in the right direction with an explanation or some documentation I'd be very grateful :-)
You can do something like:
const ShowsTable = (props) => {
return (
<div>
<h1>Show - {props.show}</h1>
<table>
<tr>
<th>Name</th>
<th>Gender</th>
</tr>
{props.characters.map((char, index) => (
<tr key={index}>
<td>{char.name}</td>
<td>{char.gender}</td>
</tr>
))}
</table>
</div>
);
};