I would like to know if it will be possible to send HTML (containing multiple charts) via an AJAX method and then render them. I don't seem to have much luck and I can't find much online doing it with this approach. I would appreciate any input.
Here is my AJAX function:
$.ajax({
url: "/admin/expensereport/getgraphs",
type: 'GET',
data: { dateFrom: $("#dateFrom").val(), dateTo:$("#dateTo").val(),
expenseBuildingType: $("input[name='expenseBuildingType']:checked").val(),
expenseScheduledType: $("input[name='expenseScheduledType']:checked").val()},
cache: false,
success: function(data) {
$('#graphsDiv').html(data);
},
Here is my PHP Laravel function with one of 3 graphs included:
$chartCategories = app()->chartjs
->name('chartCategories')
->type('pie')
->size(['width' => 400, 'height' => 200])
->labels(['Label x', 'Label y'])
->datasets([
[
'backgroundColor' => ['#FF6384', '#36A2EB'],
'hoverBackgroundColor' => ['#FF6384', '#36A2EB'],
'data' => [69, 59]
]
])
->options([]);
$view = View::make('partials.CPM.expensereportgraphs', [
'chartCategories' => $chartCategories,
]);
Here is an extract of my view:
<div class="col-md-6">
<h4>Top 10 Categories</h4>
{!! $chartCategories->render() !!}
</div>
I managed to solve the problem by taking another route. I created the charts in the html page file and then sent the data via AJAX. I suppose this method is actually much better.
Related
First of, I used the javascript example here, I grasp the basic and altered it on my own.
https://datatables.net/examples/data_sources/server_side
I have a couple of problems to deal with, those are:
Once the datatable load on page load, it successfully retrieves the default data BUT it doesn't apply the proper pagination and length view. Say I have 100 default data, it all fully shown, rather than slicing it by 10 which is the default length of dataTable. Also in pagination, it generates 1~10 paginating buttons but it doesn't work since all 100 records are already displayed in page 1.
Upon using the search, it successfully retrieves the correct data BUT the dataTable doesn't render the newly set of data to it, contradicting to the sample above.
This is my dataTable script:
$('#invoice-history').DataTable({
processing: true,
serverSide: true,
searchDelay: 1000,
ajax: {
url: '/stock-sales/search',
type: 'POST',
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
},
columns: [
{ data: 'ss_id' },
{
render: function ( data, type, row, meta ) {
return row.patient_last_name + ', ' + row.patient_first_name;
}
},
{ data: 'grandtotal_current' },
{ data: 'created_at' },
{
render: function ( data, type, row, meta ) {
return '<i class="fa fa-print"></i> Print';
}
},
{
render: function ( data, type, row, meta ) {
return '<i class="fa fa-undo"></i> Return';
}
}
],
columnDefs: [ {
targets: [ 4, 5 ],
orderable: false
} ],
language: {
emptyTable: '<center><span class="label label-danger">NO INVOICE RECORDS FOUND</span></center>',
zeroRecords: '<center><span class="label label-danger">NO MATCHING RECORDS FOUND</span></center>'
},
order: [[ 3, 'desc' ]]
});
On the server-side I use Laravel framework:
public function search(Request $request)
{
$transactions = StockSales::getAllByDepartment(Auth::user()->employee->department->id, $request->search['value']);
return array(
"draw" => 1,
"recordsTotal" => count($transactions),
"recordsFiltered" => count($transactions),
"data" => $transactions
);
}
I don't want to get the original total number of records before filter so I set it the same, I don't think it has something to do with pagination of the resulting data as I have also tried to hardcoded a higher recordsTotal value.
EDIT:
actually made the searching redraw the datatable by returning the draw interger from the ajax
public function search(Request $request)
{
$transactions = StockSales::getAllByDepartment(Auth::user()->employee->department->id, $request->search['value']);
return array(
"draw" => $request->draw, //from fixed 1
"recordsTotal" => count($transactions),
"recordsFiltered" => count($transactions),
"data" => $transactions
);
}
Try the "pageLength" attribute in your datatable initialization to specify the number of rows per page.
"pageLength": 10,
Server side:
You need to use the 'length' and 'start' parameters passed by the ajax request for server-side pagination. Take a look at all the parameters used by datatables in server-side processing.
$limit = $request->length;
$start = $request->start;
Thus, you can fine-tune your controller method to something like:
$transactions = StockSales::getAllByDepartment(Auth::user()->employee->department->id,
$request->search['value'])
->offset($start)
->limit($limit);
return array(
"draw" => $request->draw, //from fixed 1
"recordsTotal" => count($transactions),
"recordsFiltered" => count($transactions),
"data" => $transactions
);
Problem here is you misunderstood about server side processing serverSide: true Due to https://datatables.net/examples/data_sources/server_side
With server-side processing enabled, all paging, searching, ordering actions that DataTables performs are handed off to a server where an SQL engine (or similar) can perform these actions on the large data set (after all, that's what the database engine is designed for!). As such, each draw of the table will result in a new Ajax request being made to get the required data.
In your case you return all data on ajax called and think datatable will process pagination, ordering for you. That is wrong, you must do it by yourself on ajax called
However, 100 records are not large and you can fix your problem by
serverSide: false
Change like that, datatable will load all data from ajax source and process for you
I'm using bootstrap-table with inline editable plugin to create a bootstrap table for a list of laptop. My goal was to apply changes to my csv file after users make changes to the table like this example (Product Category: Laptop)
I have created a javascript function below to send Ajax data to my Django server.
// ajax to server
$(function () {
$( "#table" ).on("click" , 'button',function(event){
var selected_item = getSelectedRow(); //this will return selected row object
console.log(selected_item);
$.ajax({
type: "post",
url: '/update/',
data: {
'item': JSON.stringify(selected_item)
},
success: function (data) {
alert('success');
}
});
});
});
Below is the output from my console log
(pcategory has been changed to Laptop2)
However, when I try to get the data from Django. It gave me the output below, which (pcategory was not changed to Laptop2)
{'webcam': 'WebCam', 'lannum': '2', 'condition': 'Refurbished', 'video2': 'GM204M [GeForce GTX 970M]', 'memorybanks': '8G 2133MHz/8G 2133MHz/', 'cpus': '1', 'customernotes': '', 'lanmodels': 'Killer E2400 Gigabit Ethernet Controller/WLAN QCA6174 802.11ac Wireless Network Adapter/', 'internalnotes': '', 'pline': 'Alienware', 'sku': 'LEN-LT-TPEdge-03BV001', 'cddvd': '', 'hddcapacity': '0.0G', 'coresthreads': '4 | 8', 'sound': 'Sound-Yes', 'pmodel': '15 R2', 'resolution': '1230x1000', 'ptype': 'Minitower', 'grade': 'GradeB:R2-Ready for Resale', 'touchscreen': 'Yes', 'hddqty': '0', 'pcategory': 'Laptop', 'processor': 'i7-6700HQ 2.60GHz', 'memory': '16G', 'serialnum': 'BFYNM72', 'video1': 'GM204M [GeForce GTX 970M]', 'hddmodels': '', 'manufacturer': 'Alienware', 'motherboard': 'Alienware 15 R2', 'batch': '03BV', 'hddserialnum': ''}
My Django view function:
#csrf_exempt
def update_page(request):
file_path = os.path.join(CSV_BASE_DIR, CURRENT_BATCH, '{}.csv'.format(CURRENT_BATCH))
if request.method == 'POST':
item = json.loads(request.POST.get('item'))
pprint.pprint(item)
overwrite_csv(file_path,item)
else:
print('no data back!')
return HttpResponse('yes')
I noticed when I changed the input again. The value will get changed to laptop2. It seems like it didn't save the value in the way I expect it to be. I'm wondering is there any way my Django server would get the same value as soon as I click on the check mark?
Thank you all in advanced.
Make sure the data source is Same for both listing and updating.
I have the following javascript code
$(".order-event-btn").click(function(e) {
$.ajax({
url: "URL",
type: "POST",
data: {
eventId: $(e.target).attr('data-event-id'),
},
success: function(data) {
//Some code
},
error: function(data) {
//Some code
},
});
});
I include this script using "BookAsset".
Here
url: "URL",
I need URL to the action "book-event" in the controller Book.
On the server, I can do this:
Url::to('/book/book-event')
But how do I get URL on client side?
There is an solution:
1. js file include via BookAsset.
2. in view file I register bundle:
\frontend\assets\BookAsset::register($this);
3. in view file define a bookEventURL variable. Now it is available in the js-file.
$this->registerJs('var bookEventURL = ' . Url::to('/book/book-event') . ';');
But I do not like this solution.
What will happen when I use this script in many views. I have to define a variable bookEventURL in each view?
My Question. Is it possible to bind js-variables to my BookAsset. When I register my BookAsset in the view, in page source code automatically insert next code:
<script>var bookEventURL = "http://example.com/book-event/";</script>
A proper way of doing this is to add the needed information in your button tag, e.g. :
<?= Button::widget([
'label' => 'Order',
'options' => [
'class' => 'order-event-btn',
'data' => [
'url' => Url::to(['book/book-event']),
],
],
]) ?>
And in your js code :
$(".order-event-btn").click(function(e) {
var url = $(this).data('url');
// ...
});
But if you really want to "bind js-variables" to your BookAsset, you could simply override register() :
public static function register($view)
{
parent::register($view);
$view->registerJs('var bookEventURL = ' . json_encode(Url::to(['book/book-event'])) . ';');
}
If you wanna use it in different places of your application than I guess you should place it in the layout.
Ok, I feel like I'm going crazy here. I'm using the select2 jquery plugin (version 4), and retrieving data via ajax. So you can type in a name, and it will return that contact information. But I also want to return what organization that contact is a part of.
Here is my select2 initialization:
$('#contact_id').select2({
ajax: {
url: 'example.com/contacts/select',
dataType: 'json',
delay: 250,
data: function (params) {
return {
q: params.term,
page: params.page
};
},
processResults: function (data) {
return {
results: data
};
},
cache: true
},
minimumInputLength: 3,
maximumSelectionLength: 1
});
And here is the data I'm returning (laravel framework):
foreach($contacts as $con) {
$results[] = [
'id' => $con->contact_id,
'text' => $con->full_name,
'org' => [
'org_id' => $con->organization_id,
'org_name' => $con->org_name
]
];
}
return response()->json($results);
So isn't 'org' supposed to be attached to either the created option or select element by select2? So I could do something like $('#contact_id').select2().find(':selected').data('data').org or $('#contact_id').select2().data('data').org or something like that?
Idealistically, this would look like:
<select>
<option value="43" data-org="{org_id:377, org_name:'Galactic Empire'}">Darth Vader</option>
</select>
I swear I confirmed this worked last week, but now it's completely ignoring that org property. I have confirmed that the json data being returned does include org with the proper org_id and org_name. I haven't been able to dig anything up online, only this snippet of documentation:
The id and text properties are required on each object, and these are the properties that Select2 uses for the internal data objects. Any additional paramters passed in with data objects will be included on the data objects that Select2 exposes.
So can anyone help me with this? I've already wasted a couple hours on this.
EDIT: Since I haven't gotten any responses, my current plan is to use the processResults callback to spawn hidden input fields or JSON blocks that I will reference later in my code. I feel like this is a hacky solution given the situation, but if there's no other way, that's what I'll do. I'd rather that than do another ajax call to get the organization. When I get around to implementing it, I'll post my solution.
Can't comment for now (low reputation).. so... answering to slick:
Including additional data (v4.0):
processResults: function (data) {
data = data.map(function (item) {
return {
id: item.id_field,
text: item.text_field,
otherfield: item.otherfield
};
});
return { results: data };
}
Reading the data:
var data=$('#contact_id').select2('data')[0];
console.log(data.otherfield);
Can't remember what I was doing wrong, but with processResults(data), data contains the full response. In my implementation below, I access this info when an item is selected:
$('#select2-box').select2({
placeholder: 'Search Existing Contacts',
ajax: {
url: '/contacts/typeahead',
dataType: 'json',
delay: 250,
data: function(params){
return {
q: params.term,
type: '',
suggestions: 1
};
},
processResults: function(data, params){
//Send the data back
return {
results: data
};
}
},
minimumInputLength: 2
}).on('select2:select', function(event) {
// This is how I got ahold of the data
var contact = event.params.data;
// contact.suggestions ...
// contact.organization_id ...
});
// Data I was returning
[
{
"id":36167, // ID USED IN SELECT2
"avatar":null,
"organization_id":28037,
"text":"John Cena - WWE", // TEXT SHOWN IN SELECT2
"suggestions":[
{
"id":28037,
"text":"WWE",
"avatar":null
},
{
"id":21509,
"text":"Kurt Angle",
"avatar":null
},
{
"id":126,
"text":"Mark Calaway",
"avatar":null
},
{
"id":129,
"text":"Ricky Steamboat",
"avatar":null
},
{
"id":131,
"text":"Brock Lesnar",
"avatar":null
}
]
}
]
I am trying to store an entry in a database after a click using an ajax call to a route that calls a controller function in javascript (in Laravel 4).
I have a resource "artists", that is controlled by an "ArtistsController". The view where I am making the call is called "show.blade.php" in an "artists" directory (i.e. the page shows different artists: artists/1, artists/2, etc...).
I also have a table called "fanartists", where I want to store this data. Basically, when a user clicks a button on a specific artist's page, I want the relationship to be stored in this table.
Here is the relevant code:
show.blade.php:
<script>
window.fbAsyncInit = function() {
FB.init({
appId : '*****************',
status : true,
cookie : true,
oauth : true
//xfbml : true
});
$( '.opener' ).click(function() {
FB.ui({
method: 'feed',
link: 'http://crowdtest.dev:8888/artists/',
name: 'Hello',
caption: 'Hello',
description: 'Hello!'
});
request = $.ajax({
url: "/artists/fbclick",
type: "post",
data: serialised data
});
});
};
</script>
<a class="add-list-button-no-margin opener" style="color: white; font:14px / 14px 'DINMedium','Helvetica Neue',Helvetica,Arial,sans-serif;">Play my city</a>
ArtistsController:
public function fbclick($id) {
$artist = Artist::find($id);
$fanartist = new Fanartist;
$fanartist->artist_id = $artist->id; //the id of the current artist page (i.e. artists/1, id=1)
$fanartist->fan_id = Auth::user()->id;
$fanartist->save();
}
routes:
Route::get('/artists/fbclick', array('uses' => 'ArtistsController#fbclick'));
When I include the ajax request, the FB feed does not pop up. When I remove it, it does. Also, it is not storing the data in the database like I want it to.
Do you see anything wrong here? Your help is much appreciated. Thank you.
I see some slight mistakes in your script.
In your ajax request you are using post as the method, but you have defined your route as get so either change your route to post or change ajax method to get. I will go with post route so your new route is Route::post('/artists/fbclick', array('uses' => 'ArtistsController#fbclick')');
And ajax data field should be in json format, so now you ajax request will look some what like this
$.ajax({
url: "/artists/fbclick",
type: "post",
data: {field_name :'data'}
});
Finally coming to you controller function, with silght changes
public function fbclick() {
// $artist = Artist::find($id);
$id=Input::get('field_name'); //field_name is the field name from your Json data
$fanartist = new Fanartist;
$fanartist->artist_id = $id; //the id of the current artist page (i.e. artists/1, id=1)
$fanartist->fan_id = Auth::user()->id;
$fanartist->save();
}
Everything should work now