Afform - Use new APIv4 format for option values
authorColeman Watts <coleman@civicrm.org>
Wed, 13 Jan 2021 22:22:30 +0000 (17:22 -0500)
committerColeman Watts <coleman@civicrm.org>
Tue, 19 Jan 2021 17:23:27 +0000 (12:23 -0500)
ext/afform/admin/CRM/AfformAdmin/Utils.php
ext/afform/admin/ang/afGuiEditor/afGuiEditOptions.component.js
ext/afform/admin/ang/afGuiEditor/afGuiEditOptions.html
ext/afform/admin/ang/afGuiEditor/afGuiFieldValue.directive.js
ext/afform/admin/ang/afGuiEditor/elements/afGuiField.component.js
ext/afform/core/afform.php
ext/afform/core/ang/af/Field.js
ext/afform/core/ang/af/fields/CheckBox.html
ext/afform/core/ang/af/fields/Radio.html
ext/afform/mock/ang/testAfform.aff.html

index 5233a295d112efdca41045cd51122bf3edec0ef1..f9fc4d89753f91787d82fa9d21eec21bf22fb1ac 100644 (file)
@@ -27,7 +27,7 @@ class CRM_AfformAdmin_Utils {
     $getFieldParams = [
       'checkPermissions' => FALSE,
       'includeCustom' => TRUE,
-      'loadOptions' => TRUE,
+      'loadOptions' => ['id', 'label'],
       'action' => 'create',
       'select' => ['name', 'label', 'input_type', 'input_attrs', 'required', 'options', 'help_pre', 'help_post', 'serialize', 'data_type'],
       'where' => [['input_type', 'IS NOT NULL']],
@@ -150,19 +150,6 @@ class CRM_AfformAdmin_Utils {
       ],
     ];
 
-    // Reformat options
-    // TODO: Teach the api to return options in this format
-    foreach ($data['entities'] as $entityName => $entity) {
-      foreach ($entity['fields'] as $name => $field) {
-        if (!empty($field['options'])) {
-          $data['entities'][$entityName]['fields'][$name]['options'] = CRM_Utils_Array::makeNonAssociative($field['options'], 'key', 'label');
-        }
-        else {
-          unset($data['entities'][$entityName]['fields'][$name]['options']);
-        }
-      }
-    }
-
     $data['styles'] = [
       'default' => E::ts('Default'),
       'primary' => E::ts('Primary'),
index 764b120a1b0caf29654cdc12178b8c1acd6e0c69..ac1886ec36ed886b0d719cc5e52f23888348040f 100644 (file)
 
       this.$onInit = function() {
         $scope.options = JSON.parse(angular.toJson(ctrl.field.getOptions()));
-        var optionKeys = _.map($scope.options, 'key');
+        var optionKeys = _.map($scope.options, 'id');
         $scope.deletedOptions = _.filter(JSON.parse(angular.toJson(ctrl.field.getDefn().options || [])), function (item) {
-          return !_.contains(optionKeys, item.key);
+          return !_.contains(optionKeys, item.id);
         });
         $scope.originalLabels = _.transform(ctrl.field.getDefn().options || [], function (originalLabels, item) {
-          originalLabels[item.key] = item.label;
+          originalLabels[item.id] = item.label;
         }, {});
       };
 
index 87387636f2a9171df9f18010df6301503bdd6db4..cb9677ac12a1b9ea7cf9a4c6a8fa3aad9b7a5fb0 100644 (file)
@@ -13,7 +13,7 @@
 </div>
 <ul ui-sortable="{connectWith: '.af-gui-edit-options-deleted', cancel: 'input,textarea,button,select,option,a,[contenteditable]'}" ng-model="options" class="af-gui-edit-options-enabled">
   <li ng-repeat="option in options">
-    <div af-gui-editable ng-model="option.label" default-value="originalLabels[option.key]" >{{ option.label }}</div>
+    <div af-gui-editable ng-model="option.label" default-value="originalLabels[option.id]" >{{ option.label }}</div>
     <button type="button" class="btn btn-danger-outline btn-xs pull-right" ng-click="deleteOption(option, $index)" title="{{:: ts('Remove option') }}">
       <i class="crm-i fa-trash"></i>
     </button>
index bb3dc75653111dea72aa21ad85759b5467400607..4fa0dd36df90d3b2a9103911946c3dade7e5f2aa 100644 (file)
@@ -37,7 +37,7 @@
               $el.crmEntityRef({entity: field.fk_entity, select:{multiple: multi}});
             } else if (field.options) {
               var options = _.transform(field.options, function(options, val) {
-                options.push({id: val.key, text: val.label});
+                options.push({id: val.id, text: val.label});
               }, []);
               $el.select2({data: options, multiple: multi});
             } else if (dataType === 'Boolean') {
index 107d4684b94b718f44b1b829a456c2e6ecab0cbc..50781e4a989d8b53004c710e49f7c27b1b3bb2f5 100644 (file)
@@ -18,8 +18,8 @@
 
       $scope.editingOptions = false;
       var yesNo = [
-        {key: '1', label: ts('Yes')},
-        {key: '0', label: ts('No')}
+        {id: '1', label: ts('Yes')},
+        {id: '0', label: ts('No')}
       ];
 
       this.$onInit = function() {
index 49b3ba9f9977a3ed085f98e7e5e955a7fc2baff8..0cecbe4ed11ae7b7eaf87ae08e689d65637d643f 100644 (file)
@@ -386,7 +386,7 @@ function _af_fill_field_metadata($entityType, DOMElement $afField) {
     'action' => 'create',
     'where' => [['name', '=', $afField->getAttribute('name')]],
     'select' => ['label', 'input_type', 'input_attrs', 'options'],
-    'loadOptions' => TRUE,
+    'loadOptions' => ['id', 'label'],
   ];
   if (in_array($entityType, CRM_Contact_BAO_ContactType::basicTypes(TRUE))) {
     $params['values'] = ['contact_type' => $entityType];
@@ -402,10 +402,6 @@ function _af_fill_field_metadata($entityType, DOMElement $afField) {
       // If it's not an object, don't mess with it.
       continue;
     }
-    // TODO: Teach the api to return options in this format
-    if (!empty($fieldInfo['options'])) {
-      $fieldInfo['options'] = CRM_Utils_Array::makeNonAssociative($fieldInfo['options'], 'key', 'label');
-    }
     // Default placeholder for select inputs
     if ($fieldInfo['input_type'] === 'Select') {
       $fieldInfo['input_attrs'] = ($fieldInfo['input_attrs'] ?? []) + ['placeholder' => ts('Select')];
index 12c1726ad001936a3520a559638c1547fb54e285..dcd925ff61971be04505c8222d13c02960d28b2a 100644 (file)
@@ -14,9 +14,9 @@
         var ts = $scope.ts = CRM.ts('afform'),
           closestController = $($el).closest('[af-fieldset],[af-join],[af-repeat-item]'),
           afForm = ctrls[0],
-          boolOptions = [{key: true, label: ts('Yes')}, {key: false, label: ts('No')}],
+          boolOptions = [{id: true, label: ts('Yes')}, {id: false, label: ts('No')}],
           // Only used for is_primary radio button
-          noOptions = [{key: true, label: ''}];
+          noOptions = [{id: true, label: ''}];
         $scope.dataProvider = closestController.is('[af-repeat-item]') ? ctrls[3] : ctrls[2] || ctrls[1];
         $scope.fieldId = afForm.getFormMeta().name + '-' + $scope.fieldName + '-' + id++;
 
@@ -29,7 +29,7 @@
         $scope.select2Options = function() {
           return {
             results: _.transform($scope.getOptions(), function(result, opt) {
-              result.push({id: opt.key, text: opt.label});
+              result.push({id: opt.id, text: opt.label});
             }, [])
           };
         };
               var params = {
                 where: [['name', '=', $scope.fieldName]],
                 select: ['options'],
-                loadOptions: true,
+                loadOptions: ['id', 'label'],
                 values: {}
               };
               params.values[$scope.defn.input_attrs.controlField] = val;
               crmApi4($scope.dataProvider.getEntityType(), 'getFields', params, 0)
                 .then(function(data) {
-                  $scope.defn.options.length = 0;
-                  _.transform(data.options, function(options, label, key) {
-                    options.push({key: key, label: label});
-                  }, $scope.defn.options);
+                  $scope.defn.options = data.options;
                 });
             }
           });
index 8788043cb98d54482367d0ad04c8a988cf529a5e..4bf900396f57f4ac93b81da3ce5ed3027b531ec7 100644 (file)
@@ -1,7 +1,7 @@
 <ul class="crm-checkbox-list" id="{{ fieldId }}" ng-if="defn.options">
-  <li ng-repeat="opt in defn.options track by opt.key" >
-    <input type="checkbox" checklist-model="dataProvider.getFieldData()[fieldName]" id="{{ fieldId + opt.key }}" checklist-value="opt.key" />
-    <label for="{{ fieldId + opt.key }}">{{ opt.label }}</label>
+  <li ng-repeat="opt in defn.options track by opt.id" >
+    <input type="checkbox" checklist-model="dataProvider.getFieldData()[fieldName]" id="{{ fieldId + opt.id }}" checklist-value="opt.id" />
+    <label for="{{ fieldId + opt.id }}">{{ opt.label }}</label>
   </li>
 </ul>
 <input type="checkbox" ng-if="!defn.options" id="{{ fieldId }}" ng-model="dataProvider.getFieldData()[fieldName]" />
index 7237a698c5119c1afa89c687cbc4103b4b1f9436..7bce6be407bd1d037af4b9df04835f94eb8bdc76 100644 (file)
@@ -1,4 +1,4 @@
-<label ng-repeat="opt in getOptions() track by opt.key" >
-  <input class="crm-form-radio" type="radio" ng-model="dataProvider.getFieldData()[fieldName]" ng-value="opt.key" />
+<label ng-repeat="opt in getOptions() track by opt.id" >
+  <input class="crm-form-radio" type="radio" ng-model="dataProvider.getFieldData()[fieldName]" ng-value="opt.id" />
   {{ opt.label }}
 </label>
index 3a105a319043bd217db39337a70594b31cee89fa..e27a53ce2f5136a769a66f1e2ecdcc36f83e325c 100644 (file)
@@ -11,7 +11,7 @@
       <af-field name="first_name" />
       <af-field name="last_name" />
     </div>
-    <af-field name="gender_id" defn="{options: [{key: 1, label: 'Girl'}, {key: 2, label: 'Boy'}, {key: 3, label: 'Other'}]}"/>
+    <af-field name="gender_id" defn="{options: [{id: 1, label: 'Girl'}, {id: 2, label: 'Boy'}, {id: 3, label: 'Other'}]}"/>
     <af-field name="constituent_information.Marital_Status" />
     <af-field name="constituent_information.Marriage_Date" />
     <af-field name="constituent_information.Most_Important_Issue" />