Implement Address block with chainSelect state/county
authorColeman Watts <coleman@civicrm.org>
Tue, 31 Dec 2019 17:45:00 +0000 (12:45 -0500)
committerCiviCRM <info@civicrm.org>
Wed, 16 Sep 2020 02:13:20 +0000 (19:13 -0700)
ext/afform/core/ang/af/Field.js
ext/afform/core/ang/af/Fieldset.js
ext/afform/core/ang/af/Join.js
ext/afform/core/ang/af/Repeat.js
ext/afform/core/ang/af/fields/ChainSelect.html [new file with mode: 0644]
ext/afform/core/ang/blockAddressDefault.aff.html [new file with mode: 0644]
ext/afform/core/ang/blockAddressDefault.aff.json [new file with mode: 0644]
ext/afform/gui/ang/afGuiEditor.css
ext/afform/gui/ang/afGuiEditor/inputType/ChainSelect.html [new file with mode: 0644]

index 5bf7c9b8db6782ad0554dcc8a107ae87d4090277..554eb8221804ac8c4b533184ead2546ff7aa3464 100644 (file)
@@ -1,7 +1,7 @@
 (function(angular, $, _) {
   var id = 0;
   // Example usage: <div af-fieldset="myModel"><af-field name="do_not_email" /></div>
-  angular.module('af').directive('afField', function() {
+  angular.module('af').directive('afField', function(crmApi4) {
     return {
       restrict: 'E',
       require: ['^^afForm', '^^afFieldset', '?^^afJoin', '?^^afRepeatItem'],
             }, [])
           };
         };
+
+        // ChainSelect - watch control field & reload options as needed
+        if ($scope.defn.input_type === 'ChainSelect') {
+          $scope.$watch('dataProvider.getFieldData()[defn.input_attrs.controlField]', function(val) {
+            if (val) {
+              var params = {
+                where: [['name', '=', $scope.fieldName]],
+                select: ['options'],
+                loadOptions: true,
+                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);
+                });
+            }
+          });
+        }
       }
     };
   });
index a62483cc85f01ee2aa11c90de0825aa4767cc19f..4294ee7c58ec728008a09ad5bf393c240d711802 100644 (file)
@@ -21,6 +21,9 @@
         this.getName = function() {
           return this.modelName;
         };
+        this.getEntityType = function() {
+          return this.afFormCtrl.getEntity(this.modelName).type;
+        };
         this.getFieldData = function() {
           var data = this.getData();
           if (!data.length) {
index 35d6b350ed45c83422fcaa562d7661e29ae228ae..16de30079f8cb5eb5bc686ba44ef147fa55ca20a 100644 (file)
@@ -15,6 +15,9 @@
         },
         controller: function($scope) {
           var self = this;
+          this.getEntityType = function() {
+            return this.entity;
+          };
           this.getData = function() {
             var data, fieldsetData;
             if (self.repeatItem) {
index 52337c9276598e1a74ed20047822f332bb08ba50..bb25e5f820e9f9c012666e99efdc98283f5b6b84 100644 (file)
@@ -19,7 +19,7 @@
         },
         controller: function($scope) {
           this.getItems = $scope.getItems = function() {
-            var data = $scope.afJoin ? $scope.afJoin.getData() : $scope.afFieldset.getData();
+            var data = getEntityController().getData();
             while ($scope.min && data.length < $scope.min) {
               data.push(getRepeatType() === 'join' ? {} : {fields: {}, joins: {}});
             }
           }
           this.getRepeatType = getRepeatType;
 
+          function getEntityController() {
+            return $scope.afJoin || $scope.afFieldset;
+          }
+          this.getEntityController = getEntityController;
+
           $scope.addItem = function() {
             $scope.getItems().push(getRepeatType() === 'join' ? {} : {fields: {}});
           };
           this.getFieldData = function() {
             return this.afRepeat.getRepeatType() === 'join' ? this.item : this.item.fields;
           };
+
+          this.getEntityType = function() {
+            return this.afRepeat.getEntityController().getEntityType();
+          };
         }
       };
     });
diff --git a/ext/afform/core/ang/af/fields/ChainSelect.html b/ext/afform/core/ang/af/fields/ChainSelect.html
new file mode 100644 (file)
index 0000000..a3cb1e2
--- /dev/null
@@ -0,0 +1 @@
+<input crm-ui-select="{data: select2Options, multiple: defn.input_attrs.multiple, placeholder: defn.input_attrs.placeholder}" id="{{ fieldId }}" ng-model="dataProvider.getFieldData()[fieldName]" />
diff --git a/ext/afform/core/ang/blockAddressDefault.aff.html b/ext/afform/core/ang/blockAddressDefault.aff.html
new file mode 100644 (file)
index 0000000..76d21e4
--- /dev/null
@@ -0,0 +1,10 @@
+<div class="af-container af-layout-inline">
+  <af-field name="street_address" />
+  <af-field name="location_type_id" />
+</div>
+<div class="af-container af-layout-inline">
+  <af-field name="city" />
+  <af-field name="state_province_id" />
+  <af-field name="country_id" />
+  <af-field name="postal_code" />
+</div>
diff --git a/ext/afform/core/ang/blockAddressDefault.aff.json b/ext/afform/core/ang/blockAddressDefault.aff.json
new file mode 100644 (file)
index 0000000..2a26888
--- /dev/null
@@ -0,0 +1,6 @@
+{
+  "title": "Address Block (default)",
+  "block": "Contact",
+  "join": "Address",
+  "repeat": true
+}
index 9616e743469237133971631968e91c671af220bd..bfa548f3498cca20fb5798f5a8e5fbc641395e80 100644 (file)
 #afGuiEditor .af-gui-field-input-type-select .input-group-btn {
   position: initial;
 }
+#afGuiEditor .af-gui-field-input-type-chainselect .input-group .dropdown-toggle,
 #afGuiEditor .af-gui-field-input-type-select .input-group .dropdown-toggle {
   padding: 3px 11px;
 }
diff --git a/ext/afform/gui/ang/afGuiEditor/inputType/ChainSelect.html b/ext/afform/gui/ang/afGuiEditor/inputType/ChainSelect.html
new file mode 100644 (file)
index 0000000..bca0c94
--- /dev/null
@@ -0,0 +1,8 @@
+<div class="form-inline">
+  <div class="input-group">
+    <input autocomplete="off" class="form-control" placeholder="{{ ts('Select') }}" title="{{ ts('Click to add placeholder text') }}" ng-model="getSet('input_attrs.placeholder')" ng-model-options="{getterSetter: true}" type="text" />
+    <div class="input-group-btn">
+      <button type="button" class="btn btn-default disabled dropdown-toggle"><i class="crm-i fa-caret-down"></i></button>
+    </div>
+  </div>
+</div>