I need to pass a variable from the controller to the view, to use it in the script and configure the Highstock graph. I have a problem with the date conversion, and the use of arrays. Unfortunately, the data are not included in the chart.
I receive the data correctly in the view, but I think we need to "format" it via json_encode or whatever.
Can you tell me why and how can I solve the problem?
statistiche.blade.php
#section('content')
<div id="container" style="height: 400px; min-width: 310px"></div>
#stop
#section('css')#stop#section('js')
<script>
var data = [#php echo $data #endphp];
// Create the chart
Highcharts.stockChart('container', {
rangeSelector: {
selected: 1
},
title: {
text: 'Richieste ricevute'
},
series: [{
name: 'Richieste ricevute',
data: data,
tooltip: {
valueDecimals: 2
}
}]
});
</script>
#stop
statisticheController.php
public function index(){
/* calcolo il totale delle richieste ricevute */
$richieste = Richiesta::groupBy(DB::raw('DATE_FORMAT(created_at, "%Y-%m-%d")'))
->select(DB::raw('DATE_FORMAT(created_at, "%Y-%m-%d") as data'), DB::raw('count(*) as richieste_totali'))
->get();
foreach($richieste as $richiesta) {
$data[] = [$richiesta->data, $richiesta->richieste_totali];
}
return view('layouts.statistiche', compact( 'data'));
}
Instead of
var data = [#php echo $data #endphp]
you can just have
var data = #json($data);
Also, instead of running #php echo $stuff; #endphp you can also echo stuff like {{$stuff}}
Check this docs https://laravel.com/docs/5.6/blade
Related
I have a custom resource-tool working fine in the view panel of a resource, but it dont appears when i go o the edit mode. Is there something i should add to the component or to the Nova configuration to enable the component in the edit mode?
Code in User.php
public function fields(Request $request)
{
return [
ID::make()->sortable(),
Text::make('First name', 'firstName')
->sortable()
->rules('required', 'max:255'),
Text::make('Last name', 'lastName')
->sortable()
->rules('required', 'max:255'),
Text::make('Email')
->sortable()
->rules('required', 'email', 'max:254')
->creationRules('unique:users,email')
->updateRules('unique:users,email,{{resourceId}}'),
Password::make('Password')
->onlyOnForms()
->creationRules('required', 'string', 'min:6')
->updateRules('nullable', 'string', 'min:6'),
YesNovaUserPermissions::make(),
];
}
User view:
User edit:
Nova does not seem to allow you to obtain this functionality with a custom resource but you can with a custom field. You basically create a "dummy" field which does not really exist on the model and use a mutator on the model to overwrite the default model saving functionality.
Following the documentation above, you can build a Vue component which will appear within the resource edit form itself, similarly to how I have done with the tags picker pictured below.
Code for that:
<template>
<default-field :field="field" :errors="errors" :show-help-text="showHelpText">
<label for="tag" class="inline-block text-80 pt-2 leading-tight">Tag</label>
<template slot="field">
<div id="multitag-flex-holder">
<div id="multitag-search-holder" class="w-1/2">
<div class="search-holder">
<label>Search Categories</label>
<input type="text" v-model="searchString" #focus="isSearching = true" #blur="isSearching = false" style="border:2px solid #000"/>
<div class="found-tags" v-if="isSearching">
<div v-for="(tag, i) in foundTags" #mousedown="addToSelected(tag)" :key="i">{{tag.name}}</div>
</div>
</div>
</div>
<div class="select-tags-holder w-1/2">
<div class="selected-tags">
<div v-for="(tag, i) in selectedTags" :key="'A'+i" #click="removeTag(tag)">{{tag.name}} X</div>
</div>
</div>
</div>
</template>
</default-field>
</template>
<script>
import { FormField, HandlesValidationErrors } from 'laravel-nova'
export default {
mixins: [FormField, HandlesValidationErrors],
props: ['resourceName', 'resourceId', 'field'],
data: function () {
return {
selectedTags:[],
isSearching:false,
searchString:''
}
},
mounted(){
console.log(this.field)
this.field.value.forEach((tag)=>{
this.addToSelected(tag)
})
formData.append('whereType', 'Tag');
},
computed: {
// a computed getter
foundTags() {
// `this` points to the vm instance
return this.field.tags.filter((tag) => {
if(tag.name.search(new RegExp(this.searchString, "i")) >= 0){
if(this.selectedTagNames.indexOf(tag.name) == -1){
return tag;
}
};
})
},
selectedTagNames(){
var selNames = this.selectedTags.map((tag) => {
return tag.name;
})
return selNames;
}
},
methods: {
/*
* Set the initial, internal value for the field.
*/
setInitialValue() {
this.value = this.field.value || ''
},
removeTag(tag){
var index = this.selectedTags.indexOf(tag);
if (index > -1) {
this.selectedTags.splice(index, 1);
}
},
addToSelected(tag){
this.selectedTags.push(tag)
},
/**
* Fill the given FormData object with the field's internal value.
*/
fill(formData) {
var tagIdArray = []
this.selectedTags.forEach((tag)=>{
tagIdArray.push(tag.id)
})
formData.append(this.field.attribute, tagIdArray)
},
},
}
</script>
Then, you can overwrite how the save functionality works in your model to accommodate for the "dummy" field. Note below instead of syncing the tags directly on the mutator, which will work most of the time depending on your data structure, I had to pass the tags to the "Saved" event on the model to accommodate for when creating a new record and the associated record id is not yet available, thus cannot be synced for a many to many relationship.
public function setTagsAttribute($value)
{
$tags = explode(",", $value);
$this->tempTags = $tags;
unset($this->tags);
}
protected static function booted()
{
static::saved(function ($article) {
$article->tags()->sync($article->tempTags);
});
}
Summary of problem or feature request
The reply o load datatable is very slow, betwen 3-5seg
How can I optimize the data load?
when I did not use server inside it was much faster..
first of all, Thanks
Code snippet of problem
Controller
public function list_user(){
$users = User::all();
$users->each(function ($users)
{
$users->role;
});
return datatables()->collection($users)->toJson();
}
Js
function activar_tabla_users() {
$('#DataTableUser').DataTable({
"processing" : true,
"serverSide" : true,
"searchDelay" : 500,
"responsive": {
orthogonal: 'responsive'
},
"language": {
"url": '{!! asset('/plugins/datatables.net/latino.json') !!}'
} ,
"lengthMenu": [5,10, 25, 50, 75 ],
"ajax":'{!! url('admin/list_user') !!}',
columns: [
{data: 'id' },
{data: 'username'},
{data: 'name',
render: function (data, type, row, meta) {
return row.name + ' ' + row.lastname;
}
},
{data: 'email'},
{data: 'role.name',
render: function(data, type, row, meta) {
var html = ''
if ( row.role.name == 'Administrador' )
{
html = '<span class="label label-danger" > <label style="width:80px;"> '+row.role.name+' </label></span>';
}else {
html = '<span class="label label-primary" > <label style="width:80px;"> '+row.role.name+' </label></span>';
}
return html;
}
}
}],
});
}
activar_tabla_users();
You are using server side to get table data. Don't call all() as it will get all.
Replace:
$users = User::all();
With:
$users = User::query();
This only renders the required data in data-table page.
And, don't use loop to get role. Use eager loading using with();
$users = User::query()->with('role');
$users = User::all();
$users->each(function ($users)
{
$users->role;
});
with this the following?
$users = User::with('role');
Datatable adds pagination options automatically. if you use all() it calls all the data from the table.
Another thing is did you checked that it takes 2/3sec to get data from the server or does it takes this time to format the data in the view?
replace
$users = User::all();
$users->each(function ($users)
{
$users->role;
});
with this:
$users = User::with('role')->get();
This will use one db request instead of over 1k requests (you were making a call for each user to get their role). If you display all 1300 users at once, only request the "page" you need with laravels built in pagination, https://laravel.com/docs/5.6/pagination#paginating-eloquent-results
I am using laravel 5.0
I am also using datatable jquery plugin to display grid.
Controller mehtod
public function index() {
$jobs = \App\Job::orderBy('created_at', 'DESC')->limit(1000)->get();
return View::make('jobs.index', ['jobs' => $jobs]);
}
The issue:
Right now I hard-coded the ->limit(1000) to 1000 jobs in datatable grid to display
it but i have more then 1000 records to display.
What I want?
I want to display 500 records with grid and then 500 records.
I am not sure if there is any call back data-table plugin function available?
I need a dynamic way to load next 500
NOTE:
I am not willing to us this solution of scrolling
https://datatables.net/extensions/scroller/examples/initialisation/server-side_processing.html
You can user ajax data source:
please visit : https://datatables.net/examples/ajax/objects.html
Example PHP Script:
// function will process the ajax request
public function getMembers(Request $request) {
$draw = $request->get('draw');
$start = $request->get('start');
$length = $request->get('length');
$search = (isset($filter['value']))? $filter['value'] : false;
$total_members = 1000; // get your total no of data;
$members = $this->methodToGetMembers($start, $length); //supply start and length of the table data
$data = array(
'draw' => $draw,
'recordsTotal' => $total_members,
'recordsFiltered' => $total_members,
'data' => $members,
);
echo json_encode($data);
}
Example JavaScript :
$('#all-member-table').DataTable( {
"processing": true,
"serverSide": true,
"ajax": {
url: base_url+"ajax/members"
},
"columns": [
{ data: '1' },
{ data: '2' },
{ data: '3' },
{ data: '4' },
{ data: '5' },
]
} );
Example HTML:
<table id="all-member-table">
<thead>
<tr>
<th>Column1</th>
<th>Column2</th>
<th>Column3</th>
<th>Column4</th>
<th>Column5</th>
</tr>
</thead>
</table>
I think above answer should be extended with search feature.
Update the answer;
$filter = $request->get('search');
$search = (isset($filter['value']))? $filter['value'] : false;
where('somecolumnonyourdb','like', '%'.$search.'%')
This works for me
You can use standard pagination:
$jobs = \App\Job::latest()->paginate(500);
Or create it manually.
Hello I need to do autocompletion to some cities i already have in my db
so my code is like this :
View
<input type="text" name="ville" id="ville" class="small" placeholder="Entrer la ville souhaité">
<script type="text/javascript">
$(function() {
$( "#ville" ).autocomplete({
source:'{!!URL::route('autocomplete')!!}',
minlength:1,
autoFocus:true,
select:function(e,ui)
{
$('#ville').val(ui.item.value);
}
});
});
</script>
Controller
class VilleController extends Controller
{
public function autocomplete(Request $request)
{
$term = $request->term;
$queries = DB::table('ville')
->where('libelle_ville', 'like', '%'.$term.'%')
->take(6)->get();
foreach ($queries as $query)
{
$results[] = ['id' => $query->id, 'value' => $query->libelle_ville]; //you can take custom values as you want
}
return response()->json($results);
}
}
Routes
Route::get('/autocomplete', array('as' => 'autocomplete', 'uses'=>'VilleController#autocomplete'));
It doesn't tells me that I have an error and it doesn't show me any completion either.
Debug json request with laravel is a bit difficult, I recommend you to download this package
https://github.com/ARCANEDEV/LogViewer
or manually open the laravel log in storage/logs/laravel.log and see whats happened
Thanks to Stack and EddyTheDove I found out that the error is that aucomplete is not a function so I have to remove the barkets and $function so it would be something like this in the script tag
<script type="text/javascript">
$( "#ville" ).autocomplete({
source:'{!!URL::route('autocomplete')!!}',
minlength:1,
autoFocus:true,
select:function(e,ui)
{
$('#ville').val(ui.item.value);
}
});
</script>
So in this app Drawing belongsTo Customer. I have datatable
<table id='drawing-table' class="table table-bordered table-hover">
<thead>
<tr>
<th>Drawing number</th>
<th>Customer</th>
</tr>
</thead>
</table>
which indicates $darwing->number and $customer->title. To load info I use yajra\Datatables\Datatables;.
Data is loaded with this JS method:
$(function () {
$('#drawing-table').DataTable({
processing: true,
serverSide: true,
ajax: '{{route('drawings.datatable')}}',
columns: [
{ data: 'number', name: 'number' },
{ data: 'customer.title', name: 'customer' },
]
});
});
And this Laravel method:
public function datatable()
{
$drawings = Drawing::select(array('drawings.id','drawings.number'));
return Datatables::of(Drawing::with('customer')->select('*'))->make(true);
}
QUESTIONS
How do I make datatable search window to work with $customer->title?
How do I display drawing number and customer title as link?
public function datatable()
{
//reference customer table
$drawings = DB::table('customers')
// join it with drawing table
->join('drawings', 'drawings.customer_id', '=', 'customers.id')
//select columns for new virtual table. ID columns must be renamed, because they have the same title
->select(['drawings.id AS drawing_id', 'drawings.number', 'customers.title', 'customers.id AS customer_id']);
// feed new virtual table to datatables and let it preform rest of the query (like, limit, skip, order etc.)
return Datatables::of($drawings)
->editColumn('title', function($drawings) {
return '' . $drawings->title . '';
})
->editColumn('number', function($drawings) {
return '' . $drawings->number . '';
})
->make(true);
}
Spent many hours trying to figure it out, hope it saves someone time.
http://datatables.yajrabox.com/fluent/joins
I'm not really sure about your first question. Datatables search window will search all the content. Do you want to make it specific to just 1 column?
To answer your second question, you can edit the column output. Try this
$drawings = Drawing::select(array('drawings.id','drawings.number'));
return Datatables::of(Drawing::with('customer')->select('*'))
->editColumn('customer', function($drawings) {
return '' . $drawings->customer . '';
})
->make(true);
Edit
To achieve the search that you want, You'll want to do something like this:
public function datatable(Request $request)
{
$drawings = Drawing::select(array('drawings.id','drawings.number'));
return Datatables::of(Drawing::with('customer')->select('*'))
->filter(function ($query) use ($request) {
if ($request->has('name')) {
$query->where('customer.customer_name', 'like', "%{$request->get('name')}%");
}
})
->editColumn('customer', function($drawings) {
return '' . $drawings->customer->customer_name . '';
})
->make(true);
}
Then, in your JS
$(function () {
$('#drawing-table').DataTable({
processing: true,
serverSide: true,
ajax: {
url: '{{route('drawings.datatable')}}',
data: function (d) {
d.name = $('input[name=name]').val();
}
},
columns: [
{ data: 'number', name: 'number' },
{ data: 'customer.title', name: 'customer' },
]
});
});
This is untested, but should achieve what you want.
you may also use elequent relationships with yajra here is the example code.
$sub_sectors = Sector::where('parent_id', '>', 0)->with('parent')->latest()->get();
$sub_sectors->each(function($sub_sectors){
$sub_sectors->sector = $sub_sectors->parent->title['en'];
});
in this example you can get sector against sub sector with each method you can get sector name and now you can display sector in your yajra table