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.
Related
I would like to create a table and populate it with data using vue.js and v-for but I don`t know how to access the nested JSON file.
If I simply call {{items}} the data is presented but there is no way i manage to filter it
here is my code:
<template>
<div id="app">
<thead>
</thead>
<tbody>
<table>
<thead>
<tr>
<th>id</th>
<th>press</th>
<th>date</th>
</tr>
</thead>
<tbody>
<tr v-for="item in items" :key="item.id">
<td>{{ item.id }}</td>
<td>{{ item.results.downloadable.document_en }}</td>
<td>{{ item.}}</td>
</tr>
</tbody>
</table>
</tbody>
</div>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
items:[]
}
},
created() {
axios.get(`https://zbeta2.mykuwaitnet.net/backend/en/api/v2/media-center/press-release/?page_size=61&type=5`)
.then(response => {
this.items = response.data
})
}
}
</script>
Based on the result of your endpoint you should change your assignment of items to
.then(response => {
this.items = response.data.results
})
And your loop to
<tr v-for="item in items" :key="item.id">
<td>{{ item.id }}</td>
<!-- as downloadable is an array, see update below etc. -->
</tr>
But be aware - if you assign the data.results directly you will lose the so called "paginator" information that also contains the link to load more.
So another option would be to assign
this.items = response.data
HOWEVER, be aware that you should then define items in your data as null or empty object (not array, as this would be false)
And then change your loop to something like this (it's now looping in item.results)
<tbody v-if="items && items.results">
<tr v-for="item in items.results" :key="item.id">
<td>{{ item.id }}</td>
<!-- as downloadable is an array - see Update below etc. -->
</tr>
</tbody>
This approach would allow you to show the total count via items.count for example
UPDATE:
Actually downloadable is an array! I can only assume what you actually want to achieve to here. I've created a jsfiddle to showcase it: https://jsfiddle.net/v73xe4m5/1/
The main thing you probably want to do is filter the entry to only show entries where downloadable contains a document_en.
<tr v-for="item in items.results" :key="item.id">
<td>{{ item.id }}</td>
<td>
<div class="downloads">
<span
v-for="downloadable in item.downloadable.filter(d => !!d.document_en)"
:key="downloadable.id"
>{{ downloadable.document_en.file }}</span>
</div>
</td>
</tr>
I'm not familiar with that endpoint / api - so I don't know if it might return more than one relevant document per item.
As you can see I used a second v-for loop inside the <td> in order to go through all downloadable entries. Before doing so, they are filtered, so only entries that actually have a document_en value are shown. You can adapt this as you want.
Hope that helps!
this is the correct form to get the array from the json and save to this.items
this.items = response.data.results
I encourage you to always console.log(response) after api call , and access data according to the structure of the api results
I have a problem with laravel and vue about displaying the result from database table find method. What I don't quite understand is why the v-for directive parsing the json result incorrectly.
Here is the Vue code :
<template>
<table class="table table-hover">
<thead>
<tr>
<th>Class</th>
<th>Amount of Students</th>
<th>Teacher</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr v-for="classroom in classrooms" :key="classroom.id">
<td>{{ classroom.class_no }}•{{ classroom.field }}•{{ classroom.room_no }}</td>
<td>{{ classroom.amount_students }}</td>
<td>{{ classroom.teacher }}</td>
<td>
<a href="#">
<i class="fa fa-edit blue"></i>
</a>
</td>
</tr>
</tbody>
</table>
</template>
<script>
export default {
data () {
return {
classrooms : {
"success": true,
"data": { "id": 1, "class_no": 1, "field": "Architecture", "room_no": 4, "amount_students": 40, "teacher": "Bobby Fisher" },
"message": "Find Classroom Detail"
}
}
}
}
</script>
The json classrooms itself is actually the result from the controller :
public function show($level)
{
$classrooms = ClassRoom::where('class_no', $level)->firstOrFail();
return $this->sendResponse($classrooms , 'Find Classroom Detail');
}
And here is screenshot of the wrong result :
The result should be only a single row
Please help me to solve this problem.
Actually, as you are iterating over the classrooms which is an object having three keys, so the for loop is iterating over each key once.
If you only want to iterate over the data key then just return the data from the backend.
You can use a v-if condition to check whether the current key contains a class_no and if yes then display the row otherwise not.
<tr v-for="classroom in classrooms" :key="classroom.id" v-if="classroom.class_no">
<td>{{ classroom.class_no }}•{{ classroom.field }}•{{ classroom.room_no }}</td>
<td>{{ classroom.amount_students }}</td>
<td>{{ classroom.teacher }}</td>
<td>
<a href="#">
<i class="fa fa-edit blue"></i>
</a>
</td>
</tr>
Looking at your Vue data attribute, you want to use v-for="classroom in classrooms.data".
And if you are getting the data from API then you don't want to assign the full response to your classroom data attribute but assign response.data to classroom, so you can do
v-for="classroom in classrooms".
This will work unless your API returns data in a different format.
you can check on JsFiddle
https://jsfiddle.net/JManish/9qjvdy8n/2/
Make some changes in your classroom's data attribute.
<table class="table">
<thead>
<tr>
<th>Class</th>
<th>Amount of Students</th>
<th>Teacher</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr v-for="(classroom, index) in classrooms.data" :key="index">
<td>{{ classroom.class_no }}•{{ classroom.field }}•{{ classroom.room_no }}</td>
<td>{{ classroom.amount_students }}</td>
<td>{{ classroom.teacher }}</td>
<td>
<a href="#">
<i class="fa fa-edit blue"></i>
</a>
</td>
</tr>
</tbody>
</table>
new Vue({
el: '#app',
data() {
return {
classrooms: {
"success": true,
"data":[
{
"id": 1,
"class_no": 1,
"field": "Architecture",
"room_no": 4,
"amount_students": 40,
"teacher": "Bobby Fisher"
}
],
"message": "Find Classroom Detail"
}
}
}
})
Hope this will resolve your parsing issue.
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
I'm getting some errors while passing data to the frontend, but when I return this $order then it shows a JSON data like this
[
{
"id": 1,
"customer_id": 3446467182106354,
"products": {
"1": {
"'name'": "Soap",
"'quantity'": "1"
},
"2": {
"'name'": "Shampoo",
"'quantity'": "1"
}
},
"total_amount": 798,
"status": "pending",
"created_at": "2020-10-21T08:51:15.000000Z",
"updated_at": "2020-10-21T08:51:15.000000Z"
}
]
But when I pass It to the front end it says like this
Property [products] does not exist on this collection instance. (View: C:\xampp\htdocs\blog\resources\views\customer\orders.blade.php)
by the way I've a json data in my database
looking at the json data u have mentioned in the question, Products is array of products and its in side main array.
you can access products this way...
make another foreach loop for products
<table class="table">
<thead class="thead-dark">
<tr>
<th scope="col">Products</th>
<th scope="col">Total</th>
<th scope="col">Status</th>
</tr>
</thead>
<tbody>
#foreach ($orders as $order)
<tr>
#foreach{{$order->products as $product}}
<th>{{ $product->name }}</th>
#endforeach
<td>{{ $order->total }}</td>
<td>{{ $order->status }}</td>
</tr>
#endforeach
</tbody>
you need to loop over you cannot print collcetion so you need to update your controller and blade file like this
Controller
public function customerOrders($id)
{
$orders = Order::where('customer_id', $id)->get();
return view('customer.orders', compact('orders'));
}
blade
<table class="table">
<thead class="thead-dark">
<tr>
<th scope="col">Products</th>
<th scope="col">Total</th>
<th scope="col">Status</th>
</tr>
</thead>
<tbody>
#foreach ($orders as $order)
<tr>
<th>
#foreach ($order->products as $product)
{{ $product['name'] }}
#endforeach
</th>
<td>{{ $order->total }}</td>
<td>{{ $order->status }}</td>
</tr>
#endforeach
</tbody>
</table>
like this you will get all the data
Before using this data you should use json_decode() function
Got following .json:
[{
"STATUS": "0500",
"POSID": "..."
},
{
"STATUS": "1500",
"POSID": "..."
},
{
"STATUS": "0500",
"POSID": "..."
}]
I want to create a table in vue-js with 2 columns.
First column shows STATUS and second column counts number of .json elements with that status.
Output should be like that, in a table:
Status Count
0500 2
1500 1
Currently I'm just writing the full table with v-for:
<tr v-for="data in data">
<td>{{ data.Status }}</td>
</tr>
Tried it with filter but I won't accomplish it.
Could you help me?
UPDATED
This logic can be implemented directly by javascript. Vue.js is not and should not be responsible for this.
You can use _.groupBy from lodash or write your own implementaion.
This is one of possible solutions:
computed: {
preparedData(){
return _.groupBy(this.data, 'STATUS');
}
}
And then use preparedData instead of data in the template.
<tr v-for="(value, key) in preparedData">
<td>{{ key }}</td>
<td>{{ value.length }}</td>
</tr>
Check the example here: https://codepen.io/probil/pen/MOVMQj?editors=1010
Did it now with:
<tr v-for="(value, key) in countData">
<td>{{ key }}</td>
<td>{{ value }}</td>
</tr>
and
countData (jitcalls) {
return _.countBy(_.map(this.jitcalls, function (d) {
return d.ANLIE
}))
Thank you!! :)