Welcome Guest, Not a member yet? Register   Sign In
Passing multiple values to view from controller
#1

[eluser]ross_c[/eluser]
Hi

Ive been exploring codeigniter for a week or so now and am really enjoying using it. Previously I have had a windows .net background and have really wanted to move to open source solutions / community based technologies.

I have been making a bit of a customer database for myself whilst learning how to use the codeigniter framework. I have come unstuck in this particular situation and may be going about it the wrong way. I have a controller that displays several views here is my controller code:

Code:
function view($id)
{
  // set common properties
  $data['title'] = 'Customer Details';
  $data['link_back'] = anchor('customer/index/','Back to list of customers',array('class'=>'back'));
  
  // get customer details
  $data['customer'] = $this->Customer_model->get_by_id($id)->row();
  //$customer_id = 123;

  $this->load->view('includes/header');
  $this->load->view('includes/navigation');
  $this->load->view('includes/customer_navigation');
  $this->load->view('includes/end_navigation');
  $this->load->view('customerView', $data);
  $table = $this->getCustomerContacts($id);
  $this->load->view('subContactList', $table);
  $this->load->view('includes/footer');
}

the subContactList view contains contacts that have the same customer_id as the customer in the customerView. Basically my question is how do i also pass the $customer_id to the subContactList view as well as the $table variable so that i can use it on my subContactList view to create a new customer and link back using the id etc. hope that makes sense. If it helps below is the code from the getCustomerContacts function.

Code:
public function getCustomerContacts($customer_id)
{
  
  $uri_segment = 3;
  $offset = 0;
  
  // load data
  $contacts = $this->Contact_model->get_by_customer($customer_id)->result();
  
  // generate table data
  $this->load->library('table');
  $this->table->set_empty(" ");
  $this->table->set_heading('Title', 'Name', 'Surname', 'Direct Dial', 'Actions');
  $i = 0 + $offset;
  foreach ($contacts as $contact)
  {
   $this->table->add_row($contact->title,$contact->first_name,$contact->surname, $contact->direct_dial,
    anchor('customer/viewcontact/'.$contact->id . '/' . $customer_id,'view',array('class'=>'view')).' '.
    anchor('customer/editcontact/'.$contact->id. '/' . $customer_id,'update',array('class'=>'update')).' '.
    anchor('contact/delete/'.$contact->id,'delete',array('class'=>'delete','onclick'=>"return confirm('Are you sure want to delete this contact?')"))
   );
  }
  $data['table'] = $this->table->generate();
  

}

Hope my question makes sense, many thanks in advance.

Ross
#2

[eluser]TheFuzzy0ne[/eluser]
Welcome to the CodeIgniter forums! I'm glad you're enjoying CodeIgniter. Smile

All of the code below is untested, and may contain bugs, but I hope you might find it useful.

Your model method:
Code:
public function getCustomerContacts($customer_id)
{
    /* ... */
    
    // Your model was not returning anything. You should just return the table HTML.
    return $this->table->generate();
}

Your controller method:
Code:
function view($id)
{
    // set common properties
    $data['title'] = 'Customer Details';
    $data['link_back'] = anchor('customer/index/','Back to list of customers',array('class'=>'back'));
  
    // get customer details
    $data['customer'] = $this->Customer_model->get_by_id($id)->row();

    // Pass the customer ID into the views.
    $data['customer_id'] = $id;
    
    // Pass the table into the $data variable.
    $data['table'] = $this->getCustomerContacts($id);

    // Set the view data. Now all $data vars are available to all views.
    $this->load->vars($data);
    
    $this->load->view('includes/header');
    $this->load->view('includes/navigation');
    $this->load->view('includes/customer_navigation');
    $this->load->view('includes/end_navigation');
    $this->load->view('customerView');  
    $this->load->view('subContactList');
    $this->load->view('includes/footer');
}

I would also recommend the following:

Check that a customer with the given ID exists, and react accordingly. At present, you're will get a load of errors if you use a customer ID that doesn't exist.

Name your views consistently. You seem to have a mixture of camelcase, and lowercase separated with underscores.

Consider moving your block of view-loading code into its own method. This means that you won't have to repeat yourself. It also means you can add some extra flexibility, such as being able to define which partial view to load, or perhaps to hide the header/footer if you wanted to. For example:

Code:
protected function _load_template($data = array(), $options = array())
{
    $this->load->vars($data);
    
    if ( ! isset($options['show_header']) OR $options['show_header'] !== FALSE)
    {
        $this->load->view('includes/header');
    }
    
    $this->load->view('includes/navigation');
    $this->load->view('includes/customer_navigation');
    $this->load->view('includes/end_navigation');
    
    if (isset($options['partial']))
    {
        if ( ! is_array($options['partial']))
        {
            $options['partial'] = array($options['partial']);
        }
        
        foreach ($options['partial'] as $partial)
        {
            $this->load->view($partial);
        }
    }
    
    if ( ! isset($options['show_footer']) OR $options['show_footer'] !== FALSE)
    {
        $this->load->view('includes/footer');
    }
}

Now, let's hide the header and footer, but load customerView:
Code:
$this->_load_template($data, array(
    'show_header' => FALSE,
    'show_footer' => FALSE,
    'partial' => 'customerView',
));

What if we want to load multiple views within our template?
Code:
$this->_load_template($data, array(
    'partial' => array(
        'customerView',
        'subContactList',
    ),
));

I know it looks like a lot of code, but it's very simple and gives you flexibility. You can add more logic to make it fit into your situation. Keep it as simple as possible, and add extra logic when you need a new feature. If you don't need to hide the header or footer, don't bother implementing the logic to do so. If you only need to load a single view within the template, then don't add the logic to support multiple sub-views being loaded.

The advantage of this is that you save repeating yourself, and you have a central place to maintain for your view loading logic. If you want to reuse it, you can have a Customer_controller which you can put it into, and then extend that, so you don't have to keep repeating that code.

I'm not sure which views are loaded every time, and which are the situational views, so I've just taken a guess just to illustrate what I'm trying to say.

Hope this helps.
#3

[eluser]ross_c[/eluser]
Thank you very much for the informative detailed reply. I will work through your recommendations and report back with my progress I appreciate the advice on improving the structure of my code and naming conventions too.
#4

[eluser]ross_c[/eluser]
Just to give a bit of feed back. I have gone through my code and made the suggested changes I fully understand the benefits of what you suggested and think the loader method is great. I created a base controller called My_controller ( i followed this blog post guide here to create the base controller) and put the view loader method in this. Below is my base controller that my others are now extending from:

Code:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class MY_controller extends CI_Controller {


function __construct()
{
  parent::__construct();
  
  // load library
  $this->load->library(array('table','form_validation'));
  
  // load helper
  $this->load->helper('url');
  
  // load model
  $this->load->model('Customer_model','',TRUE);

  $this->load->model('Contact_model','',TRUE);

  $this->load->model('Device_model','',TRUE);
}

protected function _load_template($data = array(), $options = array())
{
    $this->load->vars($data);
    
     $this->load->view('includes/header');
  $this->load->view('includes/navigation');

  if ( ! isset($options['show_customer_nav']) OR $options['show_customer_nav'] !== FALSE)
    {
        $this->load->view('includes/customer_navigation');
    }

  $this->load->view('includes/end_navigation');
    
    if (isset($options['partial']))
    {
        if ( ! is_array($options['partial']))
        {
            $options['partial'] = array($options['partial']);
        }
        
        foreach ($options['partial'] as $partial)
        {
            $this->load->view($partial);
        }
    }
    
    // option to show or hide footer based on options

    //if ( ! isset($options['show_footer']) OR $options['show_footer'] !== FALSE)
    //{
        $this->load->view('includes/footer');
    //}
}




}

I have also now gained a better understanding of passing arrays and passing arrays inside arrays to my views.

Thanks again for your help much appreciated.
#5

[eluser]TheFuzzy0ne[/eluser]
I'm glad you found it useful.

Remember: If you find yourself repeating code, you probably just put it in the wrong place for the second time.

Thanks for posting back. Smile




Theme © iAndrew 2016 - Forum software by © MyBB