1

I am doing a small application in Yii Framework for that my database is something like this

 === Invoices ===
  id (PK)
  customer_id
  invoice_title
  order_no
  invoice_issue_date
  due_date
  description

  === Customers ===
  id (PK)
  email_address
  customer_name
  address
  city
  state
  postal_code
  description

I have rendered the Customer model in Invoice model so that I can enter all the values for both models in a single Invoice form.But there is one problem,let us assume that I have a customer name xyz which I had saved before.Now when I am going to again fill the Customer name with xyz,it should show all the fields of both models like invoice_title,order_no,invoice_issue_date,due_date,description,email_address,customer_name,address etc. in that input fields of the form so that I don't have to re-enter all the fields again.So how this can be achive in Yii framework.Any help and suggestions will be highly appreciable.More clarification on codes that I have done can be shared if needed. Please help me out.I am totally stuck here.

Kai
  • 38,985
  • 14
  • 88
  • 103
NewUser
  • 12,713
  • 39
  • 142
  • 236
  • 1
    You could send an AJAX request when the name was filled (or on every keystroke and attempt search with the partial name), find the related data and send it back to the view. Then, with said data, update the form. – adamors Jun 28 '12 at 11:34
  • 1
    thanks @Ors.For the reply!!!Actually I don't have any good idea about Ajax..So can you tell me more about it? – NewUser Jun 28 '12 at 14:39
  • 1
    You should consult documentations/books then; [jQuery's](http://api.jquery.com/jQuery.ajax/) is enough in this case. – adamors Jun 28 '12 at 15:03
  • ok, won't a customer have many invoices? how do you plan to select which invoice's information to fill up in the form? – bool.dev Jul 06 '12 at 13:37
  • yes..the customer has many invoices. I have selected the customer name from the dropdown option which already has been saved.Now when I will select the name it should fetch all the details of that customer within the form. – NewUser Jul 06 '12 at 13:42

3 Answers3

1

To do this as everyone has already mentioned you need ajax, and some javascript. The logic is something like this:

  1. When a value is selected in the dropdown for customer name, trigger an ajax call to retrieve the information about that user. This can be easily done with the ajax option, which is available as an additional htmlOption for some html element helpers in CHtml, as part of clientChange.

    echo $form->dropDownList($model,'customer_name',CHtml::listData(Customers::model()->findAll(),'id','customer_name'),
       array(// htmlOptions
         'ajax'=>array(// special htmlOption through clientChange, for ajax
               'type'=>'GET', 
               'url'=>$this->createUrl('controllername/customerdetails'),// action that will generate the data
               'data'=>'js:"id="+$(this).val()',// this is the data that we are sending to the action in the controller
               'dataType'=>'json',// type of data we expect back from the server
               'success'=>'js:updateFields'// a javascript function that will execute when the request completes successfully
         )
       )
     );
    

    The documentation for the above options for ajax can be seen in jquery's ajax documentation.

  2. Then in the server side find the particular customer, and send a response to the browser. Example:

    // in the controllername code an action that will return the values as json
    public function actionCustomerdetails($id){
        $var=Customers::model()->findByPk($id);
        echo CJSON::encode($var);
    }
    
  3. When you receive the server response populate the respective fields. This can be done in the success function callback for ajax, in the above code it was updateFields:

    Yii::app()->clientScript->registerScript('update','
        function updateFields(data, textStatus, jqXHR){
            // select each input field by id, and update its value
            $("#Customers_postal_code").val(data.postal_code);
            $("#Customers_city").val(data.city);
            $("#Customers_address").val(data.address);
            // similarly update the fields for the other inputs
        }
    ');
    

Notes: Your customer can have many invoices, so the question will be which invoice to select given a customer name. That's something you'll have to handle, i think my answer has enough code to get you going.

To know the input field ids, you can simply check the generated html.

bool.dev
  • 17,508
  • 5
  • 69
  • 93
  • let me know if you need any clarifications – bool.dev Jul 06 '12 at 16:39
  • can you tell me what is the meaning of `jqXHR` in `function updateFields(data, textStatus, jqXHR){}`?Why it is used here? – NewUser Jul 11 '12 at 15:31
  • did you read the documentation link i added in the answer? [jqXHR is a jquery object type](http://api.jquery.com/types/#jqXHR). a google search will easily return tons of links. it is used for ajax calls. – bool.dev Jul 11 '12 at 18:06
  • Ya I got it..by the way by this it is inserting the id in customer_name field of the database. – NewUser Jul 12 '12 at 18:04
  • yeah, can you guess why that is happening? – bool.dev Jul 12 '12 at 18:07
  • I think for this `$var=Customers::model()->findByPk($id);` – NewUser Jul 12 '12 at 18:10
  • not really, but it is related to that line of code, think a little harder, you are close... – bool.dev Jul 12 '12 at 18:12
  • I think as I have used `'data'=>'js:"id="+$(this).val()'`in `htmlOptions` and in this `id` is assigned with that value.Is it right? – NewUser Jul 12 '12 at 18:16
  • again, this is related(closer than before), but not the source of the issue, one more step back and you will get it... – bool.dev Jul 12 '12 at 18:18
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/13811/discussion-between-newuser-and-bool-dev) – NewUser Jul 12 '12 at 18:21
0

Have you checked the Yii Autocomplete widget? And you wouldn't have to worry about AJAX implementation. It does it for you.

Yii Framework: CJui AutoComplete

A more customized autocomplete solution in this link.

Yii Framework: custom-autocomplete-display-and-value-submission

Orlymee
  • 2,349
  • 1
  • 22
  • 24
Arjun Abhynav
  • 543
  • 4
  • 15
  • Thank you @Arjun for your reply.I have seen the two links that you have made post in your answer.I think the 2nd post can be use in this.But there is no ajax is found so I have to click on submit form.But my requirement is getting all the values of a specific field from the related models without clicking on submit button.So how to do that? – NewUser Jul 03 '12 at 15:16
0

You could do this in two stages, so that:

  1. When the view is initially displayed, the customer is asked for their email address or customer_name.

  2. The Controller Action that the form is submitted to then retrieves data from the Customer model for the submitted email address or customer_name (I'll use email_address in my example below). Once retrieved, you can display your Single Invoice Form View with the data pre-populated for the customer if available.

This concept could then be implemented as follows:

<?php
// file: controllers/InvoiceController.php
class InvoiceController extends CController
{
  // ... other controller functions

  public function actionCreate($step = null)
  {
    $invoice  = new Invoice;
    $customer = new Customer;

    # Form has been submitted:
    if ( isset($_POST['Customer']) )
    {
      # The submitted form was Step 1:
      if ( $step == 1 )
      {
        # make sure the submitted email address is valid
        $customer->setAttributes($_POST['Customer']);
        if ( $customer->validate(array('email_address')) )
        {
          # retrieve the customer by email_address
          $customer = Customer::model()->findByAttributes(array('email_address' => $_POST['Customer']['email_address']));
        }

        $this->render('createstep2', array('invoice' => $invoice, 'customer' => $customer));
      }

      # The submitted form was Step 2:
      elseif ( $step == 2 )
      {
        $income->setAttributes($_POST['Invoice']);
        $customer->setAttributes($_POST['Customer']);

        # save the data
        if ( $customer->save() )
        {
          $invoice->customer_id = $customer->id;
          if ( $invoice->save() )
          {
            $this->redirect(array('view', 'id' => $invoice->id));
          }
        }

        # display any errors
        $this->render('createstep2', array('invoice' => $invoice, 'customer' => $customer));
      }
    } 

    $this->render('createstep1', array('invoice' => $invoice, 'customer' => $customer));
  }

  // ... other controller functions
}
?>

You could split that to two separate Controller Actions if you wish.

For Step 1 View, you could then have the following:

<!-- file: views/invoice/createstep1.php -->
<h1>Create Invoice: Step 1</h1>

<div class="form">

<?php
$form = $this->beginWidget('CActiveForm', array(
  'id'=>'invoice-form',
  'enableAjaxValidation'=>false,
  'action'=>array('invoice/create','step' => 1)
)); 
?>

  <?php echo $form->errorSummary($customer); ?>

  <div class="row">
    <?php echo $form->labelEx($customer,'email_address'); ?>
    <?php echo $form->textField($customer,'email_address', array('size'=>60,'maxlength'=>255)); ?>
    <?php echo $form->error($customer,'email_address'); ?>
  </div>

  <div class="row buttons">
    <?php echo CHtml::submitButton('Next'); ?>
  </div>

<?php $this->endWidget(); ?>

</div><!-- form -->

Step 2 view, you could then look like what you already have. Maybe something like:

<!-- file: views/invoice/createstep2.php -->
<h1>Create Invoice: Step 2</h1>

<div class="form">

<?php
$form = $this->beginWidget('CActiveForm', array(
  'id'=>'invoice-form',
  'enableAjaxValidation'=>false,
  'action'=>array('invoice/create','step' => 2)
)); 
?>

  <?php echo $form->errorSummary($invoce); ?>
  <?php echo $form->errorSummary($customer); ?>

  <h2>Customer Details</h2>
  <div class="row">
    <?php echo $form->labelEx($customer,'email_address'); ?>
    <?php echo $form->textField($customer,'email_address', array('size'=>60,'maxlength'=>255)); ?>
    <?php echo $form->error($customer,'email_address'); ?>
  </div>

  <!-- If the customer already exists, these field should be pre-populated: -->

  <div class="row">
    <?php echo $form->labelEx($customer,'customer_name'); ?>
    <?php echo $form->textField($customer,'customer_name', array('size'=>60,'maxlength'=>255)); ?>
    <?php echo $form->error($customer,'customer_name'); ?>
  </div>

  <div class="row">
    <?php echo $form->labelEx($customer,'address'); ?>
    <?php echo $form->textField($customer,'address', array('size'=>60,'maxlength'=>255)); ?>
    <?php echo $form->error($customer,'address'); ?>
  </div>

  <div class="row">
    <?php echo $form->labelEx($customer,'city'); ?>
    <?php echo $form->textField($customer,'city', array('size'=>60,'maxlength'=>255)); ?>
    <?php echo $form->error($customer,'city'); ?>
  </div>

  <div class="row">
    <?php echo $form->labelEx($customer,'state'); ?>
    <?php echo $form->textField($customer,'state', array('size'=>60,'maxlength'=>255)); ?>
    <?php echo $form->error($customer,'state'); ?>
  </div>

  <div class="row">
    <?php echo $form->labelEx($customer,'postal_code'); ?>
    <?php echo $form->textField($customer,'postal_code', array('size'=>60,'maxlength'=>255)); ?>
    <?php echo $form->error($customer,'postal_code'); ?>
  </div>

  <div class="row">
    <?php echo $form->labelEx($customer,'description'); ?>
    <?php echo $form->textField($customer,'description', array('size'=>60,'maxlength'=>255)); ?>
    <?php echo $form->error($customer,'description'); ?>
  </div>


  <h2>Order Details</h2>

  <div class="row">
    <?php echo $form->labelEx($invoice,'invoice_title'); ?>
    <?php echo $form->textField($invoice,'invoice_title', array('size'=>60,'maxlength'=>255)); ?>
    <?php echo $form->error($invoice,'invoice_title'); ?>
  </div>

  <div class="row">
    <?php echo $form->labelEx($invoice,'order_no'); ?>
    <?php echo $form->textField($invoice,'order_no', array('size'=>60,'maxlength'=>255)); ?>
    <?php echo $form->error($invoice,'order_no'); ?>
  </div>

  <div class="row">
    <?php echo $form->labelEx($invoice,'invoice_issue_date'); ?>
    <?php $form->widget('zii.widgets.jui.CJuiDatePicker', array(
        'model'     => $invoice,
        'attribute' => 'invoice_issue_date',
        'value'     => $invoice->invoice_issue_date,
        'options'   => array(
          'showButtonPanel' => false,
          'changeYear'      => true,
          'dateFormat'      => 'yy-mm-dd',
        ),
      )); ?>
    <?php echo $form->error($invoice,'invoice_issue_date'); ?>
  </div>

  <div class="row">
    <?php echo $form->labelEx($invoice,'due_date'); ?>
    <?php $form->widget('zii.widgets.jui.CJuiDatePicker', array(
        'model'     => $invoice,
        'attribute' => 'due_date',
        'value'     => $invoice->due_date,
        'options'   => array(
          'showButtonPanel' => false,
          'changeYear'      => true,
          'dateFormat'      => 'yy-mm-dd',
        ),
      )); ?>
    <?php echo $form->error($invoice,'due_date'); ?>
  </div>

  <div class="row">
    <?php echo $form->labelEx($invoice,'description'); ?>
    <?php echo $form->textField($invoice,'description', array('size'=>60,'maxlength'=>255)); ?>
    <?php echo $form->error($invoice,'description'); ?>
  </div>


  <div class="row buttons">
    <?php echo CHtml::submitButton('Create'); ?>
  </div>

<?php $this->endWidget(); ?>

</div><!-- form -->
Turgs
  • 1,729
  • 1
  • 20
  • 49
  • 1
    @newuser Does this answer your question, or do you have and feedback? – Turgs Jul 02 '12 at 21:40
  • Thank you @Turgs for your reply.Sorry I had not visited this forum since a couple of days so I had not replied your answer.yes..I have seen your code.I have not implemented this.But from this code I think I have to `click on save`,but `I don't want to click on the button`.I just want that when `one value is entered in a single input`,it will `fetch all the values in the formfields of the corresponding model`without clicking on `save button`.So for this I think there is need ajax.So how this can be achived? – NewUser Jul 03 '12 at 14:58