Skip to content

Instantly share code, notes, and snippets.

@romaricdrigon
Created August 21, 2013 07:46
Show Gist options
  • Star 34 You must be signed in to star a gist
  • Fork 8 You must be signed in to fork a gist
  • Save romaricdrigon/6291435 to your computer and use it in GitHub Desktop.
Save romaricdrigon/6291435 to your computer and use it in GitHub Desktop.
Using AngularJS on Symfony2 forms
{# This is an extension of Twig Form Theme #}
{# We redefine form elements, so they are binded with Angular model #}
{% extends "form_div_layout.html.twig" %}
{# Make data available to current scope as $scope.data - will not work with hidden fields #}
{% block widget_attributes %}
{% spaceless %}
ng-model="data['{{ full_name }}']" {# we add Angular ng-model #}
id="{{ id }}" name="{{ full_name }}"{% if read_only %} readonly="readonly"{% endif %}{% if disabled %} disabled="disabled"{% endif %}{% if required %} required="required"{% endif %}{% if max_length %} maxlength="{{ max_length }}"{% endif %}{% if pattern %} pattern="{{ pattern }}"{% endif %}
{% for attrname, attrvalue in attr %}{% if attrname in ['placeholder', 'title'] %}{{ attrname }}="{{ attrvalue|trans({}, translation_domain) }}" {% else %}{{ attrname }}="{{ attrvalue }}" {% endif %}{% endfor %}
{% endspaceless %}
{% endblock widget_attributes %}
{# current controller submit() will called, instead of submitting the form #}
{% block form_start %}
{% spaceless %}
{% set method = method|upper %}
{% if method in ["GET", "POST"] %}
{% set form_method = method %}
{% else %}
{% set form_method = "POST" %}
{% endif %}
<form name="{{ form.vars.name }}" ng-submit="submit()" method="{{ form_method|lower }}" action="{{ action }}"{% for attrname, attrvalue in attr %} {{ attrname }}="{{ attrvalue }}"{% endfor %}{% if multipart %} enctype="multipart/form-data"{% endif %}>
{% if form_method != method %}
<input type="hidden" name="_method" value="{{ method }}" />
{% endif %}
{% endspaceless %}
{% endblock form_start %}
// An example controller binded to the form
function FormCntl($scope, $compile) {
// Consider using FosJsRouting bundle, if you want to use a Symfony2 route
$scope.formUrl = "http://url-to-fetch-my-form";
// Data from the form will be binded here
$scope.data = {};
// Method called when submitting the form
$scope.submit = function() {
// Add your own logic, for example show the response your received from Symfony2
// We have to explictly compile the data received, to parse AngularJS tags
$scope.formResponse = $compile(data)($scope);
}
}
<!-- Form (AngularJS) template -->
<div
ng-include="formUrl"
ng-bind-html-unsafe="formResponse"
ng-controller="FormCntl"
></div>
@RemiAWE
Copy link

RemiAWE commented Jul 10, 2014

Thank you ! It helps me a lot, great work.
And by the way, I'm wondering how do you deal with ng-model directives in hidden inputs to fetch their data ? (I mean the _token field for CSRF). I know two solutions:

  • Using ng-value directive but there is a conflict with the value attribute in TWIG. I can't display this two attributes togethers.
  • Using:
    {% if value is not empty %} ng-init="data['{{ full_name }}']='{{ value }}'" {% endif %} in the {% block widget_attributes %} (it's useful for the update forms).

@khal3d
Copy link

khal3d commented Sep 1, 2014

Thanks for sharing ..

I did some changes on widget_attributes block to make hidden fields work

{% extends "form_div_layout.html.twig" %}

{% block widget_attributes %}{% spaceless %}
{{ parent() }}
{% if type == 'hidden' %}
    ng-init="data['{{ full_name }}'] = '{{value}}'"
{% else %}
    ng-model="data['{{ full_name }}']"
{% endif %}
{% endspaceless %}{% endblock widget_attributes %}

@romaricdrigon
Copy link
Author

Hello @RemiAWE and @khal3d, thanks for the tips !
I'll create a new revision with those, i've also to check if Symfony2 form_theme did not changed!

@lemonlab
Copy link

lemonlab commented Jan 2, 2015

Works fine ! Thanks a lot for sharing.

For those who don't need a global customization, if you want to override JUST a specific form processed with Angular, you can do :

{% form_theme form 'AcmeBlogBundle:Form:field-angular.html.twig' %}

And in a seperate file here : Acme/BlogBundle/Ressources/views/Form/field-angular.html.twig

{% block widget_attributes %}
    {% spaceless %}
        ng-model="data['{{ full_name }}']" {# we add Angular ng-model #}
        id="{{ id }}" name="{{ full_name }}"{% if read_only %} readonly="readonly"{% endif %}{% if disabled %} disabled="disabled"{% endif %}{% if required %} required="required"{% endif %}{% if max_length %} maxlength="{{ max_length }}"{% endif %}{% if pattern %} pattern="{{ pattern }}"{% endif %}
        {% for attrname, attrvalue in attr %}{% if attrname in ['placeholder', 'title'] %}{{ attrname }}="{{ attrvalue|trans({}, translation_domain) }}" {% else %}{{ attrname }}="{{ attrvalue }}" {% endif %}{% endfor %}
    {% endspaceless %}
{% endblock widget_attributes %}

@afkplus
Copy link

afkplus commented Nov 12, 2015

Thanks a lot! Helped me a lot! Just one small suggestion:

Wouldn't it be better to remove the action attribute from the form tag in the template, or at least wrap it with {% if action %} like others? I am suggesting this because ng-submit doesn't prevent the default action if it sees action, data-action, or x-action attributes.

@ngodfraind
Copy link

It helped me too.

http://stackoverflow.com/questions/29408879/add-custom-options-to-symfony-form
This is usefull ifyou want to change the ng-model properties.

I posted my solution. Github displayed it twice on my screen... I tought it was a duplicata and removing one post removed everything -_-. I'm too lazy to post again but I basically combined this gist with the stackoverflow post.

@andyexeter
Copy link

Thanks for sharing!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment