How to create a sortable table THEAD References for Codeigniter table

I can't seem to get my links to parse my data. I've tried many different methods, now I'm not sure what to do.

For example, if a user clicks on their user id link, it will sort users by user id asc or desc and so on. Same for username, date of added links. I tried it using scripts, but because it is controlled by a controller, doesn't work.

Using my code

What I am trying to achieve is with the header area of ​​the users list table there are 5 thead that I would like to do this, when I click on one, it sorts the list according to that asc and / or dsc field. When trying to get it to work with the current pagination, pagination works great .

Some libraries are loaded automatically.

Custom Codeigniter Controller

protected function getList() {
    $data['heading_title'] = $this->lang->line('heading_title');

    $data['breadcrumbs'] = array();

    $data['breadcrumbs'][] = array(
        'text' => '<i class="fa fa-home"></i>' .' '.  $this->lang->line('text_home'),
        'href' => site_url('admin/dashboard')
    );

    $data['breadcrumbs'][] = array(
        'text'      => $this->lang->line('heading_title'),
        'href'      => site_url('admin/users')
    );

    $data['text_enabled'] = $this->lang->line('text_enabled');
    $data['text_disabled'] = $this->lang->line('text_disabled');

    $data['column_user_id'] = $this->lang->line('column_user_id');
    $data['column_name'] = $this->lang->line('column_name');
    $data['column_status'] = $this->lang->line('column_status');
    $data['column_last_updated'] = $this->lang->line('column_last_updated');
    $data['column_date_added'] = $this->lang->line('column_date_added');
    $data['column_action'] = $this->lang->line('column_action');

    $data['delete'] = site_url('admin/users/delete');
    $data['insert'] = site_url('admin/users/add');

    $data['text_confirm'] = $this->lang->line('text_confirm');

    $data['button_insert'] = $this->lang->line('button_insert');
    $data['button_edit'] = $this->lang->line('button_edit');
    $data['button_delete'] = $this->lang->line('button_delete');

    $this->load->library('setting'); 

    $this->load->library('pagination'); 

    $config = array(); 
    $config["base_url"] = base_url('admin/users'); 
    $config['total_rows'] = $this->db->get('user')->num_rows(); 
    $config["per_page"] =  $this->setting->get('config_limit_admin');
    $config["uri_segment"] = 3;  

    $config['full_tag_open'] = "<ul class='pagination'>";
    $config['full_tag_close'] ="</ul>";
    $config['num_tag_open'] = '<li>';
    $config['num_tag_close'] = '</li>';
    $config['cur_tag_open'] = "<li class='disabled'><li class='active'><a href='#'>";
    $config['cur_tag_close'] = "<span class='sr-only'></span></a></li>";
    $config['next_tag_open'] = "<li>";
    $config['next_tagl_close'] = "</li>";
    $config['prev_tag_open'] = "<li>";
    $config['prev_tagl_close'] = "</li>";
    $config['first_tag_open'] = "<li>";
    $config['first_tagl_close'] = "</li>";
    $config['last_tag_open'] = "<li>";
    $config['last_tagl_close'] = "</li>";

    $this->pagination->initialize($config);

    $data['users'] = $this->db->get('user', $config["per_page"], $this->uri->segment(3));

    if (isset($this->request->post['selected'])) {
        $data['selected'] = (array)$this->request->post['selected'];
    } else {
        $data['selected'] = array();
    }

    return $this->load->view('user/users_list', $data);
}

      

View

<form action="<?php echo $delete; ?>" method="post" enctype="multipart/form-data" id="form-user">

<div class="table-responsive">
<table class="table table-bordered table-hover">
<thead>
<tr>
<td style="width: 1px;" class="text-center"><input type="checkbox" onclick="$('input[name*=\'selected\']').prop('checked', this.checked);" /></td>
<td class="text-center" style="color: #1E91CF; font-size: 14px; font-weight: bold;"><?php echo $column_user_id; ?></td>
<td class="text-center" style="color: #1E91CF; font-size: 14px; font-weight: bold;"><?php echo $column_name; ?></td>
<td class="text-center" style="color: #1E91CF; font-size: 14px; font-weight: bold;"><?php echo $column_status; ?></td>
<td class="text-center" style="color: #1E91CF; font-size: 14px; font-weight: bold;"><?php echo $column_last_updated; ?></td>
<td class="text-center" style="color: #1E91CF; font-size: 14px; font-weight: bold;"><?php echo $column_date_added; ?></td>
<td class="text-center" style="color: #1E91CF; font-size: 14px; font-weight: bold;"><?php echo $column_action; ?></td>
</tr>
</thead>
<tbody>
<?php foreach ($users->result() as $user) { ?>  
<td class="text-center"><?php if (in_array($user->user_id, $selected)) { ?>
<input type="checkbox" name="selected[]" value="<?php echo $user->user_id; ?>" checked="checked" />
<?php } else { ?>
<input type="checkbox" name="selected[]" value="<?php echo $user->user_id ?>" />
<?php } ?>
</td>
<td class="text-center"><?php echo $user->user_id; ?></td>
<td class="text-center"><?php echo $user->username; ?></td>
<td class="text-center"><?php if ($user->status == TRUE) { echo $text_enabled; } else { echo $text_disabled ; } ?></td>
<td class="text-center"><?php echo $user->last_updated; ?></td>
<td class="text-center"><?php echo $user->date_added; ?></td>
<td class="text-center"><?php echo anchor("admin/users/edit/" . $user->user_id, '<div class="btn btn-primary text-right" role="button"><i class="fa fa-pencil"></i>
 Edit</div>');?></td>
</tr>
<?php } ?>
</tbody>
</table>
</div>
<div class="row">
<div class="col-sm-6 text-left">
<?php echo $this->pagination->create_links();?>
</div>
</div>
</form>

      

Model get users

public function getUsers() {
  $this->db->select('*');
  $this->db->from($this->db->dbprefix . 'user');
  $query = $this->db->get();

  if ($query->num_rows() > 0) {
      return $query->result();
      return true;
  } else {
      return false;
  }
}

      

+3


source to share


4 answers


Okay, let it order and paginate!

First of all, how pagination works

When you paginate you say:

"There are (say) 25 items. I want to show page 2, so if I am (say) showing 5 items per page, I have to order them and then show from item 6 to 10."

So if you want to show page 3, you order (let's say) the id and then you see from items 11 to 15. To summarize, you should know:

  • How many items are you showing
  • The page you want to list (the later you convert to offset, keep reading)
  • The order you are using to display.

Example: I will use the following table, insert it into DDBB and run queries to see what I mean:

CREATE TABLE IF NOT EXISTS `elements` (
  `id` int(11) DEFAULT NULL,
  `letter` char(50) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

INSERT INTO `elements` (`id`, `letter`) VALUES
    (10, 'a'),(9, 'b'),(8, 'c'),(7, 'd'),   (6, 'e'),   (5, 'f'),   (4, 'g'),   (3, 'h'),   (2, 'i'),   (1, 'j');

      

And now, let the paginate!

Imagine you want to show page 3, 2 elements on the page, ordering along the ascendent axis. You will need to show elements with IDs 5 and 6, since page 1 has IDs 1 and 2, and page 2 has IDs 3 and 4. So our offset would be:

$offset = ($elements_per_page) * ($page – 1);
// In this example: $offset = 2 * (3 – 1 ) = 4.

      

And know to order by id and show items from the page you have to run:

SELECT *
FROM elements
ORDER BY id ASC
LIMIT 4, 2

      

And you get in the following order: (5,'f') and (6, 'e')

And if you want to order them by letter, you run

SELECT *
FROM elements
ORDER BY letter ASC
LIMIT 4, 2

      

which gives you in the following order: (6, 'e') and (5, 'f')

Explanation: The limit clause allows you to specify the offset and number of items you want to show.

From http://dev.mysql.com/doc/refman/5.0/en/select.html , "With two arguments, the first argument indicates the offset of the first line to return, and the second indicates the maximum number of lines to return. The starting line offset is 0 (not 1) "

Well, now you know how to execute the query, so let's build it using CI.

Creating pagination with CI

Your model needs to know what you want to show: the order, the page you want to show, and the number of elements, so it should be something like:



MODEL users_model.php

public function getUsers( $offset, $elements_per_page, $order_field, $order_direction ) 
{    
    $this->db->select('*');
    $this->db->from($this->db->dbprefix . 'user');

    $this->db->order_by( $order_field, $order_direction )

    // Be careful, the order is differente here than in real MySQL query LIMIT: LIMIT $OFFSET, $ELEMENTS_PER_PAGE
    $this->db->limit($elements_per_page, $offset );  


    $query = $this->db->get();

    if ($query->num_rows() > 0) {
        return $query->result();
    } else {
        // This just to keep allways the same kind of data returned, ;D
        return array();
    }
}

// We'll use this to know how many users there are.
public function countUsers() 
{
    return $this->db->count_all_results( $this->db->dbprefix . 'user' );
}

      

With the above code, you have a model class base to start sending values ​​from the database to the controller, but you also need to play with the controller. It will have to process the pages to make sure you are in range, to make sure the values ​​you want to order are fields that actually exist ... Well, the controller works, you know?

CONTROLLER: users.php

public function user_results()
{
    // To control the page you're sending is ok, you have to count first the number of elements
    $page   = $this->input->get( $page );

    $elements_per_page  = 3; // You could also send it in your request

    $this->load->model('users_model');  
    $total      = $this->users_model->countUsers();
    $get_offset =  ( $page – 1 ) * $elements_per_page;
    // And you have to control the offset:
    $min_offset = 0; 
    $max_offset = floor( $total / $elements_per_page ); 
    $offset = ( ( get_offset > $max_offset ) ? $max_offset : ( ( $get_offset < $min_offset ) ? $min_offset : $get_offset ) ); 

    // Then, you have to control the fields to order. I'd recommend you white list filter:
    $get_order_field    = $this->input->get('order_field');
    $order_fields   = array( 'id', 'letter');
    $order_field    = in_array( $get_order_field, $order_fields ) ? $get_order_field : 'id';

    $get_order_direction    = $this->input->get('order_direction');
    $order_directions   = array( 'asc', 'desc');
    $order_field        = in_array( $get_order_direction, $order_directions ) ? $get_order_direction : 'asc';

    // And now, you can show a list of the elements you want to show from the page:       
    $data['users'] = $this->users_model->getUsers( $offset, $elements_per_page, $order_field, $order_direction );

    $this->load->view('table_users_view', $data );
}

      

And to finish with the backend, I would put all the table values ​​in the view:

VIEW: table_users_view.php

<table>
  <tr>
    <th>Id</th>
    <th>Name</th>
  </tr>
  <?php if ( !empty( $users ) : ?>
      <?php foreach ( $users as $user ) : ?> 
  <tr>
    <td><?=$user->id?></td>
    <td><?=$user->name?></td>   
  </tr>
      <?php endforeach; ?> 
  <?php endif; ?>
</table>

      

Ok, this is START ANSWER your question. You can now paginate, but you need to automatically add links to pages that might look like BASE_URL/users/?page=1&order_field=id&order_direction=asc

. And you will have to write in JS an AJAX call called with anchors in your html. If you all understand the code, follow these steps:

  • Write an AJAX call with its anchors in the table header.
  • Reload the content based on the values ​​of the selected page and these values: for this you need a controller method that takes AJAX parameters and returns a tbody to you, not the whole table.

More or less:

$(document).ready(function({
    $('.order').click( function(){
        var field = $(this).data('field');
        var dir   = $(this).data('dir');       
        var page  = $('.pagination active').data('page');
        $.ajax({
            type: 'get',
            dataType: 'json'
            url:  BASE_URL + 'users/ajax/?page=' + page + '&order_direction=' + dir + '&order_field=' + field,
            success: function(data) {
                $('table.users tbody').html(data.tbody);
            }
        });
    })   
});

      

Your opinion should be changed to:

<div class="pagination">
    <span class="active" data="1">1</span>
    <span data="2">2</span>
    <span data="3">3</span>
</div>

<table>
  <tr>
    <th>
      <span class="order" data-field="id" data-dir="asc">Up</span>
      <span class="order" data-field="id" data-dir="desc">Down</span>
      ID
    </th>
    <th>
      <span class="order" data-field="name" data-dir="asc">Up</span>
      <span class="order" data-field="name" data-dir="desc">Down</span>
      Name
    </th>
  </tr>
  <tbody>
  <?php if ( !empty( $users ) : ?>
      <?php foreach ( $users as $user ) : ?> 
  <tr>
    <td><?=$user->id?></td>
    <td><?=$user->name?></td>   
  </tr>
      <?php endforeach; ?> 
  <?php endif; ?>
  </tbody>
</table>

      

and you need a "partial view" to load only body data:

VIEW: table_users_partial_view.php

      <?php if ( !empty( $users ) : ?>
          <?php foreach ( $users as $user ) : ?> 
      <tr>
        <td><?=$user->id?></td>
        <td><?=$user->name?></td>   
      </tr>
          <?php endforeach; ?> 
      <?php endif; ?>

      

Your controller must be changed to display the partial view if you are sending an AJAX request:

CONTROLLER: Changed to return only partial data:

public function user_results()
{
    // To control the page you're sending is ok, you have to count first the number of elements
    $page  = $this->input->get( $page );

    $elements_per_page = 3; // You could also send it in your request

    $get_offset    =  ( $page – 1 ) * $elements_per_page;
    // And you have to control the offset:
    $min_offset    = 0; 
    $max_offset    = floor( $total / $elements_per_page ); 
    $offset    = ( ( get_offset > $max_offset ) ? $max_offset : ( ( $get_offset < $min_offset ) ? $min_offset : $get_offset ) ); 

    // Then, you have to control the fields to order. I'd recommend you white list filter:
    $get_order_field   = $this->input->get('order_field');
    $order_fields  = array( 'id', 'letter');
    $order_field   = in_array( $get_order_field, $order_fields ) ? $get_order_field : 'id';

    $get_order_direction   = $this->input->get('order_direction');
    $order_directions  = array( 'asc', 'desc');
    $order_field       = in_array( $get_order_direction, $order_directions ) ? $get_order_direction : 'asc';

    // And now, you can show a list of the elements you want to show from the page:
    $this->load->model('users_model');

    $data['users'] = $this->users_model->getUsers( $offset, $elements_per_page, $order_field, $order_direction );
    if ( !$this->input->is_ajax_request() ) {
        $this->load->view('table_users_view', $data );
    } else {
        $return = array( 
            'tbody' => $this->load->view('table_users_partial_view
        );  
        // This is to give back the value as a JSON the JS will understand. In fact, in the AJAX call we indicated it.
        echo json_encode( $return );
    }
}

      

DISCLAIMER: Only SQL from the beginning is tested code, all of the above may or may not work as expected if just copy / paste. The code is for clarification and gives you the following path: you must understand and code first. Everything above is written in the hope that it will be helpful, if you have any doubts, please post a comment. Have fun coding!

+2


source


Take a look at this example:

View:

<thead>
  <tr>
    <td class="text-center"><input type="checkbox" onclick="$('input[name*=\'selected\']').prop('checked', this.checked);" /></td>
    <td class="text-center asc" data-orderby="column_user_id"><?php echo $column_user_id; ?></td>
    <td class="text-center asc" data-orderby="column_name"><?php echo $column_name; ?></td>
    <td class="text-center asc" data-orderby="column_status"><?php echo $column_status; ?></td>
    <td class="text-center asc" data-orderby="column_last_updated"><?php echo $column_last_updated; ?></td>
    <td class="text-center asc" data-orderby="column_date_added"><?php echo $column_date_added; ?></td>
    <td class="text-center asc" data-orderby="column_action"><?php echo $column_action; ?></td>

      

Let's say you have a page displaying data:

controller/model/page/1

      

Lets find url for Javascript:

$url = $this->input->server('REQUEST_URI');
if( preg_match('/\?/', $url) ) 
    $url = strstr($url, "?", true);

      

JQuery code to change url:

$('.table thead td').click(function(e){
    var $this = $(this), 
        order_by = $this.data('orderby'), 
        myURL = '<?php echo $url ?>', 
        order='';

    // Handle Asc and Desc
    if( $this.hasClass('asc') ) {
        $this.removeClass('asc');
        $this.addClass('desc');
        order = 'desc';
    }
    else {
       $this.removeClass('desc');
        $this.addClass('asc');
        order = 'asc';
    }


    // change url on click
    document.location.href = myURL + '?orderby='+order_by+'&order='+order;
});

      



You will now get the url:

controller/model/page/1?orderby={data_element}&order={asc|desc}

      

Now process the QUERY STRING in the controller and pass it to the Model.

Controller:

// Return Query String else return empty
$QS = $this->input->server('QUERY_STRING');
$Page = $this->uri->segment(3);

$Start = ! empty($Page) ? $Page : 0;

// Pass this string to your model
$data['users'] = $this->mymodel->getUsers($Start, $config["per_page"], $QS);

      

Model

public function getUsers($Start=0, $Limit=10, $QS=null) {


  $this->db->select('*');
  $this->db->from('users');

  // Handle Order By
  if( ! is_null($QS) ) {
      parse_str($QS);

      if( isset($order_by) && ! empty($order_by) && isset($order) && ! empty($order) ) { 
          $this->db->order_by($order_by, $order);
      }

  }

  $this->db->limit($Start, $Limit);
  $query = $this->db->get();

  return $query->num_rows() > 0 ? $query->result_array() : false;

      

}

For active entries, please follow this link . Hope this helps you understand and implement.

0


source


First of all, put the page you are in in the parameters you pass to function in the controller:

protected function getList($offset = 0, $order_by = 'id', $order_direction = 'asc') {

as in https://ellislab.com/codeigniter/user-guide/general/controllers.html Don't forget to provide the default values ​​so that the link can be accessed without having to provide them.

The second thing is to pass this data for viewing, add it inside a data variable.

The next pass $order_by

and $order_direction

for simulation public function getUsers($order_by, $order_direction) {

do not need to set default values as parameters as they will always be set by the controller.

After that, in the model, you should make an array of things that the user can sort, just good practice. You will be sorting using the active record with the following line $this->db->order_by($order_by, $order_direction);

inside the controller, also remember to restrict the $order_direction

asc or desc so that the user cannot crash the application (just put the default if not recognized).

After this preparation in mind just do

site_url('admin/users/getList/'.$offset.'/user_id/'.(($order_direction==='asc')?'desc':'asc'));

change user_id to whatever column you have and create links using this you can create a nice function to create these links.

site_url()

refers to url_helper ( https://ellislab.com/codeigniter/user-guide/helpers/url_helper.html )

Also remember to use the offset you passed from the url in your model and change the pagination module as needed.

This is a general overview of how this can be achieved in codeigniter, I am using something like this for my application, so I know it works. You will need to write your own code, but you will know where to go from here.

0


source


I found the best program so far which does whatever I am after it is called https://datatables.net/examples/styling/bootstrap.html

I had to use this because anti-aliasing paging doesn't work with sorting methods.

0


source







All Articles