dev/core#3828 Fix required fields check to account 0
[civicrm-core.git] / ang / crmUi.js
index d8b56772bba0a5d718da96d6be533476c6d69b8b..cd59407bd268d45dee6b3b595959103f7c1d8ab6 100644 (file)
@@ -67,7 +67,7 @@
     // Simple wrapper around $.crmDatepicker.
     // example with no time input: <input crm-ui-datepicker="{time: false}" ng-model="myobj.datefield"/>
     // example with custom date format: <input crm-ui-datepicker="{date: 'm/d/y'}" ng-model="myobj.datefield"/>
-    .directive('crmUiDatepicker', function () {
+    .directive('crmUiDatepicker', function ($timeout) {
       return {
         restrict: 'AE',
         require: 'ngModel',
           element
             .crmDatepicker(scope.crmUiDatepicker)
             .on('change', function() {
-              var requiredLength = 19;
-              if (scope.crmUiDatepicker && scope.crmUiDatepicker.time === false) {
-                requiredLength = 10;
-              }
-              if (scope.crmUiDatepicker && scope.crmUiDatepicker.date === false) {
-                requiredLength = 8;
-              }
-              ngModel.$setValidity('incompleteDateTime', !($(this).val().length && $(this).val().length !== requiredLength));
+              // Because change gets triggered from the $render function we could be either inside or outside the $digest cycle
+              $timeout(function() {
+                var requiredLength = 19;
+                if (scope.crmUiDatepicker && scope.crmUiDatepicker.time === false) {
+                  requiredLength = 10;
+                }
+                if (scope.crmUiDatepicker && scope.crmUiDatepicker.date === false) {
+                  requiredLength = 8;
+                }
+                ngModel.$setValidity('incompleteDateTime', !(element.val().length && element.val().length !== requiredLength));
+              });
             });
         }
       };
           // In cases where UI initiates update, there may be an extra
           // call to refreshUI, but it doesn't create a cycle.
 
-          if (ngModel) {
+          if (ngModel && !attrs.ngOptions) {
             ngModel.$render = function () {
               $timeout(function () {
                 // ex: msg_template_id adds new item then selects it; use $timeout to ensure that
             }
           }
 
-          // If using ngOptions, wait for them to load
+          // If using ngOptions, the above methods do not work because option values get rewritten.
+          // Skip init and do something simpler.
           if (attrs.ngOptions) {
-            $timeout(init);
+            $timeout(function() {
+              element.crmSelect2(scope.crmUiSelect || {});
+              // Ensure widget is updated when model changes
+              ngModel.$render = function () {
+                element.val(ngModel.$viewValue || '').change();
+              };
+            });
           } else {
             init();
           }
         restrict: 'EA',
         scope: {
           crmUiTabSet: '@',
-          tabSetOptions: '@'
+          tabSetOptions: '<'
         },
         templateUrl: '~/crmUi/tabset.html',
         transclude: true,
             // handled in crmUiTab ctrl
             return;
           }
-          if (attrs.crmIcon.substring(0,3) == 'fa-') {
-            $(element).prepend('<i class="crm-i ' + attrs.crmIcon + '" aria-hidden="true"></i> ');
-          }
-          else {
-            $(element).prepend('<span class="icon ui-icon-' + attrs.crmIcon + '"></span> ');
+          if (attrs.crmIcon) {
+            if (attrs.crmIcon.substring(0,3) == 'fa-') {
+              $(element).prepend('<i class="crm-i ' + attrs.crmIcon + '" aria-hidden="true"></i> ');
+            }
+            else {
+              $(element).prepend('<span class="icon ui-icon-' + attrs.crmIcon + '"></span> ');
+            }
           }
+
           // Add crm-* class to non-bootstrap buttons
           if ($(element).is('button:not(.btn)')) {
             $(element).addClass('crm-button');
             $timeout(function() {
               var newPageTitle = _.trim($el.html()),
                 newDocumentTitle = scope.crmDocumentTitle || $el.text(),
-                h1Count = 0;
-              document.title = $('title').text().replace(documentTitle, newDocumentTitle);
-              // If the CMS has already added title markup to the page, use it
-              $('h1').not('.crm-container h1').each(function() {
-                if ($(this).hasClass('crm-page-title') || _.trim($(this).html()) === pageTitle) {
-                  $(this).addClass('crm-page-title').html(newPageTitle);
-                  $el.hide();
-                  ++h1Count;
+                h1Count = 0,
+                dialog = $el.closest('.ui-dialog-content');
+              if (dialog.length) {
+                dialog.dialog('option', 'title', newDocumentTitle);
+                $el.hide();
+              } else {
+                document.title = $('title').text().replace(documentTitle, newDocumentTitle);
+                // If the CMS has already added title markup to the page, use it
+                $('h1').not('.crm-container h1').each(function () {
+                  if ($(this).hasClass('crm-page-title') || _.trim($(this).html()) === pageTitle) {
+                    $(this).addClass('crm-page-title').html(newPageTitle);
+                    $el.hide();
+                    ++h1Count;
+                  }
+                });
+                if (!h1Count) {
+                  $el.show();
                 }
-              });
-              if (!h1Count) {
-                $el.show();
+                pageTitle = newPageTitle;
+                documentTitle = newDocumentTitle;
               }
-              pageTitle = newPageTitle;
-              documentTitle = newDocumentTitle;
             });
           }