I am making a Codeigniter 3 application, consisting of a table (with approximately 100 rows) that I have paginated, 10 rows per page.
In the home controller I have:
public function index() {
$this->load->model('Customer');
$this->load->library('pagination');
$config = [
'base_url' => base_url("index.php"),
'per_page' => 10,
'total_rows' => $this->Customer->get_num_rows(),
'uri_segment' => 3,
'first_tag_open' => '<li>',
'first_tag_close' => '</li>',
'last_tag_open' => '<li>',
'last_tag_close' => '</li>',
'full_tag_open' => '<ul class="pagination">',
'full_tag_close' => '</ul>',
'next_tag_open' => '<li>',
'next_tag_close' => '</li>',
'prev_tag_open' => '<li>',
'prev_tag_close' => '</li>',
'num_tag_open' => '<li>',
'num_tag_close' => '</li>',
'cur_tag_open' => '<li class="active"><a>',
'cur_tag_close' => '</a></li>',
];
$this->pagination->initialize($config);
$customers = $this->Customer->getCustomers($config['per_page'], $this->input->get('page'));
$this->load->view('home', ['records'=>$customers]);
}
In the Model file I have:
class Customer extends CI_Model {
public function __construct() {
$this->load->database();
}
public function getCustomers($limit, $offset) {
$this->db->limit($limit, $offset);
$query = $this->db->get('customers');
return $query->result();
}
}
The view:
<div class="pagination-container text-center">
<?php echo $this->pagination->create_links(); ?>
</div>
The first page looks good (I have recieved help from the comunuty with that. Thank you!):
The problem is that the second page shows records 3 to 13 instead of 11 to 20:
Inside the Home controller, after the changes that made the pagination work, I now have:
public function index() {
$this->load->model('Customer');
$this->load->library('pagination');
$config = [
'base_url' => base_url("index.php"),
'page_query_string' => TRUE,
'query_string_segment' => 'page',
'display_pages' => TRUE,
'use_page_numbers' => TRUE,
'per_page' => 10,
'total_rows' => $this->Customer->get_num_rows(),
'uri_segment' => 3,
'first_link' => '«',
'first_tag_open' => '<li>',
'first_tag_close' => '</li>',
'last_link' => '»',
'last_tag_open' => '<li>',
'last_tag_close' => '</li>',
'full_tag_open' => '<ul class="pagination">',
'full_tag_close' => '</ul>',
'next_link' => '›',
'next_tag_open' => '<li>',
'next_tag_close' => '</li>',
'prev_link' => '‹',
'prev_tag_open' => '<li>',
'prev_tag_close' => '</li>',
'num_tag_open' => '<li>',
'num_tag_close' => '</li>',
'cur_tag_open' => '<li class="active"><a>',
'cur_tag_close' => '</a></li>'
];
if (!isset($_GET[$config['query_string_segment']])) {
$_GET[$config['query_string_segment']] = 1;
}
$limit = $config['per_page'];
$offset = ($this->input->get($config['query_string_segment']) - 1) * $limit;
$this->pagination->initialize($config);
$customers = $this->Customer->getCustomers($limit, $offset);
$this->load->view('home', ['records'=>$customers]);
}
It works fine, I hope it will help many. But I wonder if I could be simplified, written with less code...
The offset is a preview limit ( bad explain ). Example:
SELECT * FROM customers LIMIT 0, 10;
Offset is a 0 and limit 10, second page:
SELECT * FROM customers LIMIT 10, 10;
The Offset is a 10 and limit 10, third page:
SELECT * FROM customers LIMIT 20, 10;
The Offset is a 20 and limit 10, etc. Using QueryBuilder of codeigniter:
$this->db->limit( $limit, $offset );
The URL param is a offset.
Then for the instance of pagination library you have use site_url() function. base_url is to statics or assets location and site_url() to navigation page.
Check variable on config.php file $config['index_page'], if you use rewrite url to remove "index.php" then this variable have been empty else your value is a "index.php".
if you use segment param instead variable, you need add route entry. For example:
$route['customers/(:num)'] = 'Customers/index/$1';
Or with regex limiters:
$route['^customers/(:num)$'] = 'Customers/index/$1';
Remember, the url param (:num) is a offset.
Try this.
Codeigniter uses array like array() not using []
Also use a separate function to count all results from table like below
public function index() {
$this->load->model('customer_model');
$this->load->library('pagination');
$config['base_url'] = base_url("controllername");
$config['total_rows'] = $this->customer_model->count_total();
$config['per_page'] = 10;
$config['uri_segment'] = 2;
$config['num_links'] = 10;
// Bootstrap
$config['full_tag_open'] = '<div class="pagination"><ul>';
$config['full_tag_close'] = '</ul></div><!--pagination-->';
$config['first_link'] = '« First';
$config['first_tag_open'] = '<li class="prev page">';
$config['first_tag_close'] = '</li>';
$config['last_link'] = 'Last »';
$config['last_tag_open'] = '<li class="next page">';
$config['last_tag_close'] = '</li>';
$config['next_link'] = 'Next →';
$config['next_tag_open'] = '<li class="next page">';
$config['next_tag_close'] = '</li>';
$config['prev_link'] = '← Previous';
$config['prev_tag_open'] = '<li class="prev page">';
$config['prev_tag_close'] = '</li>';
$config['cur_tag_open'] = '<li class="active"><a href="">';
$config['cur_tag_close'] = '</a></li>';
$config['num_tag_open'] = '<li class="page">';
$config['num_tag_close'] = '</li>';
/*
Change your uri segment number to what you want make sure though you change it in the array above also uri_segment.
*/
$page = ($this->uri->segment(2)) ? $this->uri->segment(2) : 0;
$this->pagination->initialize($config);
$data['paglinks'] = $this->pagination->create_links();
$data['records'] = $this->customer_model->getCustomers($config['per_page'], $page);
$this->load->view('home', $data);
}
http://www.codeigniter.com/user_guide/general/views.html#creating-loops
http://www.codeigniter.com/user_guide/libraries/uri.html
http://www.codeigniter.com/user_guide/general/routing.html#examples
You may need to set your routes
$route['controllername/(:any)'] = 'controllername/index/$1';
I would rename the model to something like customer_model that way if have another file with same name does not cause error
class Customer extends CI_Model {
public function __construct() {
parent::__construct();
}
public function getCustomers($limit, $offset) {
$this->db->limit($limit, $offset);
$query = $this->db->get('customers');
return $query->result();
}
public function count_total()
{
return $this->db->count_all_results('customers');
}
}
Autoload the database much better
$autoload['libraries'] = array('database');
With your current model method
public function getCustomers($limit, $offset) {
$this->db->limit($limit, $offset);
$query = $this->db->get('customers');
return $query->result();
}
You are passing in $limit, which you are passing in as 10. Your $offset seems to be the page number as is shown by the results you are seeing.
For instance, if your uri segment value is 2 ( for page 2 ) you are effectively setting the limit in your method to be
$this->db->limit(10, 2);
which will show records 3 to 13.
You can verify this by using the following var_dump statement as debug code to inspect the values.
public function getCustomers($limit, $offset) {
$this->db->limit($limit, $offset);
var_dump($limit, $offset);
$query = $this->db->get('customers');
return $query->result();
}
If you can't see those on the page directly, you will find the output for those when you perform a view-source on your HTML in your web browser.
So what you need to do is to set the $offset to reflect the number of entries * the page number.
So Page 1 will be records with $offset = $limit * ($page - 1) = 10 * 0 = 0
, with a limit of 10 will get records 1 to 10.
Page 2 should be records with $offset = $limit * ($page - 1) = 10 * 1 = 10
will give records 11-20
So this leads to the thinking that you need to rename $offset in your method parameters to $page and calculate the required $offset
public function getCustomers($limit, $page) {
$offset = 0;
if($page > 0) {
$offset = $limit * ($page - 1);
}
$this->db->limit($limit, $offset);
$query = $this->db->get('customers');
return $query->result();
}
So hopefully that helps.