Yajra Datatable custom Model Attribute - laravel

I'm using Yajra Datatables for Laravel and it won't show the custom attribute for my User model. This is my User model:
protected $appends = ['sum_work_hours'];
public function work_hours()
{
return $this->hasMany(WorkHour::class);
}
public function getSumWorkHoursAttribute()
{
return $this->work_hours->sum('hours_total');
}
And this is in Controller:
public function showHours()
{
return view('hour');
}
public function getHoursDatatable()
{
$users = User::select(['name', 'email', 'sum_work_hours']);
return Datatables::of($users)->make();
}
And in view:
<link rel="stylesheet" href="https://cdn.datatables.net/1.10.15/css/dataTables.bootstrap.min.css">
<div class="container">
<div class="row">
<div class="col-md-12">
<div class="panel panel-default">
<div class="panel-heading">All Working Hours</div>
<div class="panel-body">
<table id="users-table" class="table table-striped table-bordered">
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Sum Work Hours</th>
</tr>
</thead>
</table>
</div>
</div>
</div>
</div>
</div>
<script src="https://cdn.datatables.net/1.10.15/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.datatables.net/1.10.15/js/dataTables.bootstrap.min.js"></script>
<script type="text/javascript">
$(function() {
$('#users-table').DataTable({
processing: true,
serverSide: true,
ajax: 'http://127.0.0.1:8000/datatables/get_hours_datatable',
columns: [
{ data: 'name' },
{ data: 'email' },
{ data: 'sum_work_hours' }
]
});
});
</script>
And this is what I get:
What could be wrong?

The problem was in my Controller
public function getHoursDatatable()
{
// this line was wrong
$users = User::select(['name', 'email', 'sum_work_hours']);
return Datatables::of($users)->make();
}
It should have been like this:
$users = User::with('work_hours')->get();
Now I get the results in my table.

Related

How to display subnested arrays in Vue search component - Laravel

I'm having issues displaying eloquent relationship data via my vue.js search template, specifically my customer->biller fields.
models.student_first_name will display however
models.billers.biller_first_name wont show anything
The search function is working on my customers.index view using the following
CustomerDetailsController:
public function getData(Request $request){
$search = $request->search;
$customer = Customer::with('orders', 'billers', 'paymentplans', 'paidinfulls')->where(DB::raw('concat(student_first_name," ",student_last_name)'), 'like', '%'.$search.'%')->paginate(20);
return response()->json([
'model' => $customer
]);
}
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index(Request $request)
{
$customers = Customer::with('orders', 'paymentplans', 'billers')->orderBy('created_at', 'desc')->where('owner', Auth::user()->name)->paginate(25);
return view('customers.index', compact('customers', 'orders', 'paymentplans', 'funding'));
}
Customers.vue:
<template>
<div class="container">
<div class="field m-b-20">
<p class="control has-icons-left">
<input #keyup="fetchDataCustomer()" type="text" class="form-control input" name="search" v-model="search" placeholder="Search">
<span class="icon is-small is-left"><i class="fa fa-search"></i></span>
</p>
</div>
<table class="table">
<thead>
<tr>
<th>Student Name</th>
<th>Email</th>
<th>Biller Name</th>
<th>Biller Email</th>
<th>Courses Purchased</th>
<th>Deposit</th>
<th>Payment Plan</th>
<th>Accepted</th>
<th>Receipted</th>
</tr>
</thead>
<tbody>
<tr v-for="models in model.data">
<td>{{models.student_first_name}} {{models.student_last_name}}</td>
<td>{{models.student_email}}</td>
<td>{{models.billers.biller_first_name}}</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
import axios from 'axios'
export default{
data(){
return {
model: {},
search:'',
url:'api/customers'
}
},
created:function (){
this.fetchDataCustomer()
},
methods: {
fetchDataCustomer(){
var vm = this
axios.get(`${this.url}?search=${this.search}`)
.then(function (response) {
Vue.set(vm.$data, 'model', response.data.model)
})
}
}
}
</script>
JSON output of a search result
{"model":{"current_page":1,"data":[{"id":"627d0130-4dd0-11e8-91dd-69869f509337","enrolment_id":"John","student_first_name":"John","student_last_name":"Smith","student_email":"johnsmith#mail.com","address":"123 Test Street","suburb":"Townsville","postcode":"9999","state":"AAA","home_phone":null,"work_phone":null,"mobile_phone":"0444444444","dob":"1999-01-01 00:00:00","drivers_license_number":"123738974987498","owner":"Sales Man","owner_email":"salesman#business.com","created_at":"2018-05-02 16:16:43","updated_at":"2018-05-02 16:16:43","orders":[{"id":933,"fc_account":16,"customer_id":"627d0130-4dd0-11e8-91dd-69869f509337","biller_id":246,"enrolment_id":"John","course_id":5,"delivery_mode":0,"course_cost":"2000.00","deposit":null,"gov_funding":"0","location":"0","Monday":0,"Tuesday":0,"Wednesday":0,"Thursday":0,"Friday":0,"Saturday":0,"Sunday":0,"start_time":null,"end_time":null,"start_date":null,"enrolment_issue_date":"2018-05-02","sale_type":2,"created_at":"2018-05-02 16:17:24","updated_at":"2018-05-02 16:17:24"}],"billers":[{"id":246,"customer_id":"627d0130-4dd0-11e8-91dd-69869f509337","biller_first_name":"John","biller_last_name":"Smith","biller_email":"johnsmith#mail.com","biller_address":null,"biller_suburb":null,"biller_postcode":null,"biller_state":null,"biller_phone":null,"created_at":"2018-05-02 16:17:24","updated_at":"2018-05-02 16:17:24"}],"paymentplans":[{"id":"836e7e40-4dd0-11e8-a907-83f96c25a7d0","enrolment_id":"John","customer_id":"627d0130-4dd0-11e8-91dd-69869f509337","paysmart_id":"FIT69869f509337","biller_id":246,"biller_first_name":"John","biller_last_name":"Smith","biller_email":"johnsmith#mail.com","payment_method":-1,"contract_value":"1500.00","interest_free":1,"payment_frequency":1,"commencement_date":"2018-05-24 00:00:00","payment":"100.00","first_payment":"200.00","admin_fee":"1.30","setup_fee":"5.50","deposit":"500.00","deposit_payment_method":"Cash","special_conditions":null,"accepted":null,"accepted_student":null,"created_at":"2018-05-02 16:17:38","updated_at":"2018-05-02 16:17:38","submitted":1,"biller_ip":null,"student_ip":null}],"paidinfulls":[]}]
Vue Debug
Your models.billers is an array but you're treating it as an object. So you'll have to access it via models.billers[0].biller_first_name instead of models.billers.biller_first_name given that it is always available.

How to reload the data of a table with vue and axios?

Well, i have a table populated with v-for: "usuario in usuarios". The initial charge does it correctly. But when i push the button "Buscar" only my <p>{{nombre}}</p> shows data. Look at these pictures:
Table populated with data
In the above picture, the table was populated with data, through getUsuarios() method. But in the next picture the table only shows blank data.
Table with blank data and <p>{{nombre}}</p>
Here are my codes:
Template:
<div>
<div class="panel panel-default">
<div class="panel-heading"><h1><strong>Lista de nombres</strong></h1></div>
<div class="panel-body">
<table class="table table-hover table-bordered table-striped">
<thead>
<tr>
<th>Nombre</th>
<th>Apellido Paterno</th>
<th>Apellido Materno</th>
</tr>
</thead>
<tbody>
<tr v-for="usuario in usuarios">
<td>{{usuario.Nombre}}</td>
<td>{{usuario.Apellido_P}}</td>
<td>{{usuario.Apellido_M}}</td>
</tr>
</tbody>
</table>
</div>
</div>
<br />
<p>Buscar usuario</p>
<div class="form-group">
<div class="input-group">
<input type="text" class="form-control" v-model="busqueda" placeholder="Buscar usuario" />
<button class="btn btn-default" v-on:click="buscarUsuario">Buscar</button>
</div>
<p>{{nombre}}</p>
</div>
</div>
</template>
Script
<script>
import axios from 'axios'
export default {
data() {
return {
usuarios:[],
busqueda: '',
nombre: '',
}
},
methods: {
buscarUsuario() {
axios.get('http://localhost:50995/api/GetUsuario?id=' + this.busqueda)
.then(response => {
this.usuarios = response.data,
this.nombre = response.data.Nombre
}).catch(e => {
console.log(e)
})
},
getUsuarios() {
axios.get("http://localhost:50995/api/GetUsuarios")
.then(response => {
this.usuarios = response.data
})
.catch(e => {
console.log(e)
})
}
},
created() {
this.getUsuarios(),
this.buscarUsuario()
}
}
</script>
As you can see, the <p>{{nombre}}</p> is populated with the data of the ID that i put in the input. But the table only shows blank data.
The <p>{{nombre}}</p> is only for test if the buscarUsuario() method works, and it's works but not with the table.
And, how can i reload the data of the table with the properties of the ID when i push the "Buscar" button?
Thank you
Something is wrong in your buscarUsuario() logic: you are overwriting the initial correct array of usuario objects with a single object of one usuario
axios.get('http://localhost:50995/api/GetUsuario?id=' + this.busqueda)
.then(response => {
/* REMOVE THIS LINE */ this.usuarios = response.data,
this.nombre = response.data.Nombre
}).catch(e => {
console.log(e)
})

Sorting and Filtering ajax data using Laravel and VueJs

Current code is sorting and filtering data using vue.js. It is working fine but data is dummy, it is hardcoded. I need to get data dynamically from table using vue js and laravel. How can I get dynamic data in gridData?
JS
Vue.component('demo-grid', {
template: '#grid-template',
props: {
data: Array,
columns: Array,
filterKey: String
},
data: function () {
var sortOrders = {}
this.columns.forEach(function (key) {
sortOrders[key] = 1
})
return {
sortKey: '',
sortOrders: sortOrders
}
},
methods: {
sortBy: function (key) {
this.sortKey = key
this.sortOrders[key] = this.sortOrders[key] * -1
}
}
})
// bootstrap the demo
var demo = new Vue({
el: '#app',
data: {
searchQuery: '',
gridColumns: ['name', 'power'],
gridData: [
{ name: 'Chuck Norris', power: Infinity },
{ name: 'Bruce Lee', power: 9000 },
{ name: 'Jackie Chan', power: 7000 },
{ name: 'Jet Li', power: 8000 }
]
}
})
laravel.blade.php
#extends('layouts.app')
#section('title', 'Customers List')
#section('styles')
#endsection
#section('content')
<div class="container">
<div class="row">
<div class="col-md-10 col-md-offset-1">
<div class="panel panel-default">
<div class="panel-heading">Customers List</div>
<div class="panel-body">
<script type="text/x-template" id="grid-template">
<table class="table table-hover table-bordered">
<thead>
<tr>
<th v-for="key in columns" #click="sortBy(key)" :class="{active: sortKey == key}">#{{key | capitalize}}<span class="arrow" :class="sortOrders[key] > 0 ? 'asc' : 'dsc'"></span>
</th>
</tr>
</thead>
<tbody>
<tr v-for="entry in data | filterBy filterKey | orderBy sortKey sortOrders[sortKey]">
<td v-for="key in columns">
#{{entry[key]}}
</td>
</tr>
</tbody>
</table>
</script>
<div id="app">
<form id="search">
Search <input name="query" v-model="searchQuery">
</form>
<demo-grid :data="gridData" :columns="gridColumns" :filter-key="searchQuery"></demo-grid>
</div>
</div>
</div>
</div>
</div>
</div>
#endsection
#section('scripts')
<script src="/js/vue.js"></script>
<script src="/js/vue-resource.min.js"></script>
<script src="/js/customers.js"></script>
#endsection
You will need to do a few things.
First, in Laravel, create a new route in your routes.php file, for ex.:
Route::get('/api/fighters', 'SomeController#index');
Then in your controller (somecontroller.php), you will have a method index which will query your database table and return it as JSON data.
public function index() {
//query your database any way you like. ex:
$fighters = Fighter::all();
//assuming here that $fighters will be a collection or an array of fighters with their names and power
//when you just return this, Laravel will automatically send it out as JSON.
return $fighters;
}
Now, in Vue, your can call this route and grab the data. Using AJAX. You can use any AJAX library that you like, even jQuery. I currently use Superagent.js. Vue will work just fine with any.
So, in your Vue code, create a new method to get your data.:
methods: {
getDataFromLaravel: function() {
//assign `this` to a new variable. we will use it to access vue's data properties and methods inside our ajax callback
var self = this;
//build your ajax call here. for example with superagent.js
request.get('/api/fighters')
.end(function(err,response) {
if (response.ok) {
self.gridData = response.body;
}
else {
alert('Oh no! We have a problem!');
}
}
}
}
Then you can just call this new method using a button or anyway you like. For example, using a button click event:
<button type="button" #click="getDataFromLaravel">Get Data</button>
Or you can even just have the data loaded automatically using Vue's ready function:
// bootstrap the demo
var demo = new Vue({
el: '#app',
data: {
.... }
ready: function () {
this.getDataFromLaravel();
},
methods: {
.... }
});
Done! You now have your database data assigned to Vue's data property gridData.

Laravel 5.1 datatables reorder row

I need help.
I'm using yajra/laravel-datatables for include datatables into my project.
All is working.
Now I want to use the row reorder extension: https://datatables.net/extensions/rowreorder/
But when I make a drag and drop with a row seems to work, but is not working.
I think is possible that is reloaded because I use ajax url to load data, unmaking the reorder I do. Is possible?
Well, these are my codes:
Controller:
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
$med = new Medicinas;
return view('admin.medicinas.index', ['med' => $med->get()]);
}
/**
* Process datatables ajax request.
*
* #return \Illuminate\Http\JsonResponse
*/
public function anyData()
{
return Datatables::of(User::select('*'))->make(true);
}
Routes:
Route::get('administrator/medicinas', [
'as' => 'admin.medicinas',
'uses' => 'MedicinasController#index'
]);
Route::controller('administrator/medicinas', 'MedicinasController', [
'anyData' => 'datatables.data',
'index' => 'administrator/medicinas',
]);
View:
#extends('app')
#section('content')
<div class="col-xs-12 col-sm-10">
#foreach($med as $medicina)
<div class="col-xs-12 col-sm-4">
{{ $medicina->nombre_comercial }}
</div>
#endforeach
</div>
<table id="users-table" class="table table-striped table-bordered" cellspacing="0" width="100%">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Email</th>
<th>Created At</th>
<th>Updated At</th>
</tr>
</thead>
<tfoot>
<tr>
<th>Id</th>
<th>Name</th>
<th>Email</th>
<th>Created At</th>
<th>Updated At</th>
</tr>
</tfoot>
</table>
<input type="text" name="" value="" placeholder="">
#endsection
#section('scripts')
<script type="text/javascript">
$(function() {
var table_id = '#' + 'users-table';
window.table = $(table_id).DataTable({
rowReorder: true,
processing: true,
serverSide: true,
ajax: '{!! route('datatables.data') !!}',
columns: [
{ data: 'id', name: 'id' },
{ data: 'name', name: 'name' },
{ data: 'email', name: 'email' },
{ data: 'created_at', name: 'created_at' },
{ data: 'updated_at', name: 'updated_at' }
]
});
window.table_h = $(table_id + ' thead th');
window.table_f = $(table_id + ' tfoot th');
});
</script>
#endsection
This is my layout:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Medicinas de amoooor</title>
{!! Html::style('assets/css/bootstrap.css') !!}
{!! Html::style('assets/css/bootstrap-switch.css') !!}
{!! Html::style('assets/css/bootstrap-tagsinput.css') !!}
{!! Html::style('assets/css/rowReorder.bootstrap.min.css') !!}
{!! Html::style('assets/css/style.css') !!}
<!-- Datatables -->
<link rel="stylesheet" href="//cdn.datatables.net/1.10.7/css/jquery.dataTables.min.css">
<!-- Fonts -->
<link href='https://fonts.googleapis.com/css?family=Arimo:400,400italic,700,700italic' rel='stylesheet' type='text/css'>
{!! Html::style('assets/css/font-awesome.min.css') !!}
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
#include('header')
<!-- Contents -->
#if (Auth::guest())
<div class="row">
<div class="container">
#yield('content')
</div>
</div>
#else
<div class="row">
<div class="container">
#include('admin.sidebar')
#yield('content')
</div>
</div>
#endif
#if (Session::has('errors'))
<div class="container">
<div class="alert alert-danger" role="alert">
<ul>
<strong>Oops! Something went wrong : </strong>
#foreach ($errors->all() as $error)
<li>{{ $error }}</li>
#endforeach
</ul>
</div>
</div>
#endif
<!-- Footer -->
#include('footer')
<!-- Modal -->
#yield('modal')
<!-- Scripts -->
{!! Html::script('assets/js/jquery-2.1.4.min.js') !!}
{!! Html::script('assets/js/jquery.dataTables.min.js') !!}
{!! Html::script('assets/js/dataTables.jqueryui.min.js') !!}
{!! Html::script('assets/js/dataTables.bootstrap.min.js') !!}
{!! Html::script('assets/js/bootstrap.min.js') !!}
{!! Html::script('assets/js/bootstrap-switch.js') !!}
{!! Html::script('assets/js/bootstrap-tagsinput.js') !!}
{!! Html::script('assets/js/dataTables.rowReorder.min.js') !!}
<!-- DataTables -->
<script src="//cdn.datatables.net/1.10.7/js/jquery.dataTables.min.js"></script>
#yield('scripts')
<script type="text/javascript">
$(function() {
if (typeof table_h !== 'undefined') {
// Setup - add a text input to each header cell
table_h.each( function () {
var title = $(this).text();
$(this).html( '<input type="text" placeholder="Search '+title+'" />' );
} );
}
if (typeof table_f !== 'undefined') {
// Setup - add a text input to each header cell
table_f.each( function () {
var title = $(this).text();
$(this).html( '<input type="text" placeholder="Search '+title+'" />' );
} );
}
// Apply the search
table.columns().every( function () {
var that = this;
if (typeof table_h !== 'undefined') {
$( 'input', this.header() ).on( 'keyup change', function () {
if ( that.search() !== this.value ) {
that
.search( this.value )
.draw();
}
});
}
if (typeof table_f !== 'undefined') {
$( 'input', this.footer() ).on( 'keyup change', function () {
if ( that.search() !== this.value ) {
that
.search( this.value )
.draw();
}
});
}
});
});
</script>
What you need to do is inject the sequence into the data.
<script type="text/javascript">
$(function() {
var table_id = '#' + 'users-table';
window.table = $(table_id).DataTable({
rowReorder: true,
processing: true,
serverSide: true,
ajax: {
url:'{!! route('datatables.data') !!}',
dataSrc: function ( d ) {
for ( var i=0, ien=d.data.length ; i<ien ; i++ ) {
d.data[i].seq = i;
}
return d.data;
}
},
columns: [
{ data: 'id', name: 'id' },
{ data: 'name', name: 'name' },
{ data: 'email', name: 'email' },
{ data: 'created_at', name: 'created_at' },
{ data: 'updated_at', name: 'updated_at' }
]
});
window.table_h = $(table_id + ' thead th');
window.table_f = $(table_id + ' tfoot th');
});
</script>

Get database record using AJAX, Knockout and JSON

I am fairly new to Knockout and Entity Framework and I have a problem where I cannot seem to output any JSON from an MVC 4 controller action via an AJAX call using Knockout onto an html page.
The table includes fields Email and RegsitrationNumber, these are used to validate the user.
If the user exists in the table then their country is displayed on the screen.
The profiler states a Status Code of 200 i.e OK. Can anyone help?
HTML ------
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script src="./Scripts/jquery-1.8.2.min.js"></script>
</head>
<body>
<div>
<div>
<h2 id="title">Login</h2>
</div>
<div>
<label for="email">Email</label>
<input data-bind="value: $root.Email" type="text" title="Email" />
</div>
<div>
<label for="registrationnumber">Registration Number</label>
<input data-bind="value: $root.RegistrationNumber" type="text" title="RegistrationNumber" />
</div>
<div>
<button data-bind="click: $root.login">Login</button>
</div>
</div>
<table id="products1" data-bind="visible: User().length > 0">
<thead>
<tr>
<th>Country</th>
</tr>
</thead>
<tbody data-bind="foreach: Users">
<tr>
<td data-bind="text: Country"></td>
</tr>
</tbody>
</table>
<script src="./Scripts/knockout-2.2.0.js"></script>
<script src="./Scripts/knockout-2.2.0.debug.js"></script>
<script src="./Scripts/functions.js"></script>
</body>
</html>
JAVASCRIPT -----
function UserViewModel() {
//Make the self as 'this' reference
var self = this;
//Declare observable which will be bind with UI
self.Name = ko.observable("Robbie");
self.Email = ko.observable("rob#test.com");
self.Occupation = ko.observable("Designer");
self.Country = ko.observable("UK");
self.RegistrationNumber = ko.observable("R009");
self.UserDate = ko.observable("06-04-2014");
var User = {
Name: self.Name,
Email: self.Email,
Occupation: self.Occupation,
Country: self.Country,
RegistrationNumber: self.RegistrationNumber,
UserDate: self.UserDate
};
self.User = ko.observable(); //user
self.Users = ko.observableArray(); // list of users
//Login
self.login = function ()
{
alert("login");
if (User.Email() != "" && User.RegistrationNumber() != "") {
$.ajax({
url: '/Admin/Login',
cache: false,
type: 'GET',
contentType: 'application/json; charset=utf-8',
data: ko.toJSON(User),
success: function (data) {
self.Users.push(data);
$('#title').html(data.Email);
}
}).fail(
function (xhr, textStatus, err) {
console.log('fail');
console.log(xhr.statusText);
console.log(textStatus);
console.log(err);
});
} else {
alert('Please enter an email and registration number');
}
};
}
var viewModel = new UserViewModel();
ko.applyBindings(viewModel);
ACTION -----
public ActionResult Login(string Email, string RegistrationNumber)
{
var user = from s in db.Users
select s;
user = user.Where(s => s.Email.ToUpper().Equals(Email.ToUpper())
&& s.RegistrationNumber.ToUpper().Equals(RegistrationNumber.ToUpper())
);
if (user == null)
{
return HttpNotFound();
}
return Json(user, JsonRequestBehavior.AllowGet);
}
Looks like your binding is incorrect...
<table id="products1" data-bind="visible: Users().length > 0">
<thead>
<tr>
<th>Country</th>
</tr>
</thead>
<tbody data-bind="foreach: Users">
<tr>
<td data-bind="text: Country"></td>
</tr>
</tbody>
</table>
User().length should be Users().length.

Resources