Vue/PHP - Parse JSON string as table - php

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.

Related

Convert PHP object to JSON format problem with single item arrays

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);
}

Laravel backend to Vue not displaying correctly sorted data

Simple situation: Fetching all rows from DB with Laravel controller and display them with Vue.
Laravel produces correctly sorted (by name) results from model however when fetched via Vue and looped over to display in an HTML table they are shown as the order they're stored in the DB.
Controller:
public function readCountryAll()
{
$data = World::Countries()->sortBy('name');
//return response()->json($data);
return $data;
}
Vue:
<thead>
<tr>
<th>Code</th>
<th>Name</th>
<th>Currency</th>
</tr>
</thead>
<tr v-for="country in countryList" :key="country.code">
<td>{{ country.code }}</td>
<td>{{ country.full_name }}</td>
<td>{{ country.currency_code }}</td>
</tr>
</table>
<script>
export default {
mounted: function() {
this.read();
},
data() {
return {
countryList: [],
}
},
methods: {
read() {
window.axios.get('/readCountry')
.then(response => this.countryList = response.data)
},
},
components: {
},
}
</script>
When data is sent via JSON order will be random. What you need to do is create a computed property in vuejs which can be called "sortedCountryList" and do your sorting there. Then you can use this computed property wherever you need to output sorted list.
<script>
export default {
mounted: function() {
this.read();
},
data() {
return {
countryList: [],
}
},
methods: {
read() {
window.axios.get('/readCountry')
.then(response => this.countryList = response.data)
},
},
computed: {
sortedCountryList: function() {
return this.countryList.sort(function (a, b) {
return b.name - a.name;
});
},
},
components: {
},
}
</script>
This Solved my issue.
computed: {
sortedArray: function() {
function compare(a, b) {
if (a.name < b.name)
return -1;
if (a.name > b.name)
return 1;
return 0;
}
return this.countryList.sort(compare);
}
}

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)
}

Ignited Datatables - display records on screen

I'm using Ignited Datatables to display posts in tabular way in my view. I've been struggling the last 4 days in order to do this working correct, but I can't understand what I'm doing wrong.
This is the functionality that fetches the data
// the Post_model
/**
* Get page data on datatables
*/
public function get_datatable() {
$this->load->library('datatables');
$this->datatables->select('id, title, slug, sort_description, status');
$this->datatables->from('posts');
return $this->datatables->generate();
}
// the posts controller
/**
* List all posts
*/
public function index() {
$this->data['datatables'] = true;
$this->data['data_url'] = 'admin/posts/data_ajax';
// $this->data['posts'] = $this->post_model->get_datatable();
// dump($this->data['pages']);
// load view
$this->load->view('admin/posts/index', $this->data);
}
public function data_ajax() {
$this->output->enable_profiler(false);
echo $this->post_model->get_datatable();
// echo json_encode($this->post_model->get_datatable());
exit();
}
// the view
<table class="table dataTable table-bordered" cellspacing="0" width="100%">
<thead>
<tr>
<th>ID</th>
<th>Title</th>
<th>Url Slug</th>
<th>Sort Description</th>
<th>Status</th>
</tr>
</thead>
<tfoot>
<tr>
<th>ID</th>
<th>Title</th>
<th>Url Slug</th>
<th>Sort Description</th>
<th>Status</th>
</tr>
</tfoot>
<!-- <tbody>
<tr>
<td colspan="5" class="dataTables_empty"></td>
</tr>
</tbody> -->
</table>
<?php if(isset($datatables)): ?>
<?php echo js_tag('js/dataTables/jquery.dataTables.min.js'); ?>
<?php echo js_tag('js/dataTables/dataTables.bootstrap.min.js'); ?>
<script type="text/javascript">
$(document).ready(function() {
$('.dataTable').DataTable({
'bProcessing' : true,
'bServerSide' : true,
'sAjaxSource' : '<?php echo base_url($data_url); ?>',
'sServerMethod' : 'POST',
'fnServerData' : function (sSource, aoData, fnCallback) {
$.ajax({
dataType : 'json',
type : 'post',
url : sSource,
data : aoData,
success : fnCallback,
"columns": [
{ "data": "id" },
{ "data": "title" },
{ "data": "slug" },
{ "data": "sort_description" },
{ "data": "status" }
]
});
}
});
});
</script>
<?php endif; ?>
So if I access the data_ajax() function from the url like this
localhost/my-blog/admin/posts/data_ajax
and echo echo $this->page->get_datatable(); I can the records
{"draw":0,"recordsTotal":2,"recordsFiltered":2,"data":[{"id":"1","title":"First post","slug":"first-post","sort_description":"This is the first post","status":"visible"},{"id":"2","title":"Second post","slug":"second-post","sort_description":"This is the second post","status":"visible"}]}
but the problem is I can't display them on my screen. In addition I also get this warning in an alert box
DataTables warning: table id=DataTables_Table_0 - Requested unknown parameter '0' for row 0. For more information about this error, please see http://datatables.net/tn/4
This is a screenshot of what I get
How can I make this work properly? Any help would be appreciated
Please try this
Add Columns parameter to associate data with column
The code will be something like this
$('.dataTable').DataTable({
'bProcessing' : true,
'bServerSide' : true,
'sAjaxSource' : '<?php echo base_url($data_url); ?>',
'sServerMethod' : 'POST',
"columns": [
{ "data": "id" },
{ "data": "title" },
{ "data": "slug" },
{ "data": "date_published" },
{ "data": "status" }
]
'fnServerData' : function (sSource, aoData, fnCallback) {
$.ajax({
dataType : 'json',
type : 'post',
url : sSource,
data : aoData,
success : fnCallback,
});
}
});
Please refer datatables column, for details
I had similar problem. This is how I got it solved:
You have to set the columns as this
"columns": [null, null, null, null, null,{}]
Set it separately not in the Ajax.

Style the output of JSON in Zend Framework to make jQuery DataTables working

I am trying to implement jQuery DataTables into a "new" form with Zend Framework, I set up the following action in the controller:
public function ajaxFindQuotesAction()
{
$this -> setNoRender();
$quoteTable = new Model_QuotesTable();
$select = $quoteTable->select();
$select -> from($quoteTable, array('qte_id', 'qte_description'));
$rows = $quoteTable->fetchAll($select);
$json = Zend_Json::encode($rows->toArray());
echo($json);
}
I also set up in the view the following code:
<?php $this->inlineScript()->captureStart(); ?>
$(document).ready(function() {
$('#example').dataTable( {
"bProcessing": true,
"sAjaxSource": '/jobs/ajax-find-quotes'
} );
} );
<?php $this->inlineScript()->captureEnd(); ?>
<table class="display dataTable" id="example" >
<thead>
<tr>
<th>ID</th>
<th>Title</th>
</tr>
</thead>
</table>
Problem is, the current JSON output is the following:
[
{
"column_1":"value 1",
"column_2":"value 2"
},
{
"qte_id":"3",
"qte_description":"go to the zoo"
}
]
While DataTables to work wants this format (copied from the example file):
{
"aaData": [
[
"value 1",
"value 2"
],
[
"Trident",
"Internet Explorer 5.0"
]
]
}
Any ideas? Thank you very much in advance
Try:
$data = array_values(array_map('array_values', $rows->toArray()));
$json = Zend_Json::encode(array_combine(
array('aaData'),
array($data)
));
You need to encode an object, which consists of rows and fields as arrays. The problem is that PHP's so-called arrays are actually ordered maps, so you need to get rid of the associative keys to have arrays in resulting JSON.

Categories