Search code examples
phpjqueryajaxcodeignitercodeigniter-2

How to display data from code igniter model with AJAX request


My Codeigniter site has side panel and when i click or select any options in side panel appropriate content will appear to the main panel.

Home page URL is http://localhost/main/userinfo/allusers When i click female button URL is http://localhost/main/userinfo/female

enter image description here i have following output when i made the Ajax request. Where i did the mistake? enter image description here

Controller(main.php)

class Main extends CI_Controller {
public function __construct() {
    parent::__construct();           
    $this->load->model('userinfo_model'); 
}
public function index() {}   
public function userinfo($gender) {
    $this->load->view('home/inc/header_view');        
    $usermain_data['user_info'] = $this->userinfo_model->get_data($gender);
    $this->load->view('home/main_view', $usermain_data);
}

Model(userinfo_model.php)

class Userinfo_model extends CI_Model {
function __construct() {
    // Call the Model constructor
    parent::__construct();
}
function get_data($gender) {      
    $this->db->select('*'); 
    if($gender == 'female'){
        $this->db->where('gender', 0); 
    }
    elseif($gender == 'male'){
        $this->db->where('gender', 1); 
    }
    elseif($gender == 'allusers'){
        $gNames = array(0, 1);             
        $this->db->where_in('gender', $gNames);
    } 
    else {
        redirect(base_url() . 'main/userinfo/allusers');
    }
    $query = $this->db->get('tble_userinfo');
    //return $query->result();
    echo(json_encode($query->result())); 
}}

View(main_view.php)

<div class="container">  
<div class="row">
    <div class="col-md-3 side_menu">
        <div class="btn-group" data-toggle="buttons">
            <label class="btn btn-default gender-label" id="lbl-female" onclick="displayfemale()">
                <input type="radio" name="options" id="option1" autocomplete="off">
                <span>Female</span>
            </label>
            <label class="btn btn-default gender-label" id="lbl-male" onclick="displaymale()">
                <input type="radio" name="options" id="option2" autocomplete="off">
                <span>Male</span>
            </label>
        </div> <br> <br> 
        <label class="label nav-label">Age</label>
        <select class="btn nav-age-select" id="ageSelect1" autocomplete="off">
            <option value="18">18</option>
            <option value="19">19</option>
            <option value="20">20</option>       
            <option value="21"  selected="selected">21</option>
            <option value="22">22</option>
            <option value="23">23</option>       
            <option value="24">24</option>
            <option value="25">25</option>

        </select>
        <label class="label nav-label label-to">To</label>
        <select class="btn nav-age-select" id="ageSelect2" autocomplete="off">
            <option value="18">18</option>
            <option value="19">19</option>
            <option value="20">20</option>       
            <option value="21">21</option>
            <option value="22">22</option>
            <option value="23">23</option>       
            <option value="24">24</option>
            <option value="25" selected="selected">25</option>
        </select>

    </div>
    <div class="col-md-8 main-body">
        <div id="userdata">
            <?php
            //foreach ($user_info as $info) {
                //confuse of adding date here with ajax
                //echo $info->content . '<br />' . $info->added_date .'<br />'; 
            //}
            ?>
        </div>         
    </div>
</div>      

<script type="text/javascript"> 
$(document).ready(function () {
    var ajaxUrl     = '<?php echo base_url(); ?>' + 'main/userinfo';        
    var gender      = 'allusers'; // defual 1 for female and male both together

    getAjax(ajaxUrl, gender); 

    $("#lbl-female").click(function () {   
        gender = 'female';
        getAjax(ajaxUrl, gender);  
    });
    $("#lbl-male").click(function () {   
        gender = 'male';
        getAjax(ajaxUrl, gender);  
    });
});     
function getAjax(ajaxUrl, gender){       
    ajaxUrl = ajaxUrl + '/' + gender;                
    $.ajax({
        url: ajaxUrl,
        dataType: "JSON",
        type: "POST",
        success: function (retdata) { 
            $("#userdata").html('');                 
            if(retdata.hasOwnProperty("error")){
                $("#userdata").html('<div">' + retdata.msg + '</div>');  
            }  
            else{    
                $.each(retdata, function(i){    
                    $("#userdata").append(retdata[i].content + '<br>');                       
                });                         
            }

        }
    });          
}


Solution

  • This answer will have main load both genders initially. Rather than use several gender specific URLs the gender buttons will return the html of the selected gender and dynamically change the html of the page.

    main_view.php (with Javascript included)

    <div class="container">  
      <div class="row">
        <div class="col-md-3 side_menu">
          <div class="btn-group" data-toggle="buttons">
            <label class="btn btn-default gender-label" id="lbl-female">
              <input type="radio" name="options" id="option1" autocomplete="off">
              <span>Female</span>
            </label>
            <label class="btn btn-default gender-label" id="lbl-male">
              <input type="radio" name="options" id="option2" autocomplete="off">
              <span>Male</span>
            </label>
          </div> <br> <br> 
          <label class="label nav-label">Age</label>
          <select class="btn nav-age-select" id="ageSelect1" autocomplete="off">
            <option value="18">18</option>
            <option value="19">19</option>
            <option value="20">20</option>       
            <option value="21"  selected="selected">21</option>
            <option value="22">22</option>
            <option value="23">23</option>       
            <option value="24">24</option>
            <option value="25">25</option>
    
          </select>
          <label class="label nav-label label-to">To</label>
          <select class="btn nav-age-select" id="ageSelect2" autocomplete="off">
            <option value="18">18</option>
            <option value="19">19</option>
            <option value="20">20</option>       
            <option value="21">21</option>
            <option value="22">22</option>
            <option value="23">23</option>       
            <option value="24">24</option>
            <option value="25" selected="selected">25</option>
          </select>
        </div>
        <div class="col-md-8 main-body">
          <div id="userdata">
            <?php
            foreach($user_info as $info)
            {
              echo $info->content.'<br />'.$info->added_date.'<br />';
            }
            ?>
          </div>         
        </div>
      </div>
    </div>
    <script>
      $(document).ready(function () {
      var ajaxUrl = '<?php echo base_url(); ?>' + 'main/userinfo';
    
      $("#lbl-female").click(function () {
        getAjax(ajaxUrl, 'female');
      });
      $("#lbl-male").click(function () {
        getAjax(ajaxUrl, 'male');
      });
    });
    function getAjax(URL, gender) {
      $.ajax({
        url: URL,
        data: {gender: gender},
        dataType: "html",
        type: "POST",
        success: function (retdata) {
          $("#userdata").html(retdata);
        }
      });
    }
    </script>
    

    Note that in the $.ajax options with the line

    data: {gender: gender},
    

    we are "posting" data to the controller which will be retrieved by using $this->input->post("gender"); in the AJAX response function.

    Models should not do anything but return data for a controller to use. It is the controller's job to determine what happens based on the data returned. So the redirect() call has been removed.

    Userinfo_model.php

    class Userinfo_model extends CI_Model
    {
      function __construct()
      {
        // Call the Model constructor
        parent::__construct();
      }
    
      // Note the default value for argument $gender. 
      // This means you do not have to pass an argument.
      // If you don't pass one, then !empty($gender) === FALSE
      function get_data($gender = NULL)
      {
        $this->db->select('*');
    
        //select based on gender. 
        //If no $gender then a "where" clause is not needed and both genders are selected
        if(!empty($gender)) 
        //an argument was provided
        {
          if($gender == 'female')
          {
            $this->db->where('gender', 0);
          }
          else
          {
            $this->db->where('gender', 1);
          }
        }
    
        $query = $this->db->get('tble_userinfo');
        return $query->result();
      }
    }
    

    Finally, we get to the controller. index() will display both genders by calling get_data() without passing an argument to the model. After that the AJAX responder userinfo() will return html of the desired gender to the ajax success function. The success function will replace the existing html with the new html echoed from userinfo().

    class Main extends CI_Controller
    {
      public function __construct()
      {
        parent::__construct();
        $this->load->model('userinfo_model');
      }
    
      public function index()
      {
        $usermain_data['user_info'] = $this->userinfo_model->get_data();
        $this->load
            ->view('home/inc/header_view')
            ->view('home/main_view', $usermain_data);
      }
    
      //Only used to respond to an AJAX request
      public function userinfo()
      {
        $gender = $this->input->post('gender');
    
        if(empty($gender))
        {
          $out =  "No Users Found";
        }
        else
        {
          $user_info = $this->userinfo_model->get_data($gender);
          $out = "";
    
          foreach($user_info as $info)
          {
            $out .= $info->content.'<br />'.$info->added_date.'<br />';
          }
        }
        echo $out;
      }
    
    }
    

    This seems reasonably secure so far. The only user input is the gender value. (Never trust user input) Should someone try to pass a value other than the string "female" the database will return only the males info. No user input is presented directly to the database so I don't see any vulnerabilities.