I have a page that contains two tabs. Tab one contains Kendo bar charts. Tab 2 contains a kendo grid for search results and two tabs that contain 1 kendo grid each for detail information. The "Change" event of the search results grid makes an ajax call to update the 2 details grids with details of the item selected. I want the 2 details grids to be sortable. But when I click on a column to sort the data, the entire page refreshes and takes me back to the first tab that contains the kendo bar charts. The search results grid is sortable and works as expected. It doesn't refresh the entire page when I click on a column to sort by. So, how do i allow the 2 details grids to resort without refreshing the page?
NOTE: I have also noticed, when the screen refreshes due to sorting, my controller action isn't being called. So, its refreshing the screen but not actually re-executing my controller code - not sure if that helps or not.
HTML that gets replaced by AJAX call:
<div id="groupDetails">
<div class="panel-body">
<ul class="nav nav-tabs" id="detailsTabs">
<li class="active">Diagnosis</li>
<li>Procedure</li>
</ul>
<div class="tab-content">
<div class="tab-pane active" id="tab-diagnosis" />
<div class="tab-pane" id="tab-procedure" />
</div>
</div>
</div>
Search Results Grid:
$("#searchResults").kendoGrid({
dataSource: { data: mdl,},
selectable: true,
sortable: true,
pageable: false,
change: function(e) {
var itm = this.dataSource.view()[this.select().index()];
$.ajax({
type: "GET",
url: "#Url.Action("GroupDetails", "Analytics")",
data: {idx: itm.Idx, name: itm.Name},
success: function (r) {
groupDetails.html('');
groupDetails.html(r);
}
});
}
});
AJAX result:
<div class="panel-body">
<ul class="nav nav-tabs" id="myTab2">
<li class="active">Diagnosis</li>
<li>Procedure</li>
</ul>
<div class="tab-content">
<h1>Service Line: #Model.Name</h1>
<div class="tab-pane active" id="tab-diagnosis">
#Html.Kendo().Grid(Model.DiagnosisDetailsResults).Name("DiagDetailsResults").Columns(
column =>
{
column.Bound(c => c.Name).Title("Description");
column.Bound(c => c.TotalCharged).Title("Charged").Format("{0:c0}").Width(175);
column.Bound(c => c.Totalpayments).Title("Revenue").Format("{0:c0}").Width(175);
}).Sortable().Scrollable().Selectable(selectable => selectable.Mode(GridSelectionMode.Single).Type(GridSelectionType.Row)).DataSource(dataSource => dataSource.Server().Model(model => model.Id(item => item.Idx)))
</div>
<div class="tab-pane" id="tab-procedure">
#Html.Kendo().Grid(Model.ProcedureDetailsResults).Name("ProcedureDetailsResults").Columns(
column =>
{
column.Bound(c => c.Name).Title("Description");
column.Bound(c => c.TotalCharged).Title("Charged").Format("{0:c0}").Width(175);
column.Bound(c => c.Totalpayments).Title("Revenue").Format("{0:c0}").Width(175);
}).Sortable().Scrollable().Selectable(selectable => selectable.Mode(GridSelectionMode.Single).Type(GridSelectionType.Row)).DataSource(dataSource => dataSource.Server().Model(model => model.Id(item => item.Idx)))
</div>
</div>
</div>
That happens because your details grids are both server binding grids, so of course when you try to sort the grid, a request will be sent to the server and the page will be refreshed. You need to change the data source to Ajax if you don't want the sort to refresh the page.
<div class="tab-pane active" id="tab-diagnosis">
#Html.Kendo().Grid(Model.DiagnosisDetailsResults).Name("DiagDetailsResults").Columns(
column =>
{
column.Bound(c => c.Name).Title("Description");
column.Bound(c => c.TotalCharged).Title("Charged").Format("{0:c0}").Width(175);
column.Bound(c => c.Totalpayments).Title("Revenue").Format("{0:c0}").Width(175);
}).Sortable().Scrollable().Selectable(selectable => selectable.Mode(GridSelectionMode.Single).Type(GridSelectionType.Row)).DataSource(dataSource => dataSource.Ajax().ServerOperation(false).Model(model => model.Id(item => item.Idx)))
</div>
<div class="tab-pane" id="tab-procedure">
#Html.Kendo().Grid(Model.ProcedureDetailsResults).Name("ProcedureDetailsResults").Columns(
column =>
{
column.Bound(c => c.Name).Title("Description");
column.Bound(c => c.TotalCharged).Title("Charged").Format("{0:c0}").Width(175);
column.Bound(c => c.Totalpayments).Title("Revenue").Format("{0:c0}").Width(175);
}).Sortable().Scrollable().Selectable(selectable => selectable.Mode(GridSelectionMode.Single).Type(GridSelectionType.Row)).DataSource(dataSource => dataSource.Ajax().ServerOperation(false).Model(model => model.Id(item => item.Idx)))
</div>
By the way, why are you using Razor for the details grids, but not for the main one? Be consistent.
Related
I am trying to use the snappy library with wkhtmltopdf to render a chart (LavaChart) on a generated PDF but I have not been able. The PDF generates fine but the chart does not show. If the view is not converted to PDF, the Chart is rendered as expected.
Below is my code for the LavaChart and Snappy.
The Chart Part
$chart = Lava::ColumnChart('Performance', $table, [
'title' => 'Performance Chart',
'png' => true,
'animation' => [
'startup' => true,
'easing' => 'inAndOut'
],
'titleTextStyle' => [
'fontName' => 'Arial',
'fontColor' => 'blue'
],
'legend' => [
'position' => 'top'
],
'vAxis' => [
'title' => 'Total Score'
],
'hAxis' => [
'title' => 'Class'
],
'events' => [
'ready' => 'getImageCallback'
],
'colors' => ['#3366CC','#DC2912', '#FF9900']
]);
The Snappy Part
$pdf = PDF::loadView('print.charts')->setPaper('portrait');
$pdf->setOption('enable-javascript', true);
$pdf->setOption('javascript-delay', 10000);
$pdf->setOption('no-stop-slow-scripts', true);
$pdf->setOption('page-size', 'A4');
$pdf->setOption('margin-left', 0);
$pdf->setOption('margin-right', 0);
$pdf->setOption('margin-top', 0);
$pdf->setOption('margin-bottom', 0);
$pdf->setOption('lowquality', false);
$pdf->setTimeout(1500);
$pdf->setOption('disable-smart-shrinking', true);
The View Part
<script type="text/javascript">
function getImageCallback (event, chart) {
console.log(chart.getImageURI());
}
</script>
<div id="chart" style="margin: 10px; height: 200px; width: 50%;"></div>
{!! Lava::render('ColumnChart', 'Performance', 'chart') !!}
Since the chart renders as expected when the view is not converted to pdf, I have reasons to believe the wkhtmltopdf does not execute the javascript has expected in the pdf version. I have the latest wkhtmltopdfinstalled but still no luck.
Library Version:
barryvdh/laravel-snappy: ^0.4.3
khill/lavacharts: 3.0.*
Any help will be appreciated, thanks.
I can show with a simple example, At first I have shown the chart on browser, The chart example is taken from Lavacharts docs(you can use yours). Keep a Note on
events with callback getImageCallback.
public function index(){
$lava = new Lavacharts;
$data = $lava->DataTable();
$data->addDateColumn('Day of Month')
->addNumberColumn('Projected')
->addNumberColumn('Official');
// Random Data For Example
for ($a = 1; $a < 20; $a++) {
$rowData = [
"2020-10-$a", rand(800,1000), rand(800,1000)
];
$data->addRow($rowData);
}
$lava->LineChart('Stocks', $data, [
'elementId' => 'stocks-div',
'title' => 'Stock Market Trends',
'animation' => [
'startup' => true,
'easing' => 'inAndOut'
],
'colors' => ['blue', '#F4C1D8'],
'events' => [
'ready' => 'getImageCallback'
]
]);
return view('charts-view', ['lava' => $lava]);
}
In view charts-view,
<div id="stocks-div">
<?= $lava->render('LineChart', 'Stocks', 'stocks-div'); ?>
</div>
<form action="{{ url('export-pdf') }}" method="post">
#csrf
<div class="form-group">
<input type="hidden" name="exportpdf" id="exportPDF">
<button class="btn btn-info" type="submit">Export as PDF</button>
</div>
</form>
<script type="text/javascript">
function getImageCallback (event, chart) {
console.log(chart.getImageURI());
document.getElementById("exportPDF").value = chart.getImageURI();
}
</script>
note the function name in script must be same as the value set for ready key in events in the controller. Upto this step you have done as well. I have passed the result obtained by as a hidden input field and posted the form to the controller.You can see in the diagram button export as PDF.
The url export-pdf calls the controller function exportPdf which willfinally generate the PDF. You need to pass the image (obtained as data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAB .....) to the controller to pass it to the view as image.
In exportPdf,
public function exportPdf(Request $request){
$imageData = $request->get('exportpdf');
$pdf = SnappyPDF::loadView('export-pdf', ['imageData' => $imageData])->setPaper('a4')->setOrientation('portrait');
$pdf->setOption('lowquality', false);
$pdf->setTimeout(1500);
$pdf->setOption('disable-smart-shrinking', true);
return $pdf->download('stock-market.pdf');
}
The export-pdf blade view
<!DOCTYPE html>
<html lang="en">
<head>
<title>Stock Market</title>
</head>
<body>
<div class="container">
<div class="col">
<h2>Stock Market Detail</h2>
</div>
<div class="col">
<h4>Oct 2020</h4>
</div>
</div>
<img src="{{ $imageData }}" alt="image" width="720" height="230">
</body>
</html>
The final PDF obtained looks like,
I''m new to laravel and vue.js. Need help :)
I have 2 tables. The purchase and the remittance. In my project, I have already STORED some data to the purchase table. But the remittance_id has no data yet (unsigned null by default and data should be stored after update).
So, for example. I checked table row 1 and table row 2. ((2) [{…}, {…}, ob: Observer] array list)
And by clicking my GENERATE REMITTANCE BUTTON, It will show a MODAL. And I have to input 2 fields (sample_date and sample_no) and it will automatically update the remittance_id
ON SUBMIT, my purchase table the 2 selected rows will now have updated remittance_id of 1(for example). my remittance table will now create sample_date, sample_no and remittance_id(1)
<vs-prompt
#accept="generateRemittance"
:is-valid="validDate"
:active.sync="popupRemit"
accept-text= "Generate" title="Generate" color="warning">
<div class="con-exemple-prompt">
Enter details to <b>continue</b>.
<div class="vx-col w-full mb-base">
<div class="vx-row mb-6">
<div class="vx-col sm:w-1/3 w-full">
<span>SAMPLE DATE:</span>
</div>
<div class="vx-col sm:w-2/3 w-full">
<vs-input name="sample_date" class="w-full" type="date" v-model="sample_date"/>
</div>
</div>
<div class="vx-row mb-6">
<div class="vx-col sm:w-1/3 w-full">
<span>SAMPLE NO</span>
</div>
<div class="vx-col sm:w-2/3 w-full">
<vs-input name="sample_no" class="w-full" v-model="sample_no"/>
</div>
</div>
</div>
</div>
</vs-prompt>
<vs-button #click="addRemit" type="filled" color="primary" icon-pack="feather" icon="icon-download">GENERATE REMITTANCE</vs-button>
my method
methods: {
addRemit(){
this.popupRemit = true
},
generateRemittance () {
this.$nextTick().then(result => {
if (result) {
this.$vs.loading();
axios
.post("/api/my/sample/url/", this.form)
.then(res => {
this.$vs.loading.close();
Fire.$emit('AfterSave');
})
.catch(error => {
this.$vs.loading.close();
this.$vs.notify({
title: "Error",
text: error.response.data.errors || error.response.data.message,
iconPack: "feather",
icon: "icon-alert-circle",
color: "danger"
});
});
}else {
this.$validator.reset()
this.$validator.resume()
console.log(this.$validator.errors);
this.$vs.notify({
title: "Error",
text: this.$validator.errors,
iconPack: "feather",
icon: "icon-alert-circle",
color: "danger"
});
}
});
},
thanks.
Seems like your purchase table belongsTo the remittance table, so you'll want to create the remittance model first and save the purchase model after, you can do this with a tap:
tap(Remittance::create($request->only(['sample_no', 'sample_date'])), function (Remittance $remittance) use ($purchase) {
$remittance->purchase()->save($purchase);
});
Here tap is giving us access to the created Remittance model in the callback, where we're then saving the one-to-one relationship.
I'm new in components and alpine in laravel. I have data from controller $positions.
$positions = [
['id' => 1, 'content' => 'king'],
['id' => 2, 'content' => 'lord']
];
When I pass it to laravel blade. here is my code
<div class="row">
<div class="col">
#foreach($list as $key => $position)
<x-list :position="$position"/>
#endforeach
</div>
</div>
I have component name it <x-list/> with a prop position, and here is the code of my x-list component
<div class="red w-60 mb-1">
<div x-data="positionData()" class="relative">
<button #click="submit()" class="p-2">Submit</button>
</div>
</div>
<script>;
var position = #json($position);
function positionData() {
return {
submit() {
console.log(position);
},
};
}
</script>
It is just very simple code but when I click the submit button, the data I get is the last position
from the list ['id' => 2, 'content' => 'lord'], even I click position 1 the data I get is still position 2 data. I don't know what happen now. I try to search it in google to fix it but I can't find the right answer on this.
I think the issue in this case is that the positionData function is being overwritten on each iteration of x-list (since each of the components is creating a new window.positionData function).
To solve it you could do:
<div class="red w-60 mb-1">
<div x-data="positionData(#json($position))" class="relative">
<button #click="submit()" class="p-2">Submit</button>
</div>
</div>
<script>;
function positionData(position) {
return {
submit() {
console.log(position);
},
};
}
</script>
Specifically, you should probably move the <script></script> out of the x-list component so that it doesn't get re-created for each component (it should only be added to the page once).
I want to display all my charts on the same view I used lavacharts I gave different no to my charts but in the view it shows me that the last chart in the controller.
Controller code:
function l()
{
$lava = new Lavacharts; // See note below for Laravel
$reasons = \Lava::DataTable();
$abs=Absencecollab::all();
$r=$abs->count();
$absm=Absencecollab::where('motif','maladie');
$tm=$absm->count();
$absc=Absencecollab::where('motif','conge');
$tc=$absc->count();
$absnj=Absencecollab::whereNull('motif');
$tnj=$absnj->count();
$pm=($tm100)/$r;
$pc=($tc100)/$r;
$pnj=($tnj100)/$r;
$reasons->addStringColumn('Reasons')
->addNumberColumn('Percent')
->addRow(['Maladie',$pm ])
->addRow(['Conge',$pc])
->addRow(['Absence non justifiée',$pnj]);
\Lava::PieChart('IMDB', $reasons, [
'title' => 'Abscences collaborateurs par motif',
'is3D' => true,
'slices' => [
['offset' => 0.2],
['offset' => 0.25],
['offset' => 0.3]
]
]);
$reasons1 = \Lava::DataTable();
$abs1=Absence::all();
$r1=$abs1->count();
$absm1=Absence::where('motif','maladie');
$tm1=$absm1->count();
$absc1=Absence::where('motif','conge');
$tc1=$absc1->count();
$absnj1=Absencecollab::whereNull('motif');
$tnj1=$absnj1->count();
$pm1=($tm1100)/$r;
$pc1=($tc1100)/$r;
$pnj1=($tnj1*100)/$r;
$reasons1->addStringColumn('Reasons')
->addNumberColumn('Percent')
->addRow(['Maladie',$pm1 ])
->addRow(['Congé parents',$pc1])
->addRow(['Absence non justifiée',$pnj1]);
\Lava::PieChart('abse', $reasons1, [
'title' => 'Abscences enfants par motif',
'is3D' => true,
'slices' => [
['offset' => 0.2],
['offset' => 0.25],
['offset' => 0.3]
]
]);
return view('statistiquesg');
view code
#piechart('IMDB', 'chart-div')
<canvas id="line" height="300" width="450"></canvas>
</div>
</section>
</div>
<!-- Bar -->
<div class="col-lg-6">
<section class="panel">
<header class="panel-heading">
Absence enfants
</header>
<div class="panel-body text-center" id="chart-div">
#piechart('abse', 'chart-div')
<canvas id="bar" height="300" width="500"></canvas>
</div>
</section>
</div>
The second parameter of #piechart is the ID of the div, both pie charts are using the chart-div id.
Kendo-grid search box in toolbar in mvc with razor syntax,
I am facing i need toolbar in which searching box , this searching box search into grid data.
Just copy and paste this code bind with mvc model and custom button(CRUD) and search box in toolbar in kendo grid template
<div>
#(Html.Kendo().Grid(Model)
.Name("DiagnosisTestGrid")
.Columns(columns =>
{
columns.Bound(c => c.Description).Title("Description");
columns.Bound(c => c.Cost).Title("Cost");
columns.Bound(c => c.CostingRequired).Title("Cost Req.");
columns.Bound(c => c.DxTestId).ClientTemplate(#"
<a href='/DiagnosisTest/Details/#=DxTestId#' class = 'dialog-window'>Detail</a> |
<a href='/DiagnosisTest/Edit/#=DxTestId#' class = 'dialog-window' >Edit</a> |
<a href='/DiagnosisTest/Delete/#=DxTestId#' class = 'dialog-window'>Delete</a>
").Title("");
})
.ToolBar(toolbar =>
{
toolbar.Template(#<text>
<div class="toolbar">
<div class="row">
<div class="col-md-4">
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-search" aria-hidden="true"></span></span>
<input type="text" class="form-control" id='FieldFilter' placeholder="Search for...">
<span class="input-group-btn">
<button class="btn btn-default" type="button"><span class="glyphicon glyphicon-refresh" aria-hidden="true"></span></button>
</span>
</div>
</div>
</div>
</div>
</text>);
})
.Resizable(resizing => resizing.Columns(true))
.Sortable(sorting => sorting.Enabled(true))
.Reorderable(reorder => reorder.Columns(true))
.Pageable()
.DataSource(dataSource => dataSource
.Ajax()
.PageSize(5)
.ServerOperation(false)
))
</div>
Script for search box. and filter grid items
<script>
$(document).ready(function () {
$("#FieldFilter").keyup(function () {
var value = $("#FieldFilter").val();
grid = $("#DiagnosisTestGrid").data("kendoGrid");
if (value) {
grid.dataSource.filter({ field: "Description", operator: "contains", value: value });
} else {
grid.dataSource.filter({});
}
});
});
I know this is a bit of an old question now but it seems like the accepted answer is quite limited. This is how I got my searchbox added into the toolbar.
.ToolBar(toolBar => toolBar.Template(#<text><input class='k-textbox' value="Search..." onfocus="if (this.value=='Search...') this.value='';" onblur="this.value = this.value==''?'Search...':this.value;" id='searchbox'/></text>))
Then the script
<script type="text/javascript">
function addSearch() {
return { searchbox: $('#searchbox').val() };
}
$('#searchbox').keyup(function () {
$('#gridWorkflows').data('kendoGrid').dataSource.read();
});
</script>
This seems a bit simpler that what you are using currently.
Hope it helps.