User Tools

Site Tools


php:onetomanyjquery

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

php:onetomanyjquery [2013/03/16 17:40] (current)
Line 1: Line 1:
 +==== Implement one-to-many relation with jQuery in forms ====
 +12.10.2010
  
 +
 +This example is built on:
 +
 +<code yml>
 +# config/​doctrine/​schema.yml
 +
 +SbPerson:
 +    columns:
 +        peid: { type: integer, primary: true, autoincrement:​ true, unsigned:​true }
 +        firstname: string(100)
 +        lastname: string(100)
 +        CNP: string(13)
 +        identity_docs:​ string(100)
 +        DOB: date
 +        phone: string(30)
 +        email: string(30) ​     ​
 +    relations:
 +        SbAddress: { type: many, class: SbAddress, local: peid, foreign: person_id }
 +
 +SbAddress:
 +    columns:
 +        person_id: { type: integer, unsigned: true }
 +        street: string(80)
 +        number: string(10)
 +        addition: string(10)
 +        city: string(50)
 +        county: string(50)
 +        postal_code:​ string(8)
 +    indexes:
 +        streetIdx:
 +            fields: [street] ​       ​
 +</​code>​
 +
 +
 +=== NEW CASE ===
 +
 +First, let's take a quick look at the final result:
 +
 +{{:​php:​sy_frmnewpa.jpg| New Person/​Address }}
 +
 +The + sign will add one at the time Address form. For example, if you want 3 Addresses, you'll press 3 times in a row (you should do this operation *before* actually putting data there). The - sign of course, will remove a form at the time.
 +
 +
 +== The template ==
 +
 +
 +The code inside the form template looks something as:
 +
 +<code html>
 +<table class="​ui-widget ui-widget-content genTable"​ id="​tblNewPerson">​
 +    <?php echo $form ?>
 +    <tr>
 +        <td colspan="​2">​
 +            <a id="​person_add_address"​ href="#"><​img src="/​images/​plus-icon.png"​ alt="​Add Address"/></​a>​
 +            <a id="​person_delete_address"​ href="#"><​img src="/​images/​minus-icon.png"​ alt="​Remove Address"/></​a>​
 +        </td>
 +    </tr>
 +    <​tr><​td colspan="​2"​ id="​tblAddress"></​td></​tr>​
 +</​table>​
 +</​code>​
 +
 +
 +== The Javascript ==
 +
 +
 +Implement the actions for + and - buttons.
 +
 +<code javascript>​
 +$().ready(function() {
 +    $('#​person_add_address'​).click(function(){
 +        new_address_count = new_address_count + 1;
 +        $('#​tblNewPerson #​tblAddress'​).html(person_add_new_address(new_address_count));​
 +    });
 +    ​
 +    $('#​person_delete_address'​).click(function() {
 +        new_address_count = new_address_count - 1;
 +        if (new_address_count >= 0) {
 +            $('#​tblNewPerson #​tblAddress'​).html(person_add_new_address(new_address_count));​
 +        }
 +    });
 +});    ​
 +</​code>​
 +
 +Function //​person_add_new_address//​ is as follow:
 +
 +<code javascript>​
 +var new_address_count = 0;
 +function person_add_new_address(num){
 +    return $.ajax({
 +        type: '​GET',​
 +        url: '/​person_add_new_address?​howmany='​+num,​
 +        async: false
 +    }).responseText;​
 +}
 +</​code>​
 +
 +
 +== Routing ==
 +
 +In **routing.yml** we implement the URL:
 +
 +<​code>​
 +person_add_address:​
 +    url:   /​person_add_new_address
 +    param: { module: readers, action: personAddNewAddress }
 +</​code>​
 +
 +
 +== Action File ==
 +
 +We continue with //​personAddNewAddress//​ action inside readers module (the file will be readers/​actions/​actions.class.php):​
 +
 +<code php>
 +class readersActions extends sfActions {
 +    ...
 +    public function executePersonAddNewAddress(sfWebRequest $request) {
 +        $this->​forward404unless($request->​isXmlHttpRequest());​
 +        $howmany = intval($request->​getParameter("​howmany"​));​
 +        $this->​form = new SbPersonForm();​
 +        $this->​form->​addNewAddress($howmany);​
 +        return $this->​renderPartial('​addNewAddress',​array('​form'​ => $this->​form,​ '​howmany'​ => $howmany));
 +    }
 +    ...
 +}
 +</​code>​
 +
 +== The Partial Template ==
 +
 +This will be //​readers/​templates/​__addNewAddress//:​
 +
 +<code html>
 +<tr>
 +    <td colspan="​2">​
 +        <?php echo $form['​newAddress'​] ?>
 +    </td>
 +</tr>
 +</​code>​
 +
 +== Form Modifications ==
 +
 +SbPersonForm will get a new method (the one what actually embed the Address subforms)
 +
 +<code php>
 +class SbPersonForm extends BaseSbPersonForm {
 +    public function configure() {
 +        ...
 +        // EMBEDDED RELATION
 +        $this->​embedRelation('​SbAddress'​);​
 +    }
 +    ....
 +    public function addNewAddress($howmany){
 +        $new_addresses = new BaseForm();
 +
 +        for ($i=1; $i <= $howmany; $i++){
 +            $addressObj = new SbAddress();​
 +            $addressObj->​setPersonId($this->​getObject());​
 +            $new_addresses->​embedForm($i,​ new SbAddressForm($addressObj));​
 +        }
 +    ​
 +        $this->​embedForm('​newAddress',​ $new_addresses);​
 +    }
 +    ....
 +</​code>​
 +
 +Also, overwrite the //bind// method inside SbPersonForm.
 +
 +<code php>
 +    /**
 +     ​* ​
 +     * recreates the structure of the request data in the created form before the form binding ​
 +     */
 +    public function bind(array $taintedValues = null, array $taintedFiles = null) {
 +        $new_addresses = new BaseForm();
 +        if (array_key_exists('​newAddress',​ $taintedValues)) {
 +            foreach($taintedValues['​newAddress'​] as $key => $value){
 +                $addressObj = new SbAddress();​
 +                $addressObj->​setPersonId($this->​getObject());​
 +                $new_addresses->​embedForm($key,​new SbAddressForm($addressObj));​
 +            }
 +        }
 +        $this->​embedForm('​newAddress',​ $new_addresses);​
 +        parent::​bind($taintedValues,​ $taintedFiles);​
 +    } 
 +</​code>​
 +
 +
 +=== EDIT CASE ===
 +
 +
 +First a quick look at the final result:
 +
 +{{:​php:​sy_frmeditpa.jpg| Editing person-address }}
 +
 +
 +== Form Modifications ==
 +
 +In order to be able to delete addresses in edit more, we'll implement a "​Delete"​ field in SbAddressForm:​
 +
 +<code php>
 +class SbAddressForm extends BaseSbAddressForm {
 +    public function configure() {
 +        unset($this['​person_id'​]);​
 +        ​
 +        // insert only if is NOT new (edit mode)        ​
 +        if ($this->​object->​exists()) {
 +            $this->​widgetSchema['​delete'​] = new sfWidgetFormInputCheckbox();​
 +            $this->​validatorSchema['​delete'​] = new sfValidatorPass();​
 +        }
 +    }
 +}
 +</​code>​
 +
 +SbPersonFrom will be modified as follow:
 +
 +<code php>
 +class SbPersonForm extends BaseSbPersonForm {
 +    protected $address_tobe_deleted = array(); // add this
 +    ​
 +    /**
 +     * UPDATED BIND HERE!
 +     * recreates the structure of the request data in the created form before the form binding ​
 +     */
 +    public function bind(array $taintedValues = null, array $taintedFiles = null) {
 +        $new_addresses = new BaseForm();
 +        if (array_key_exists('​newAddress',​ $taintedValues)) {
 +            foreach($taintedValues['​newAddress'​] as $key => $value){
 +                $addressObj = new SbAddress();​
 +                $addressObj->​setPersonId($this->​getObject());​
 +                $new_addresses->​embedForm($key,​new SbAddressForm($addressObj));​
 +            }
 +        }
 +        $this->​embedForm('​newAddress',​ $new_addresses);​
 +
 +        if (array_key_exists('​SbAddress',​ $taintedValues)) {
 +            foreach ($taintedValues['​SbAddress'​] as $key => $value) {
 +                if (isset($value['​delete'​]) && $value['​id'​]) {
 +                    $this->​address_tobe_deleted[$key] = $value['​id'​];​
 +                }
 +            }
 +        }
 +        ​
 +        parent::​bind($taintedValues,​ $taintedFiles);​
 +    }
 +
 +    // this will do the delete part
 +    protected function doUpdateObject($values) {
 +        if ($this->​address_tobe_deleted) {
 +            foreach ($this->​address_tobe_deleted as $key => $value) {
 +                unset($values['​SbAddress'​][$key]);​
 +                unset($this->​object['​SbAddress'​][$key]);​
 +                Doctrine::​getTable('​SbAddress'​)->​findOneById($value)->​delete();​
 +            }
 +        }
 +        $this->​getObject()->​fromArray($values);​
 +    }
 +}       
 +</​code>​
 +
 +
 +More references [[http://​prendreuncafe.com/​blog/​post/​2009/​11/​29/​Embedding-Relations-in-Forms-with-Symfony-1.3-and-Doctrine | here]] and [[ http://​tech.cibul.org/​embedded-forms-with-symfony-1-4-and-jquery/​ | here ]].
php/onetomanyjquery.txt ยท Last modified: 2013/03/16 17:40 (external edit)