Skip to content

hook_civicrm_alterAngular

Summary

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

Availability

This hook is available in CiviCRM 4.7.21 and later.

Definition

 hook_civicrm_alterAngular(&$angular)

Parameters

  • array $angular - \Civi\Angular\Manager

Examples

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

function example_civicrm_alterAngular($angular) {
  $angular->add(\Civi\Angular\ChangeSet::create('mychanges')
    ->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
  Civi::dispatcher()->addListener('hook_civicrm_alterAngular',
    ['CRM_Classname_AfformMetadataInjection', 'preprocess']);

Within your AfformMetadataInjection.php file:

<?php

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) {
               continue;
            }

            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
    $event->angular->add($changeSet);
  }

  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.