Skip to content



This hook alters the definition of some AngularJS HTML partials and allows you to inject AngularJS changesets.


This hook is available in CiviCRM 4.7.21 and later.




  • array $angular - \Civi\Angular\Manager


Directly modify the attributes of a form and add a translated attribute

function example_civicrm_alterAngular($angular) {
    ->alterHtml('~/crmMailing/EditMailingCtrl/2step.html', function(phpQueryObject $doc) {
      $doc->find('[ng-form="crmMailingSubform"]')->attr('cat-stevens', 'ts(\'wild world\')');

You can also add a listener and a class that responds to that lisener. In this example the system loops through each field to find the appropriate ones that it needs to modify, and changes the field defintion.

 // Listener to modify fields
    ['CRM_Classname_AfformMetadataInjection', 'preprocess']);

Within your AfformMetadataInjection.php file:


use Civi\Core\Event\GenericHookEvent;
use Civi\Core\Service\AutoService;

 * Provides ability to modify fields prior to rendering
 * @internal
 * @service
class CRM_Classname_AfformMetadataInjection extends AutoService {

   * @param \Civi\Core\Event\GenericHookEvent $e
   * @see CRM_Utils_Hook::alterAngular()
  public static function preprocess($event) {
    $changeSet = \Civi\Angular\ChangeSet::create('modifySomething')
      ->alterHtml(';\\.aff\\.html$;', function($doc, $path) {
        // You can conditionally restrict it to certain Forms or change them all
        if ($path == '~/formname/formname.aff.html') {
          // Run through each field and modify the ones that are applicable
          foreach (pq('af-field', $doc) as $afField) {
            $fieldName = $afField->getAttribute('name');

            // Obtain Field Definition
            $fieldDefn = self::getFieldDefinition($afField);
            if (!$fieldDefn) {

            if ($fieldName == 'myfield') {
              // Get some data from API calls if you choose to use below

              // Change the default value
              $fieldDefn['afform_default'] = xyz;

              // If you have an option field you can change the values as below
              $fieldDefn['options'] = \CRM_Utils_JS::writeObject(array_map(['\CRM_Utils_JS', 'encode'], $optionsReturn));

              // Write out the field definition back to the field
              pq($afField)->attr('defn', htmlspecialchars(\CRM_Utils_JS::writeObject($fieldDefn), ENT_COMPAT));





    // Write out the changset

  public static function getFieldDefinition($afField) {
    $existingFieldDefn = trim(pq($afField)->attr('defn') ?: '');
    if ($existingFieldDefn && $existingFieldDefn[0] != '{') {
      // If it's not an object, don't mess with it.
      return NULL;
    return $existingFieldDefn ? \CRM_Utils_JS::getRawProps($existingFieldDefn) : [];


Hot Tips

After any modification to your angular hooks it is essential to do a system flush to ensure that your changes are seen right away.

FormBuilder caches the changesets and forms so normally your changes don't register until this reset has happened.