How to iterate over values of Map values - html

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

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 can I get details for each item from an array of objects?

I have an array of objects from which I take a name to create a list. When I click on one element of the list, a modal window should open to me in which detailed information about this element will be shown (you need to display a certain object), you can suggest how this can be implemented in Angular ?
You might want to try with a custom div modal, if you are using none of the ui kits or frameworks.
If you are using kits like material, you can use the material modal to display on clicking that item. To know which data to be passed, you can pass the id of the row data on clicking and then populate the required data from the array using filter().
for example, if you are using angular you are going to use *ngFor for array of objects
array of objects
eg:
ArrayObjects= [
{
"id": 1,
"place": "Sweden"
}, {
"id": 2,
"place": "USA"
}, {
"id": 3,
"place": "England"
}
]
if you are going to use to show data in table
<table>
<tr>
<th> Sl.No </th>
<th> Place </th>
<th> Popup Action </th>
</tr>
<tr *ngFor="let group of ArrayObjects; index as i">
<td> {{i+1}} </td>
<td> {{group.place}} </td>
<td (click)="ClickMeToGetParticularData(group, i)" > </td>
</tr>
</table>
In .ts part
ClickMeToGetParticularData(data, index){
console.log("Required data", data) ////////// use this to get data to show in popup
console.log("Required index", index) ///// if you want index
}

How to iterate a JSON array in typescript in HTML?

I have a snippets of JSON array as shown below:
[{
"auction_number": "015",
"email": "pete#abc.com",
"first_name": "Peter",
"last_name": "Dan",
"table": 0,
"id": "015"
},
{
"auction_number": "024",
"email": "dan#gog.com",
"first_name": "Dan",
"last_name": "Fain",
"table": 0,
"id": "024"
}
]
Typescript Code:
The typescript (ts) for the above JSON array is shown below. Here attendees is an array object.
attendees: Attendee[];
constructor(public authService: AuthService) {
const str = localStorage.getItem("attendees");
if(str) {
this.attendees = JSON.parse(str);
console.log(str);
}
}
HTML Code:
The HTML code which I have used in order to iterate everything from the JSON array (in the typescript code) is shown below. For some reasons, it is not able to iterate attendees in the HTML.
<tr *ngFor="let row of attendees">
<td class="left">{{ attendees.first_name }} {{ attendees.last_name }}</td>
<td class="number1">250</td>
<td class="table1">{{attendees.table}}</td>
<td class="right-bill">Bill</td>
</tr>
Problem Statement:
I am wondering what changes I should make in the HTML code above so that I am successfully able to iterate attendees array. I tried using ngfor directive but somehow it didn't work.
You should reference fields in each row as row.first_name because you set each attendee as let row of attendees. The variable you defined is row.
You are accessing the parent loop again, you should access only the elements of row
<tr *ngFor="let row of attendees">
<td class="left">{{ row .first_name }} {{ row .last_name }}</td>
<td class="number1">250</td>
<td class="table1">{{attendees.table}}</td>
<td class="right-bill">Bill</td>
</tr>

Vue v-bind - access array object from another array loop

I'm working on a project where I created a table component which is used on multiple pages with different configuration. Every table has it's configuration in a separate file where I store keys, titles and size classes for each column.
Data for each table body come from REST calls and they are loaded dynamically, paginated and then displayed.
<template slot="thead">
<tr>
<th v-for="item in headers" :key="item.id" :class="item.classes">{{item.title}}</th>
</tr>
</template>
<template slot="tbody">
<tr v-for="skill in paginatedSkills"
:key="skill.id"
v-on:click="selectRow(skill)"
v-bind:class="{selectedRow: selectedSkill === skill}"
>
<td class="cell-l">{{skill.name}}</td>
<td class="cell-m">{{skill.owner}}</td>
<td class="cell-s">{{skill.complexity}}</td>
<td class="cell-full">{{skill.description}}</td>
</tr>
</template>
What I want to do is to avoid writing size class for every single cell in the tbody loop. I was hoping to get index of looped object and use it to retrieve the class from config object which is used to populate cells in thead.
<tr v-for="(skill, index) in paginatedSkills" ...>
<td class="{headers[index].classes}">{{skill.name}}</td>
Using index on headers will return the correct item but as a string so obviously classes are not accessible. Any idea how to tweak it?
This options are no go, failing on compile
<td :class="{JSON.parse(headers[index]).classes}">{{skill.name}}</td>
<td :class="{JSON.parse(headers)[index].classes}">{{skill.name}}</td>
<td :class="{{JSON.parse(headers[index]).classes}}">{{skill.name}}</td>
To set class from a variable/property you have two options:
<td v-bind:class="headers[index].classes">{{skill.name}}</td>
<td :class="headers[index].classes">{{skill.name}}</td>
No need for curly braces here since v-bind already expects JS expression.
Update:
What you can also do, is to associate keys of skill object (name, owner, complexity, description) with their header, so each item of headers array will also have for example key property used to access value from skill object:
headers: [
{ id: 1, classes: 'cell-l', title: 'title', key: 'name' },
{ id: 2, classes: 'cell-s', title: 'title', key: 'owner' },
...
]
Thus, your code can be simplified the following way:
<tr v-for="skill in paginatedSkills" ...>
<td v-for="header in headers" v-bind:class="header.classes">{{skill[header.key]}}</td>
</tr>

Organize an HTML table by item ID

I have an HTML table that pulls in data that is stored locally. It searches through the model in the foreach loop and then displays the information in two columns (Patient Name & SiteID). Is there a way that I can display the information so that it is organized by SiteID?
<table id="patient_table">
<tr>
<th>Patient Name</th>
<th>Site ID</th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>#string.Format("{0} {1}", item.FirstName, item.LastName)</td>
<td class="TableAlign">#Html.ActionLink(string.Format("{0}", item.SiteId), "Details", "Site", new { id = item.SiteId }, null)</td>
</tr>
}
</table>
Your question has knockout.js tagged. However, your example code is using ASP.NET and Razor to iterate through your Model.
Based on what you have presented, if your Model is IEnumerable I would alter your #foreach like so, which should order the displayed information by SiteId:
#foreach (var item in Model.OrderBy(x => x.SiteId))
You can try that :)
this.allItems(this.allItems().sort(function(a, b) { return a.SiteId > b.SiteId ;}));