OK so basically I have created a simple page using Kohana for displaying a user's message inbox/outbox using tabs.
My controller is something like this:
$content = View::factory('messages')->bind('user', $user)->bind('received', $received)->bind('sent', $sent)->bind('pager_links', $pager_links);
$user = Auth::instance()->get_user();
$message_count = ORM::factory('message')->where('to_id', '=', $user)->where('read', '=', '0')->count_all();
$pagination = Pagination::factory(array(
'total_items' => $message_count,
'items_per_page' => 10
));
$received = ORM::factory('messages')->where('messages.to_id', '=', $user)->limit($pagination->items_per_page)->offset($pagination->offset)->find_all();
$sent = ORM::factory('messages')->where('messages.user_id', '=', $user)->limit($pagination->items_per_page)->offset($pagination->offset)->find_all();
$pager_links = $pagination->render();
$this->template->content = $content;
So far I am only displaying the received messages and pagination in the view and it is working fine. However I want to implement a tab container to display both the received and sent items on the same page.
I am scratching my head wondering how to use the pagination aspect for each tab without it affecting both tabs. What would be the best direction for this using the existing approach? Perhaps throwing an additional parameter into the URL when a tab is selected...
Thanks
Basically your issue is that you can't use page in the query string for both of the tabs at once, as obviously it will affect both pagination functions. Luckily there is in fact a configuration open that allows you to specify the source of the current page parameter in the query string.
Try this...
$pagination = Pagination::factory(array(
'current_page' => array('source' => 'query_string', 'key' => 'tab1_page'),
'total_items' => $message_count,
'items_per_page' => 10
));
Then all you need to do is make sure that your pagination view is passing the page number to the correct parameter in the query string e.g. http://mydomain.com/pagewithtabs?tab1_page=2&tab2_page=3 will put tab 1 on page 2 and tab 2 on page 3.
Hope that helps!
Related
I'm using alaouy/youtube package for one of my projects, Its working just fine, But with this method I can't use pagination! Is there any way or I've to write my own code? There is a vendor folder in my resources with pagination folder but I can't get work with it!
// List videos in a given channel, return an array of PHP objects
$videoList = Youtube::listChannelVideos('UCk1SpWNzOs4MYmr0uICEntg', 40);
I'm the creator of that package, happy that it was helpful for you and sorry that the documentation wasn't clear enough.
The listChannelVideos is based on the searchAdvanced method, so you can paginate the channel videos like this :
$params = array(
'channelId' => 'UCk1SpWNzOs4MYmr0uICEntg',
'type' => 'video',
'part' => 'id, snippet',
'maxResults' => 40);
// Make intial call. with second argument to reveal page info such as page tokens
$search = Youtube::searchAdvanced($params, true);
print_r($search); // First page results
// Check if we have a pageToken
if (isset($search['info']['nextPageToken'])) {
$params['pageToken'] = $search['info']['nextPageToken'];
}
// Make another call and repeat
$search = Youtube::searchAdvanced($params, true);
print_r($search); // Second page results
Hope this will help you!
I am using cakePHP 2.5 and I want to access $this->Paginator->hasNext() in controller, but it through exception.
$type = array('featured', 'newest', 'trending');
foreach($type as $each)
{
$conditions = array('Product.status'=>'1', "is_$each" => '1');
$this->Product->recursive = 1;
//retrieve and set final result set
$this->paginate = array(
'fields' => array('Product.*'),
'conditions' => $conditions,
'limit' => $page_limit,
'page' => $page,
'order' => "$order_by $order_by_sort",
);
$products[$each] = $this->paginate('Product');
}
On my page, I want to display 3 type of product featured/trending/newest. Initially I load first page by default, then when user scroll down then I will call ajax and append next page like wise. But if last page is reached then I want to stop ajax call (because unknown page through 404 not found error).
To overcome that, I prevent AJAX call for unknown pages. And also make sure that first page isn't last!!
Hope my details make sense!
I could not find any answer on any forum/document. Please guide me or point me if it's duplicate of any.
You don't need to (and cannot*) access a helper in the controller.
Take a look at the source code for hasNext which is just calling the helper function _hasPage, which is simply checking the parameters array.
The paginator parameters are all available in the controller:
$paging = array(
'page' => $page,
'current' => count($results),
'count' => $count,
'prevPage' => ($page > 1),
'nextPage' => ($count > ($page * $limit)),
'pageCount' => $pageCount,
'order' => $order,
'limit' => $limit,
'options' => Hash::diff($options, $defaults),
'paramType' => $options['paramType']
);
So from the code in the question:
$this->request['paging']['Product']['nextPage']
Is the information you're looking for (it will be overwritten each time you call paginate.
Consider your application design.
Unless you have exactly the same number of featured, newest and trending records - it'd be better to have one ajax request for each type. Also see this related question, for more information on implementing infinite-scroll type pages.
* Almost anything is possible, you certainly should not need to use a helper in a controller though.
MVC Violation
$this->Paginator->hasNext()
That's a method of the helper. Helpers are not thought to be used in controllers because this is a violation of the MVC pattern and bad practice. If you think you have to you're wrong: Fix your architecture, it's broken by design.
Proper solution
Return the status of the pagination along with the data in the AJAX response:
$this->set('pagination', $this->request->paging['Product']);
$this->set('products', $result);
$this->set('_serialize', ['products', 'pagination']);
You can change the state of your view depending on the data then:
if (pagination.Product.nextPage == true) { /*... */ }
I have a search form which, if someone fills it in and there are no results to report, I want to make them aware of that but then show them a result set of my choosing. The problem is that when I show them this result set of my choosing and I use the paginator helpers for prev/next they want to pass the search term which is in my URL along with the page number.
That obviously causes problems because there isn't a page:2 for the results search:termHasNoResults
How can I stop the paginator helper passing my search variable in the URL when I'm showing them my alternative result set?
Thanks
Use
$this->Paginator->options('url' => array(
'controller' => 'YOUR CONTROLLER', 'action' => 'YOUR ACTION', 'OTHER PARAMS');
You can pass 'url' option to pagination in your view like this:
$url = array_merge($this->request->pass, $this->request->named);
unset($url['page']);
$parts = explode('?', $_SERVER['REQUEST_URI'], 2);
if (count($parts) == 2) {
$url['?'] = $parts[1];
}
$this->Paginator->options(array(
'url' => $url,
));
More here: http://api.cakephp.org/2.2/class-PaginatorHelper.html
and here: http://book.cakephp.org/2.0/en/core-libraries/helpers/paginator.html#PaginatorHelper::options
If you widely use filters and additional url params - make an element which will handle it for you
I am trying to build in a "search" box on a results page in my cakephp app. The page uses the cakePHP pagination component to show and "page" results. This is perfect, but I am having difficulties to get the next part to work.
The desired outcome:
A cakephp form (post) with an input box and a couple of select boxes, including a date selector so that I can select between dates. The user should be able to populate these fields and submit
On submit, the user selection should change the cakePHP pagination conditions in the controller
In the view I want the pagination bar to keep record of the user selection, so that when I filter through different pages, it keeps the users search. I understand this can be achieved using $this->passedArgs, hence why I am using post and not get.
The code:
// Form:
<?php
echo $this->Form->create('search', array('class' => false));
echo $this->Form->input('searchFor');
echo $this->Form->input('dateFrom');
echo $this->Form->input('dateTo');
echo $this->Form->end();
?>
// Controller:
if($this->request->is("post")) {
$filters = $this->request->data["search"];
$this->passedArgs["searchFor"] = $filters["searchFor"];
$this->passedArgs["dateFrom"] = $filters["dateFrom"]." 00:00:00";
$this->passedArgs["dateTo"] = $filters["dateTo"]." 00:00:00";
// Assign search parameters:
if($this->passedArgs["searchFor"] != "") {
$conditions["Model.field LIKE"] = "%".$this->passedArgs["searchFor"]."%";
}
$conditions["Model.created >="] = $this->passedArgs["dateFrom"];
$conditions["Model.created <="] = $this->passedArgs["dateTo"];
} else {
$conditions = array("Result.status_id >=" => 12);
}
$this->paginate = array(
'conditions' => $conditions,
'order' => array('Result.created ASC'),
'limit' => 20
);
$this->set("results",$this->paginate("Model");
// The view file:
<?php
$this->Paginator->options(array('url' => $this->passedArgs));
?>
Where I am now:
The initial page loads with all of the results
When I populate the search boxes it does return my results
The problem:
I am convinced the way I am doing it is incorrect as I now need to do 2 checks, a) being if results has been posted and b) check if there is passedArgs available. I am 100% convinced this is not the right way of doing it.
Let's say I have 2 free form fields for search, say name and surname, if I leave surname blank my url would be written as below, and this does not look or appear to be correct. That means I have to assign default values to ensure the items below does not happen, which does not appear to be very dynamic.
http://localhost/site/controller/action/surname:0/name:John/date:0/
On refresh it says the page does not exist because the posted values is not available anylonger.
usually I proceed like this in the controller:
//transform POST into GET
if($this->request->is("post")) {
$url = array('action'=>'index');
$filters = array();
if(isset($this->data['searchFor']) && $this->data['searchFor']){
//maybe clean up user input here??? or urlencode??
$filters['searchFor'] = $this->data['searchFor'];
}
//redirect user to the index page including the selected filters
$this->redirect(array_merge($url,$filters));
}
$conditions = array();
//check filters on passedArgs
if(isset($this->passedArgs["searchFor"])){
$conditions["Model.field LIKE"] = "%".$this->passedArgs["searchFor"]."%";
}
//paginate as normal
$this->paginate = array(
'conditions' => $conditions,
'order' => array('Result.created ASC'),
'limit' => 20
);
The idea is to transform the POST sent by your form into GET. so you wont have problems with the paginator nor the refresh
Hope this helps
What you want can be done a lot more simple and DRY by using this search plugin.
It automates what you want more or less plus it already can do more than your code.
So I suggest you to use the plugin directly or take a look at it how it does the trick. :)
public function index($page = 0) {
$this->load->library('pagination');
$conf = array(
'total_rows' => 11,
'base_url' => 'localhost/admin/product/index',
'per_page' => 10,
'use_page_numbers' => false
);
$this->pagination->initialize($conf);
$this->load->view('product/index');
}
In view
<?php echo $this->pagination->create_links(); ?>
In the first page it work correctly. When I click on the page 2 link, it only display ONE product, this was correct, but the pagination links for current page still in page ONE. Suppose this should be page TWO.
which part I did wrong?
Well, the pagination class uses "per_page" in the query string. So, you have to divide that number by 10 (in your case) and add 1 to get the real page number, i.e.:
localhost/product/index (page 1)
localhost/product/index?per_page=10 (page 2)
localhost/product/index?per_page=20 (page 3)
...
localhost/product/index?per_page={10n) (page n+1)
This is useful to use directly in the database limit clause:
$this->db->limit(10, $this->input->get('per_page'))...
I think that's why CI chose to do it that way....