Merge pull request #24115 from kcristiano/5.52-token
[civicrm-core.git] / ext / afform / core / ang / af / afField.component.js
index cbfd84d826b10026f3b52a75ca474dcfd1566b82..aa83eac8fbae9dced69200437e697e5dc774f4c0 100644 (file)
     controller: function($scope, $element, crmApi4, $timeout, $location) {
       var ts = $scope.ts = CRM.ts('org.civicrm.afform'),
         ctrl = this,
+        // Prefix used for SearchKit explicit joins
+        namePrefix = '',
         boolOptions = [{id: true, label: ts('Yes')}, {id: false, label: ts('No')}],
+        // Used to store chain select options loaded on-the-fly
+        chainSelectOptions = null,
         // Only used for is_primary radio button
         noOptions = [{id: true, label: ''}];
 
@@ -29,6 +33,9 @@
 
         $element.addClass('af-field-type-' + _.kebabCase(ctrl.defn.input_type));
 
+        if (this.defn.name !== this.fieldName) {
+          namePrefix = this.fieldName.substr(0, this.fieldName.length - this.defn.name.length);
+        }
 
         if (ctrl.defn.search_range) {
           // Initialize value as object unless using relative date select
 
         // ChainSelect - watch control field & reload options as needed
         if (ctrl.defn.input_type === 'ChainSelect') {
-          $scope.$watch('dataProvider.getFieldData()[defn.input_attrs.control_field]', function(val) {
-            if (val) {
+          var controlField = namePrefix + ctrl.defn.input_attrs.control_field;
+          $scope.$watch('dataProvider.getFieldData()["' + controlField + '"]', function(val) {
+            // After switching option list, remove invalid options
+            function validateValue() {
+              var options = $scope.getOptions(),
+                value = $scope.dataProvider.getFieldData()[ctrl.fieldName];
+              if (_.isArray(value)) {
+                _.remove(value, function(item) {
+                  return !_.find(options, function(option) {return option.id == item;});
+                });
+              } else if (value && !_.find(options, function(option) {return option.id == value;})) {
+                $scope.dataProvider.getFieldData()[ctrl.fieldName] = '';
+              }
+            }
+            if (val && (typeof val === 'number' || val.length)) {
+              $('input[crm-ui-select]', $element).addClass('loading').prop('disabled', true);
               var params = {
-                where: [['name', '=', ctrl.fieldName]],
-                select: ['options'],
-                loadOptions: ['id', 'label'],
-                values: {}
+                name: ctrl.afFieldset.getFormName(),
+                modelName: ctrl.afFieldset.getName(),
+                fieldName: ctrl.fieldName,
+                joinEntity: ctrl.afJoin ? ctrl.afJoin.entity : null,
+                values: $scope.dataProvider.getFieldData()
               };
-              params.values[ctrl.defn.input_attrs.control_field] = val;
-              crmApi4($scope.dataProvider.getEntityType(), 'getFields', params, 0)
+              crmApi4('Afform', 'getOptions', params)
                 .then(function(data) {
-                  ctrl.defn.options = data.options;
+                  $('input[crm-ui-select]', $element).removeClass('loading').prop('disabled', !data.length);
+                  chainSelectOptions = data;
+                  validateValue();
                 });
+            } else {
+              chainSelectOptions = null;
+              validateValue();
             }
-          });
+          }, true);
         }
 
         // Wait for parent controllers to initialize
             var index = ctrl.getEntityIndex();
             uniquePrefix = entityName + (index ? index + 1 : '') + (joinEntity ? '.' + joinEntity : '') + '.';
           }
-          // Set default value based on url
+          // Set default value from url with uniquePrefix + fieldName
           if (urlArgs && urlArgs[uniquePrefix + ctrl.fieldName]) {
-            $scope.dataProvider.getFieldData()[ctrl.fieldName] = urlArgs[uniquePrefix + ctrl.fieldName];
+            setValue(urlArgs[uniquePrefix + ctrl.fieldName]);
+          }
+          // Set default value from url with fieldName only
+          else if (urlArgs && urlArgs[ctrl.fieldName]) {
+            $scope.dataProvider.getFieldData()[ctrl.fieldName] = urlArgs[ctrl.fieldName];
           }
           // Set default value based on field defn
           else if (ctrl.defn.afform_default) {
-            $scope.dataProvider.getFieldData()[ctrl.fieldName] = ctrl.defn.afform_default;
+            setValue(ctrl.defn.afform_default);
           }
         });
-
       };
 
+      // Set default value; ensure data type matches input type
+      function setValue(value) {
+        if (ctrl.defn.input_type === 'Number' && ctrl.defn.search_range) {
+          if (!_.isPlainObject(value)) {
+            value = {
+              '>=': +(('' + value).split('-')[0] || 0),
+              '<=': +(('' + value).split('-')[1] || 0),
+            };
+          }
+        } else if (ctrl.defn.input_type === 'Number') {
+          value = +value;
+        } else if (ctrl.defn.search_range && !_.isPlainObject(value)) {
+          value = {
+            '>=': ('' + value).split('-')[0],
+            '<=': ('' + value).split('-')[1] || '',
+          };
+        }
+
+        $scope.dataProvider.getFieldData()[ctrl.fieldName] = value;
+      }
+
       // Get the repeat index of the entity fieldset (not the join)
       ctrl.getEntityIndex = function() {
         // If already in a join repeat, look up the outer repeat
       // Params for the Afform.submitFile API when uploading a file field
       ctrl.getFileUploadParams = function() {
         return {
-          entityName: ctrl.afFieldset.modelName,
+          modelName: ctrl.afFieldset.getName(),
           fieldName: ctrl.fieldName,
           joinEntity: ctrl.afJoin ? ctrl.afJoin.entity : null,
           entityIndex: ctrl.getEntityIndex(),
       };
 
       $scope.getOptions = function () {
-        return ctrl.defn.options || (ctrl.fieldName === 'is_primary' && ctrl.defn.input_type === 'Radio' ? noOptions : boolOptions);
+        return chainSelectOptions || ctrl.defn.options || (ctrl.fieldName === 'is_primary' && ctrl.defn.input_type === 'Radio' ? noOptions : boolOptions);
       };
 
       $scope.select2Options = function() {