I have a Laravel application where I create a page layout, adding a table to it as a "content" variable (pretty much all from tutorials I found). Here's the controller action:
public function getMain() {
$js_config = Category::all();
$resources = Resource::all()->take(100);
$this->layout->content = View::make('categories.show')->with('js_config', $js_config)->with('resources', $resources);
}
This uses the main layout template and inserts this table using the content variable:
<table class="table table-striped table-bordered">
<thead>
<tr>
<td>ID</td>
<td>Name</td>
</tr>
</thead>
<tbody>
#foreach($resources as $key => $value)
<tr>
<td>{{ $value->id }}</td>
<td>{{ $value->title }}</td>
</tr>
#endforeach
</tbody>
</table>
But then comes the problem: I have a jstree where the user can select nodes, triggering a jQuery method:
$('#jstree2').on("changed.jstree", function (e, data) {
console.log(data.selected);
$.get("filter", { category: data.selected })
.done(function (resultdata) {
//Test only, this returns the data wanted in json, which I stringify just to display in test
alert("Data Loaded: " + JSON.stringify(resultdata));
});
});
The jQuery calls this action method in the controller:
public function getFilter()
{
$input = Input::get('category.0');
$categories = Category::find($input);
//category is the name from the model below
return Response::json(array(
'error' => false,
'category' => $categories->toArray()),
200
);
}
(The reason there's an array as input is I eventually want to be able to allow picking multiple nodes in the tree)
This action gets the data from the DB correctly and returns it as json. The callback in the jQuery above then alerts this at the moment, just as a test.
But what I really want to do, of course, is to repopulate the table. Now, as you can see I have used Bootstrap to create a pretty table and all, and I just want to be able to let the user repopulate it at will, without refreshing the page.
But I don't know how to do that, except by painstakingly recreate this table in some sort of string return value, but that doesn't seem like a good idea.
I'm hoping there's some way of passing the return value back to the view and have it reload the values in the table, utilizing the same "sub view" that I loaded in the php variable "content" as described above?
Any help greatly appreciated!
EDIT:
As requested, here's a sample of the json (taken from the browser console output, and it's actually not the categories table, but the same format):
[{"id":"1","title":"Transportation AC 4494","created_by":"4","modified_by":null},{"id":"2","title":"Safety First AC 4294","created_by":"3","modified_by":null},{"id":"3","title":"Warranty AC 34066","created_by":"4","modified_by":null}]
EDIT 2 (Just realized there was some crap from the controller in the previous edit of the json, so I changed it to a cleaner sample now)
EDIT 3:
I have made this work by creating the table rows in jQuery:
var trHTML = '';
$.each(resultdata, function (i, item) {
trHTML += '<tr><td>' + item.id + '</td><td>' + item.title + '</tr>';
});
$('#ajaxtable').html(trHTML);
But mainly I'm hoping this might explain my question better: this is not what I wanted to do. What I would have wanted was to just create a partial view and then load that ready-made view with the jquery:
A partial view like this:
<table class="table table-striped table-bordered" id="resultstable">
<thead>
<tr>
<td>ID</td>
<td>Name</td>
</tr>
</thead>
<tbody id="ajaxtable">
#foreach($resources as $key => $value)
<tr>
<td>{{ $value->id }}</td>
<td>{{ $value->title }}</td>
</tr>
#endforeach
</tbody>
</table>
I tested this by creating and calling a new function in the controller from the jquery code:
public function getTable()
{
$resources = Resource::all()->take(5);
return View::make('categories.results')->with('resources', $resources);
}
But it doesn't work. Although it does indeed give me the html of that view, it is unprocessed. I.e, the foreach loop is not resolved, but still there as code in the table. See the image:
So how can I load this view with the jquery code? It feels to me that even if the jquery creation of table rows works, doing the view in php and then just loading it with jquery should be the more correct way of doing it...?
Have you looked into the Datatables jQuery plugin? There is actually a nice package for Laravel that helps integrate Laravel and Datatables. The Laravel package generates the json and you can use Datables+AJAX to repopulate the data. Might be working checking out...
https://github.com/Chumper/datatable
http://datatables.net/
Otherwise, you'll just need to use AJAX to repopulate the table.
As Sirago answered, using jQuery Datatables is a good option to load data into tables in ajax manner.
In addition to what Sirago suggested, here is another great Laravel 4 package which is dedicated to generate JSON data from server side.
https://github.com/bllim/laravel4-datatables-package
But apart from server side configuration(modifying files like composer.json, config/app.php etc.), you need to code in Javascript, utilizing Datatables as well.
Related
Im trying to pass an integer (id) to a function which calls an api. The api then checks if the id passed matches any data in the database and returns the name associated with the id. I'm using vue.js for this along side laravel. Below is my code.
<tr v-for="store in storeList" :key="store.id">
<td>{{ getNodeName(store.store_name) }}</td>
</tr>
getNodeName(nodeId)
{
axios.get('api/store/getNodeName/'+nodeId).then(function (response){
return response.data[0].name;
});
}
Now the question is how do I get the result to print inside the td tag. apparently return from ajax doesnt work and I tried pushing it all to an array and printing it again but it didnt work either.
thanks
Assuming your API works, the first thing you are doing wrong is that you are returning from the callback when the Promise is resolved and not from the getNodeName method.
One simple way to achieve what you want, is to loop through your storeList (assuming it's a prop) inside the mounted lifecycle hook (using arrow functions here)
...
<tr v-for="node in nodes" :key="node.id">
<td>{{ node.name }}</td>
</tr>
...
data() {
return {
nodes: []
};
},
mounted() {
this.storeList.forEach(store => this.getNodeName(store.store_name));
},
methods: {
getNodeName(nodeId) {
axios.get('api/store/getNodeName/' + nodeId)
.then(response => this.nodes.push({ id: nodeId, name: response.data[0].name }))
}
}
...
You probably also want to turn this into one API call if possible, since you are making storeList.length calls.
You can make a loop of storelist and get nodeId from there and then do the API calls.
<tr v-for="store in storeData" :key="store.id">
<td>{{store.name}} </td>
</tr>
data(){
return{
storeData : []
};
},
created(){
for(var i=0; i<this.storeList.length; i++){
axios.get('api/store/getNodeName/' + this.storeList[i].store_name)
.then(response => this.storeData.push({ id: this.storeList[i].store_name,
name: response.data[0].name
}))
}
}
In my view, I'm getting all the available slots so a user can click the book button to book that slot. However, I just can't seem to find a way to get the correct value (id of the input) so I can set the status of the specific booking in the database to booked.
index.blade.php
#if(count($slots) > 0)
<table class="table table-striped">
<tr>
<th>Date</th>
<th>Time</th>
<th></th>
</tr>
#foreach($slots as $slot)
<tr>
<td>{{$slot->date}}</td>
<td>{{$slot->time}}</td>
<td>
<input name="id" value="{{$slot->id}}" type="hidden"> THIS IS WHAT I WANT TO SEND
<button class="btn btn-primary pull-right" type="submit">Book</button>
</td>
</tr>
#endforeach
BookingsController.php
public function store(Request $request)
{
$booking = new Booking;
$booking->user_id = auth()->user()->id;
$booking->date_id = THIS IS WHAT I NEED;
DB::table('calendar')
->select('id','status')
->where('id', GET DATE ID)
->update(['status' => 1]);
$booking->save();
return redirect('/bookings')->with([
'success' => 'Booking successful!',
]);
}
Use the request object to retrieve the parameters you send :
$whatYouNeed = $request->id (or in general $request->WhateverYouNamedYourField)
Edit : This is not related to hidden fields only, it works with any kind of form fields.
Request docs
In store function you are Typehinting Request.
store(Request $request)
The first Request is referring to the request handler.
So if you'll put this after your.
$booking->date_id = $request->input('id')
Thats your answer.
You are requesting the input id from the request input
from the docs
$request->all();
or
$request->get('filedName');
or
$request->fieldName;
or
$request->input('fieldName');
These are the ways of getting inputs including hidden ones
I need to get all data records from a clients table, there is more than 18000 records.
I use DataTables jQuery plugin to display data, so I do not want to use paginate Laravel method here.
I just want to retrieve data and pass to DataTable jQuery. This plugin does pagination.
This is my Controller code:
$data = Client::orderBy('created_at', 'desc')->get();
I got 500 error, because the result is too big.
I do not want to set higher memory limit, I want to use limitations or similar.
I tried this:
$data = Client::orderBy('created_at', 'desc')->take(10)->skip(1200)->get();
But it only gets 10 records and no more.
Any idea?
you can use Laravel Datatable package which is more effective and easy to use, here is my example that How I am doing it.
Note: I am using Yajra Datatable package for this, you all basic requirement will be cover in this.
My Controller method, where datatable Ajax request will come
public function getData()
{
$users = User::whereHas('roles',function($q){
$q->whereNotIn('roles.name',['user','memberstudent','educationmanager']);
})->select(array('users.id','users.firstname','users.lastname' ,'users.username','users.email',DB::raw("'roles'"), 'users.confirmed', 'users.created_at'));
return Datatables::of($users)
//->edit_column('created_at', '{{ $created_at->format("Y-m-d h:i:s") }}')
->edit_column('created_at', '{{ date("Y-m-d", strtotime($created_at))}}')
->edit_column('confirmed','#if($confirmed)
Yes
#else
No
#endif')
->add_column('roles','{{ implode(", ", User::find($id)->roles()->lists(\'name\')) }}')
->add_column('actions', '
#if(Auth::user()->hasRole("owner"))
<div class="btn-group">
<i class="fa fa-pencil"></i> {{{ Lang::get(\'button.edit\') }}}
<i class="fa fa-trash-o"></i> {{{ Lang::get(\'button.delete\') }}}
</div>
#elseif(Auth::user()->hasRole("superadmin") && User::find($id)->roles()->pluck(\'name\') != "owner")
<div class="btn-group">
<i class="fa fa-pencil"></i> {{{ Lang::get(\'button.edit\') }}}
<i class="fa fa-trash-o"></i> {{{ Lang::get(\'button.delete\') }}}
</div>
#endif
')
->remove_column('id')
->remove_column('rn') // rownum for oracle
->remove_column('created_at') // rownum for oracle
->make();
}
My view is
<table id="users" class="table table-striped table-hover table-bordered">
<thead>
<tr>
<th class="col-md-2">first name</th>
<th class="col-md-2">last name</th>
<th class="col-md-2">username</th>
<th class="col-md-2">email</th>
<th class="col-md-2">roles</th>
<th class="col-md-2">activated</th>
<th class="col-md-2">actions</th>
</tr>
</thead>
</table>
MY JS code is
<script type="text/javascript">
var oTable;
$(document).ready(function() {
oTable = $('#users').dataTable( {
"sDom": "<'row'<'col-md-6'l><'col-md-6'f>r><'row'<'col-md-6'i><'col-md-6'p>>t<'row'<'col-md-6'i><'col-md-6'p>>",
"aoColumnDefs": [
{ "bSearchable": true, "bSortable": false, "aTargets": [ 2,5 ] }
],
"sPaginationType": "bootstrap",
"oLanguage": {
"sLengthMenu": "_MENU_ records per page"
},
"bProcessing": true,
"bServerSide": true, //this means data will come from server, ajax based
"sAjaxSource": "{{ URL::to('admin/users/data') }}", // get data from this URL
"fnDrawCallback": function ( oSettings ) {
$(".iframe").colorbox({iframe:true, width:"80%", height:"80%"});
}
});
});
</script>
You really, really need to use server-side pagination in this case.
The problem with relying on client-side pagination (i.e., the plugin's pagination feature) is that the response from your API containing all 18,000 records will be humongous, and your users will not only have to wait for the request to complete (which literally could take minutes for this much data), but depending on how the plugin works they may also have to wait while it renders the DOM for all these records.
It looks like Datatables supports server-side pagination. Why not give that a try?
I have adopted another solution, using paginate method from laravel and forget DataTables plugin, DataTables is a great plugin!, but in my case, to use this plugin, would have to implement an ajax script to get data.
Currently I have the system implemented to work with routes, controllers, views with Teepluss themes and a search tool.
I thought there was a simpler way to implement this plugin with Laravel using MVC pattern.
With this lines I have what I need:
My controller
public function index()
{
$data = Client::orderBy('created_at', 'desc')->paginate(50);
$theme = Theme::uses('mytheme');
$view = array(
'name' => 'Teepluss',
'data' => $data,
);
return $theme->scope('clients.index', $view)->render();
}
My view
//-- Table head here
#foreach($data->getCollection()->all() as $value)
//-- Table and data here
#endforeach
//-- Pagination links
{{ $data->appends(Request::except('page'))->links() }}
No 500 error, get all data, pagination working fine. Of course, I am giving up other features of DataTables plugin for the moment...
Anyway thank you very much!
I'm working on yii old version i need to write model function in view file this file is html format i don't know how to call model function. I need to send this value {{ $model->customers_charge->shop_id }} to model function
My code is :
{{foreach $models model}}
<tr>
<td>{{date('M/d/Y H:i', strtotime($model.created))}}</td>
<td>{{if $model->deposit>0}}{{$model->deposit}}{{/if}}</td>
<td>{{if $model->deposit<0}}{{$model->deposit*-1}}{{/if}}</td>
<td>
{{if $model->memo eq Order}}
Shopping Order
{{else}}
{{$model->memo|ucwords}}
{{/if}}
</td>
</tr>
{{/foreach}}
How to get model function in Yii framework.can any one kindly guide me. I'm looking forward your valuable reply.
Can't you just do this ?
YourModelName::model()->YourFunction($arg1,$arg2);
Or
$model = new YourModelName();
$model->YourFunction($arg1,$arg2);
Or I'm missing something?
I'm trying to figure out how to have a table where each row has data including a unique ID and an edit button. When the edit button is clicked I would like for another section of the page to show a form to edit the data on that line. So far I have something like:
//linePage.blade.php
<table>
#foreach($lineList as $line)
<tr>
<td>{{ $line->Name }}</td>
<td>Edit</td>
</tr>
#endforeach
</table>
#if (!empty($lineSelected))
{{-- show form --}}
#endif
//routes.php
Route::get('/LinePage/{lineSelected?}', 'Forms#linePage');
Route::post('/LinePage/{lineSelected?}', 'Forms#updateLinePage');
//Forms.php
public function linePage($lineSelected = NULL){
$data = array('lineSelected=>$lineSelected);
return View::make('Forms\linePage',$data);
}
public function updateLinePage($lineSelected = NULL){
$data = array('lineSelected=>$lineSelected);
return View::make('Forms\linePage',$data);
}
This is working for me but I feel like I'm making it more complicated than it needs to be. Am I going about this correctly? Also, I don't like how the address bar shows localhost/LinePage/LineName once the line is selected. Is it possible to somehow hide the data being passed within the page?
Thanks
a simpler method for this is to use Javascript (and/or) jQuery .
The basic idea is, when you click a button in the table, you will make an ajax request. In that ajax request, you have only the form for that particular lineName . In this way, the page will not be reloaded, and you won't get to change the URL, and it's more fast .
If you choose to do this with jQuery. You will have something like :
//linePage.blade.php
<table>
#foreach($lineList as $line)
<tr>
<td>{{ $line->Name }}</td>
<td>Edit</td>
</tr>
#endforeach
</table>
//in the footer somewhere, after you load query
<script>
$(function()
{
$('a.btn-line').click(function(event){
var id = event.target.id;
fieldName = id.split('-');
lineName = fieldName[1];
$.get(
"{{action('Forms#lineForm'}}?lineName="+lineName,
function(data){
$('div#line-form').html(data);
}
);
});
</script>
in your routes :
Route::get('/linePage/form/', 'Forms#lineFormPage');
and in your controller, you will return the view with only the form
Maybe this is not the easiest way to do, but you won't need to refresh every time you need to reload the form, + it keeps things more separated