Alex Budenchuk Alex Budenchuk - 4 months ago 20
Javascript Question

symfony form: set entity at client side

I'm quite new with symfony2, so I'm probably not aware about some important details when working with forms...
How can I set an entity for a form at client side, after page rendering?

On my page I have several products and a form. I need to choose product which I want to edit, by click. So I need to modify the form data at client side. Here is my simplified template code:

<div class="product" onclick="editFormProduct({
id: '{{ product1.id }}',
name: '{{ product1.name }}'
price: '{{ product1.price }}'
})">
<span>{{ product1.name }}</span>
<span>{{ product1.price }}</span>
</div>

<div class="product" onclick="editFormProduct({
id: '{{ product2.id }}',
name: '{{ product2.name }}'
price: '{{ product2.price }}'
})">
<span>{{ product2.name }}</span>
<span>{{ product2.price }}</span>
</div>

{{ form_start(form, {'attr': {'id': 'form-product'}}) }}

{{ form_widget(form.name) }}
{{ form_widget(form.price) }}

{{ form_end(form) }}

<script type="text/javascript">
function editFormProduct(product) {
$('#form-product').find('input[id=form_id]').val(product.id);
$('#form-product').find('div[name=name] input').val(product.name);
$('#form-product').find('div[name=price] input').val(product.price);
}
</script>


But when I try to submit it, I get an error: "Neither the property "id" nor one of the methods "addId()"/"removeId()", "setId()", "id()", "__set()" or "__call()" exist and have public access in class "AppBundle\Entity\Product"

Any help will be appreciated.

Answer

Well, I've found the solution at least. Not sure whether it's the cleanest one, but it works. To choose the object for editing dynamically, at client side, you need to do these simple steps:

  1. Create a hidden field in a form which will keep the id of the object you've currently chosen for editing.
  2. Save the id of an object into this field by click (or whatever you like) at client side, using javascript.
  3. After the form submission, use the id from this field to fetch the needed object from DB and apply changes to it. Here is a controller sample:

    class DefaultController extends Controller
    {
        public function indexAction(Request $request)
        {
            $repository = $this->getDoctrine()->getRepository('AppBundle:Product');
    
            //when the form is submitted, get edit_id
            //probably there is a better way to get the form data 
            //before creating the $form object...
            if ($request->request->get('form') != null)
                $editedProduct = $repository->find($request->request->get('form')['edit_id'] - 1);
            else
                $editedProduct = new Product();
    
            $form = $this->createFormBuilder($editedProduct)
                ->add('name', 'text')
                ->add('price', 'text')
                //hidden field that will store the id of the edited object
                //must not to be mapped, as it doesn't belong to the entity
                ->add('edit_id', 'hidden', array('mapped' => false));
    
            $form->handleRequest($request);
    
            ...
        }
    }
    

    And the corresponding template sample is almost equal to the original one:

    <div class="product" onclick="editFormProduct({
            id: '{{ product1.id }}',
            name: '{{ product1.name }}'
            price: '{{ product1.price }}'
       })">
       <span>{{ product1.name }}</span>
       <span>{{ product1.price }}</span>
    </div>
    
    <div class="product" onclick="editFormProduct({
            id: '{{ product2.id }}',
            name: '{{ product2.name }}'
            price: '{{ product2.price }}'
        })">
        <span>{{ product2.name }}</span>
        <span>{{ product2.price }}</span>
    </div>
    
    {{ form_start(form, {'attr': {'id': 'form-product'}}) }}
    
        {{ form_widget(form.name) }}
        {{ form_widget(form.price) }}
    
    {{ form_end(form) }}
    
    <script type="text/javascript">
        function editFormProduct(product) {
            //fill the edit_id field with the chosen product id
            $('#form-product').find('#form_edit_id').val(product.id);
            $('#form-product').find('#form_name').val(product.name);
            $('#form-product').find('#form_price').val(product.price);
        }
    </script>
    
Comments