Convert PHP object to JSON format problem with single item arrays - php

Im creating a service that displays some information in a Vuetify datatable.
The problem is that when I get an answer from the server that's using json_encode. The one of the values will sometimes be a single value which will be translated into an object and not an array. As far as my knowledge goes, using vuetify requires it to be an array to display it correctly.
I Already tried to explicitly tell the object that it's an array.
[
{
"values": "something",
"Items": {
"item" : [{ "Iteminfo": "Item1" },
{ "Iteminfo": "Item2"}
]
}
}
]
///////// result with single Object
[
{
"values": "something",
"Items": {
"item" : { "Iteminfo": "Item1"}
}
}
]
//// Vuetify
<v-data-table
:headers="headers"
:items="orders"
:expand="expand"
:dark="false"
item-key="Name"
>
<template v-slot:items="props">
<tr #click="props.expanded = !props.expanded">
<td>Order: {{ props.item.Ordernumber }} , Klantnaam: {{
props.item.Name }}
</td>
</tr>
</template>
<template v-slot:expand="props">
<v-card flat>
<v-card-text>
<table>
<tr>
<th>Artikelnummer</th>
</tr>
<tr v-for="item in props.item.Items.item">
<td>{{ item.Article }}</td>
</tr>
</table>
</v-card-text>
</v-card>
</template>
</v-data-table>
///For getting the information
<script>
export default{
data () {
return {
filiaalnummer: '',
expand: false,
headers: [
{
text: 'Orders',
align: 'left',
sortable: false,
value: 'name'
},
],
orders: [],
}
},
methods: {
getOrders : function(){
console.log(this.filiaalnummer);
axios.get('/orders/getOrders/'+this.filiaalnummer)
.then(response => this.orders =response.data)
.catch(error => console.log(error.response.data));
},
}
}
</script>
Laravel Server Side
return json_encode($arrayOfObjectsContainingTheItems);
To get the items inside of the Object I need them to be inside an array. And when a single object is presented it will encode to an object aswell, which results in Vuetify trying to read al de individual properties of that object as Items.
Can I explicityly tell PHP that it needs to be an array? Or can I do something in Vuetify to read the object nonetheless?

I fixed it using the JsonSerializable interface
public function jsonSerialize() {
if(is_array($this->item)){
return $this->item;
}else{
return array($this->item);
}

Related

filtered date doesn't show after edit the column date format - Laravel Yajra Datatable

I use laravel 8 + lumen rest api server and little bit confused because when i consume timestamp and parse it to localize format date on laravel side, also separated the display and timestamp for the js side datatables, the editColumn()it make the filtered search doesn't work because the main of search params is from the timestamp i was set before but on the view i saw it use display side, so how i can make the both filtered(search) and sort work ?
response data :
array:4 [▼
0 => array:6 [▼
"id_role" => 1
"nama_role" => "super.admin"
"created_at" => "2021-11-02T07:32:00.000000Z"
"updated_at" => "2021-11-02T07:32:00.000000Z"
"created_by" => "self"
"updated_by" => "self"
]
.. => ...
]
the column i was sorted was created_at and updated at.
RoleController.php
<?php
public function index(Request $request)
{
$raw = Http::withHeaders(['Authorization' => 'Bearer ' . Cookie::get('access_token')])->get(env('API_URL') . '/v1/kelola-role/role');
$data = $raw->json('data');
$status = $raw->json('status');
if ($request->ajax()) {
if ($status == 'success') {
return DataTables::of($data)
->addIndexColumn()
->editColumn('created_at', function ($e) {
return [
'display' => Carbon::parse($e['created_at'])->format('d/m/Y'),
'timestamp' => Carbon::parse($e['created_at'])
];
})
->editColumn('updated_at', function ($e) {
return [
'display' => Carbon::parse($e['updated_at'])->format('d/m/Y'),
'timestamp' => Carbon::parse($e['updated_at'])
];
})
->make(true);
}
return abort(401);
}
return view('pages.pengaturan.kelola-role');
}
the view :
<table class="table" id="dataRole" style="width:100%">
<thead>
<tr>
<th>No</th>
<th>Nama Role</th>
<th>Dibuat Pada</th>
<th>Diupdate Pada</th>
</tr>
</thead>
<tfoot>
<tr>
<th>No</th>
<th>Nama Role</th>
<th>Dibuat Pada</th>
<th>Diupdate Pada</th>
</tr>
</tfoot>
</table>
the js side :
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
document.addEventListener("DOMContentLoaded", function() {
$("#dataRole").DataTable({
processing: true,
serverSide: true,
ajax: {
type: "GET",
url: "",
dataSrc: function(json) {
barDone();
return json.data;
}
},
columns: [{
data: 'DT_RowIndex',
name: 'DT_RowIndex',
orderable: false,
searchable: false
},
{
data: 'nama_role',
name: 'nama_role'
},
{
name: 'created_at.timestamp',
data: {
_: 'created_at.display',
sort: 'created_at.timestamp'
}
},
{
name: 'updated_at.timestamp',
data: {
_: 'updated_at.display',
sort: 'updated_at.timestamp'
}
},
],
responsive: true,
fixedHeader: true,
select: {
style: "multi"
},
language: {
url: '{{ env('APP_URL') }}/id.json',
processing: "<div id='loadercontainer'><div class='d-flex justify-content-center text-secondary' id='loader'><div class='spinner-border' role='status'><span class='sr-only'>Loading...</span></div></div></div>"
},
dom: '<"row"<"col-12 col-sm-6 py-0"l><"col-12 col-sm-6 py-0 pt-2 pt-sm-0"fr><"col-12"t><"col-12 d-flex justify-content-between"ip>>',
render: function(data, type, row, meta) {
return meta.row + meta.settings._iDisplayStart + 1;
},
});
});
created_at sort view just work
but when i search it doesn't work
You also need to transform the search on the query level. Try using filterColumn to modify how the package will search on the edited column.
In some cases, we need to implement a custom search for a specific column. To achieve this, you can use filterColumn api.

Vue/PHP - Parse JSON string as table

I am trying to parse a JSON string that my Laravel application serves to my Vue view. The JSON string can look like this:
{
"1":[ { "row":"Some text here on first column." },
{ "row":"And more text. Second row." },
{ "row":"Text!" }
],
"2":[ { "row":"2nd column text." },
{ "row":"" }
],
"3":[ { "row":"Even more text. But on the third column." }
]
}
Things to note here:
The "1", "2", and "3" refers to columns. So in above examples, I have 3 columns.
Each "row" refers to a row within the column.
I am trying to parse the string as a table, like: https://jsfiddle.net/59bz2hqs/1/
This is what I have now:
<template>
<div>
<table>
<tbody>
<tr v-for="row in this.content">
<td>{{row}}</td>
</tr>
</tbody>
</table>
<div>
</template>
<script>
export default {
data() {
return {
content: []
}
},
created() {
Event.$on("document-was-processed", content => {
this.content = content;
});
}
}
</script>
Now above simply prints out the actual JSON string. Can anyone help me out on how to actually parse the content?
Edit
Thinking a bit more about this. I am actually not quite sure if my JSON string layout can even support my desired output.
Maybe like something below? Not quite sure.
{ "1":[
{ "text":"Some text here on first column."},
{ "text":"2nd column text."},
{ "text":"Even more text. But on the third column"}
],
"2":[
{ "text":"And more text. Second row." },
{ "text":"" },
{ "text":"" }
],
"3":[
{ "text":"Text!"},
{ "text":""},
{ "text":""}
]}
Then something like:
<table class="text-left w-full border-collapse m-3">
<thead>
<tr class="bg-gray-100">
<th v-for="(item, idx) in this.content" class="p-1">
{{idx}}
</th>
</tr>
</thead>
<tbody>
<tr v-for="(row, rid) in this.content">
<td v-for="(col, cid) in row">{{ col.text }} </td>
</tr>
</tbody>
</table>
You have to transpose your data before rendering it.
This is my dummy code
<script>
export default {
data() {
return {
dataTable: []
};
},
created() {
// Instead of fetching your content I put it in a local variable
let content = JSON.parse(`{
"1":[ { "row":"Some text here on first column." },
{ "row":"And more text. Second row." },
{ "row":"Text!" }
],
"2":[ { "row":"2nd column text." },
{ "row":"" }
],
"3":[ { "row":"Even more text. But on the third column." }
]
}`);
// Transform object in array of its values
let data = Object.values(content);
let colsLength = data.map(r => r.length);
let maxNumCols = Math.max.apply(Math, colsLength);
let colsArraySchema = Array.apply(null, Array(maxNumCols)).map((r, i) => i);
this.dataTable = colsArraySchema.map((col, i) => data.map(row => row[i]));
// For debug.
console.log(content);
console.log(data);
console.log(colsLength);
console.log(maxNumCols);
console.log(this.dataTable);
}
};
</script>
Now you can render the dataTable variable in your template.
(Take care that you row array could contain undefined values)
<template>
<table border="1">
<tbody>
<tr v-for="(row, index) in dataTable" :key="index">
<td v-for="(cell, index) in row" :key="index">
<span v-if="cell">{{cell["row"]}}</span>
</td>
</tr>
</tbody>
</table>
</template>
You can see a live demo here: https://codesandbox.io/s/vue-json-transpose-dt915
I hope it helps you.

PHP dynamic JSON invalid

I am trying to get a dataTable on a page called "locations.php" but i am still get a JSON invalid error.
I generate the JSON dynamically using this php code on "get_SR_Locations.php":
$myjson = array();
foreach ($locationList as $list) :
$json= array(
"id" => addslashes($list['id']),
"name" => addslashes($list['name']),
"address" => addslashes($list['address']),
"telephone" => addslashes($list['telephone']),
"emailaddress" => addslashes($list['email'])
);
array_push($myjson, $json);
endforeach;
$mj=array("data"=>$myjson);
echo json_encode($mj);
The generated JSON looks something like this:
{"data":[{"id":"108","name":"Sportpark","address":"Karspstreet 501","telephone":"0123456789","emailaddress":"sport#mail.com"},{"id":"2","name":"Blaashal","address":"Gustavstreet 2920","telephone":"","emailaddress":"sporting#mailing.com"}]}
So when I put this in a JSON validator it says: VALID JSON
But I still get an invalid JSON warning by ajax.
On locations.php I have this code:
HTML
<table id="displayTable" class="table table-striped table-bordered display compact" style="width:100%">
<thead>
<tr>
<th> </th>
<th>Name</th>
<th>Address</th>
<th>Telephone</th>
</tr>
</thead>
<tfoot>
<tr>
<th> </th>
<th>Name</th>
<th>Address</th>
<th>Telephone</th>
</tr>
</tfoot>
</table>
And this JQUERY
function format ( d ) {
// `d` is the original data object for the row
return 'So Far .... NOT so Good';
}
$('#SR_sendForm').click(function(){
$('#displayTable').DataTable(
{
"order": [[ 1, "asc" ]],
"scrollY": $(window).height()-($(window).height()/10),
"scrollX": true,
"ajax": 'pages/get_SR_Locations.php?fdr='+$('#FDR').val()+'&s_term='+$('#searchterm').val()+'&city='+$('#city').val()+'&searchgroup='+$('#searchgroup').val(),
"columns": [
{
"className": 'details-control',
"orderable": false,
"data": null,
"defaultContent": ''
},
{ "data": "name" },
{ "data": "address" },
{ "data": "telephone" }
]
}
);
$('#responseTable').show();
}
});
// Add event listener for opening and closing details
$('#responseTable tbody').on('click', 'td.details-control', function () {
var tr = $(this).closest('tr');
var row = table.row( tr );
if ( row.child.isShown() ) {
// This row is already open - close it
row.child.hide();
tr.removeClass('shown');
}
else {
// Open this row
row.child( format(row.data()) ).show();
tr.addClass('shown');
}
} );
And this is the error I get:
DataTables warning: table id=displayTable - Invalid JSON response. For more information about this error, please see http://datatables.net/tn/1
What is wrong?
Thank you Jeff.... I did what you said ... Add json to the data instead of going via ajax.
So the solution is:
I made an tempDIV to load the data from get_SR_Locations.php
<div class="row" id="tempDIV" style="display: none"></div>
then I load the data and I use the callback for errors etc.
$('#tempDIV').load('pages/get_SR_Locations.php?fdr='+$('#FDR').val()+'&s_term='+$('#searchterm').val()+'&city='+$('#city').val()+'&searchgroup='+$('#searchgroup').val(), function(responseTxt, statusTxt, xhr) {
if(statusTxt == "success"){
$('#displayTable').DataTable(
{
"order": [[ 1, "asc" ]],
"scrollY": $(window).height()-($(window).height()/10),
"scrollX": true,
"data": JSON.parse($.trim($('#tempDIV').text())),
"columns": [
{
"className": 'details-control',
"orderable": false,
"data": null,
"defaultContent": ''
},
{ "data": "name" },
{ "data": "address" },
{ "data": "telephone" }
]
}
);
$('#responseTable').show();
}
if(statusTxt == "error"){
$('#responseTable').html("<b>Oops</b><br>Houston we have a problem");
alert("Error: " + xhr.status + ": " + xhr.statusText);
$('#responseTable').show();
}
});
And a last modification in get_SR_Locations.php:
I removed this line:
$mj=array("data"=>$myjson);
$myjson = array();
foreach ($locationList as $list) :
$json= array(
"id" => addslashes($list['id']),
"name" => addslashes($list['name']),
"address" => addslashes($list['address']),
"telephone" => addslashes($list['telephone']),
"emailaddress" => addslashes($list['email'])
);
array_push($myjson, $json);
endforeach;
echo json_encode($myjson);

Laravel 5 dataTables, initialise table with controller function

I'm trying to create a dataTable of users where each row has a drop-down child row that contains checkboxes of the user privileges. So quite dynamically a 'super' admin can click on users and assign their privileges within the table.
Firstly, not sure if this is a good idea, so feel free to suggest a better way of doing it. Maybe a simple popup modal per row would be easier but for now I've decided this would be a cool way of doing it, so I push on.
Trying to initialise the dataTable with AJAX has me stumped currently however.
PermissionsController.php
public function grid()
{
//retrieve data from models
$data['data'] = collect([ 'admins' => $admins, 'roles' => $roles ]);
return $data;
}
routes.php
Route::get('user-permissions', 'PermissionsController#grid');
permissions.blade
<table class="table table-striped" id="admins_table" >
<thead>
<tr>
<th>Last Name</th>
<th>First Name</th>
<th>Email</th>
<th>Phone</th>
</tr>
</thead>
</table>
js
var oTable = $('#admins_table').dataTable( {
"sDom": "<'row'<'col-md-6'l><'col-md-6'f>r>t<'row'<'col-md-12'p i>>",
"aaSorting": [],
"oLanguage": {
"sLengthMenu": "_MENU_ ",
"sInfo": "Showing <b>_START_ to _END_</b> of _TOTAL_ entries"
},
"ajax": {
//here's where I'm trying to grab the data
"url": "http://example.app/user-permissions",
"dataSrc": "data"
},
"columns": [
{ "data": "last_name" },
{ "data": "first_name" },
{ "data": "email" },
{ "data": "phone" }
]
});
Ajax
{
"data":
{
"admins":
[{
"id":31,
"email":"example#gmail.com",
"last_login":"2015-07-27 09:50:50",
"first_name":"Gary",
"last_name":"Barlow",
"roles":[{
"id":1,"slug":"admin"
}]
}],
"roles":
[
{"id":3,"slug":"admin","name":"Admin"},
{"id":7,"slug":"accounts","name":"Accounts"},
{"id":8,"slug":"sales","name":"Sales"},
{"id":9,"slug":"superAdmin","name":"SuperAdmin"}
]
}
}
The "admin" object encompasses all the admins that are passed through and their already assigned roles. These should appear as already ticked within the child-row.
The "roles" object will contain all the current roles available to allow for assignment of additional roles. Basically, this identifies the number of checkboxes that need to appear.
I've abstracted out the rest as what's above pertains to the initialisation. Greatly appreciate any help.
Trying to use AJAX I'm getting nothing but "No data available in table" when if I type in the browser the route path I get the JSON object output.
I'm not sure how I should call the route.
url: '/user-permissions',
dataSrc: 'data.admins',
success: function (data) {
console.log(data);
}
Will the above suffice? I don't really want to be calling the whole url. I even added a success function to try and get a console output of the data but still nothing.
the correct dataSrc reference would be data.admins
you miss a admins[].phone in the sample data?
As I understand you want to show a <select> populated with data.roles, showing the current data.admins[].roles[0].id?
You can do this by collecting data.roles in the dataSrc callback (or in a xhr.dt event) and use a render method for the role column :
<table class="table table-striped" id="admins_table" >
<thead>
<tr>
<th>Last Name</th>
<th>First Name</th>
<th>Email</th>
<th>Phone</th>
<th>role</th>
</tr>
</thead>
</table>
js, only the important
var roles,
var oTable = $('#admins_table').dataTable( {
"ajax": {
"url": "http://example.app/user-permissions",
"dataSrc" : function(json) {
roles = json.data.roles;
return json.data.admins;
}
},
"columns": [
{ "data": "last_name" },
{ "data": "first_name" },
{ "data": "email" },
{ "data": "phone" },
{ "data": "roles",
"render": function(data, type, row) {
var select = '<select>',
role = data[0].id;
for (var i=0;i<roles.length;i++) {
select+='<option value="'+roles[i].id+'"';
if (role == roles[i].id) select+=' selected';
select+='>'+roles[i].name+'</option>';
}
select+='</select>';
return select;
}
}
]
});
produces this table :
with this data :
{ "data": {
"admins": [{
"id":31,
"email":"example#gmail.com",
"last_login":"2015-07-27 09:50:50",
"first_name":"Gary",
"last_name":"Barlow",
"phone" : "123",
"roles":[{
"id":8,"slug":"sales"
}]
},{
"id":32,
"email":"example#yahoo.com",
"last_login":"2015-07-27 09:50:50",
"first_name":"Bary",
"last_name":"Garlow",
"phone" : "321",
"roles":[{
"id":7,"slug":"accounts"
}]
}],
"roles": [
{"id":3,"slug":"admin","name":"Admin"},
{"id":7,"slug":"accounts","name":"Accounts"},
{"id":8,"slug":"sales","name":"Sales"},
{"id":9,"slug":"superAdmin","name":"SuperAdmin"}
]
}
}
It's been awhile now since I asked this question and I thought I'd clarify what I did to solve the problem. First I ensured all the data tables scripts were the latest versions, not sure if this was a problem but I was using some outdated stuff.
Within the tables initialisation the ajax call became simply:
ajax: "/user-permissions"
Most the hard work went into the controller function that was called by the above route:
public function grid()
{
$admins = // get users with relevant roles e.g. ($user->load('roles'))
return Datatables::of($admins)->make(true)
}

AngularJS json output format

I have problem with outputting data from JSON file
{
"movie": {
"RowCount": 0,
"Result": [
{
"movieID": "124",
"moviename": "Hello"
},
{
"movieID": "123",
"moviename": "World"
}
]
}
}
I dont know why the {{}} statement wont work with this kind of JSON file. if the JSON File with another format like following
{
"discCount": 0,
"results":[
{
"disccode": "ABC123"
},
{
"disccode": "ABCD123"
}
]
}
it works perfect just by calling the {{variablename.disccode}}
can anybody help me please? thank you
From your edit, it appeared that you are resolving the wrong property. You should resolve :
defer.resolve({
data: response.movie.Result,
rowCount: response.movie.RowCount
});
Then, because the controller stores the data in $scope.movies, the following ng-repeat will be ok :
<tr data-ng-repeat="movie in movies">
<td>{{movie.ID}}</td><td>{{movie.moviename}}</td>
</tr>

Categories