Support

Account

Home Forums Front-end Issues Sending user to Tab on validation errors Reply To: Sending user to Tab on validation errors

  • I’ve expanded on this to just highlight the field group and the tab in which fields below have errors. I haven’t tested this code extensively but it should work with all of the simple fields (everything except repeater, flexible content, etc). Those may work as well but I haven’t tested them.

    This is sort of the approach I’ve been needing when I start getting a lot of fields and a lot of tabs on a page template.

    
    (function($) {
    
    	$(function() {
    
    		var TabErrorMarker = {
    			errorClass: 'acf-tab-validation-errors',
    			errors: [],
    			fields: [],
    			init: function($form) {
    				var self = this;
    				this.$form = $form;
    				this.$tabs = this.$form.find('.acf-tab-wrap a');
    
    				var $groups = this.$form.find('.acf-postbox');
    
    				// Find all Field groups in form and then find all tabs in form.
    				// Then build a tabs array where each tab keeps track of its parent field group as well as its child fields.
    
    				$groups.each(function(gIndex) {
    					var $group = $(this),
    					gKey = $group.attr('id').replace('acf-', ''),
    					$tabs = $group.find('.acf-tab-wrap a');
    
    					$tabs.each(function(index) {
    						self.addTabObject($(this), {
    							index: $group.index(),
    							$el: $group
    						});
    					});
    				});
    
    				// ACF Hooks for adding/removing error classes on tabs and field groups of error fields hidden behind tabs.
    
    				acf.add_filter('validation_complete', this.proxy(this.validateTabs));
    
    				acf.add_action('validation_begin', this.proxy(this.removeErrors));
    
    				acf.add_action('invalid_field', this.proxy(this.addTabError));
    				return this;
    			},
    			addTabObject($tabLink, group) {
    				// Build the tab object before handing it off to the 'this.fields' array.
    				var self = this,
    				key = $tabLink.attr('data-key'),
    				$label = group.$el.find('.acf-field-tab').filter('[data-key="' + key + '"]'),
    				$fields = $label.nextUntil('.acf-field-tab'),
    
    				tab = {
    					index: $tabLink.index(),
    					key: key,
    					$link: $tabLink,
    					$label: $label
    				};
    
    				$fields.each(function(fIndex) {
    					self.addFieldObject($(this), tab, group);
    				});
    
    				return tab;
    			},
    			addFieldObject($field, tab, group) {
    				var key = $field.attr('data-key'),
    				type = $field.attr('data-type'),
    				$input = $field.find('#acf-' + key),
    				field = {
    					index: $field.index(),
    					key: key,
    					type: type,
    					$input: $input,
    					tab: tab,
    					group: group
    				};
    
    				this.fields.push(field);
    				return field;
    			},
    			validateTabs: function(json, $form){
    
    				// Check for validation errors and begin looping through all tabs in the form if any.
    				
    				this.errors = (json.errors || []);
    				if(this.errors.length) {
    					this.addErrors();
    				} else {
    					this.removeErrors();
    				}
    				return json;
    			},
    			addErrors: function() {
    
    				// Loop over each error, find the field related to the error and mark the parent tab with an error class.
    						
    				this.errors.forEach(this.proxy(function(err, index) {
    					var key = this.errors[index].input.replace('acf[', '').replace(']', ''),
    					$field = this.$form.find('.acf-field[data-key="' + key + '"]');
    
    					this.addTabError($field, this.$form);
    				}));
    				return this;
    			},
    			removeErrors: function () {
    
    				// Loop over each tab and check if all fields below that tab are error free.
    				// If so, remove the error class from the tab.
    						
    				var self = this;
    
    				this.$tabs.each(function(i) {
    					self.removeTabError($(this));
    				});
    				return this;
    			},
    			addTabError: function($field) {
    
    				// Add the error class to the tab and field group of any field that has validation errors
    
    				var index = $field.index();
    				key = $field.attr('data-key'),
    				$input = $field.find('[id="acf-' + key + '"]'),
    				$tabLabels = $($field.get(0), this.$form).prevAll('.acf-field-tab'),
    				tabKey = $tabLabels.eq(0).attr('data-key'),
    				$tab = $('.acf-tab-wrap a[data-key=' + tabKey + ']', this.$form),
    				$group = $tab.closest('.acf-postbox');
    
    				$tab.addClass(this.errorClass);
    				$group.addClass(this.errorClass);
    				return this;
    			},
    			removeTabError: function($tabLink) {
    
    				// Remove the error class to the tab and field group of any field that has validation errors
    				
    				var self = this,
    				$tabLinks = $tabLink.parents('ul').find('li a');
    
    				// Loop over each tab link, find all fields with an error class 
    				$tabLinks.each(function(i) {
    					var $tab = $(this),
    					$group = $tab.closest('.acf-postbox'),
    					$errorFields = $tab.parents('.acf-fields').children('.acf-field.acf-error');
    
    					if ($errorFields.length === 0) {
    						$tab.removeClass(self.errorClass);
    						$group.removeClass(self.errorClass);
    					}
    				});
    				return this;
    			},
    			proxy: function(func) {
    
    				// Simple proxy function to ensure the context of a callback function is this object's instance.
    				
    				var self = this;
            return function() {
                return func.apply(self, arguments);
            };
    			}
    		};
    
    		
    
    		$(function () {
    
    			var $form = $('#wpbody form');
    
    			TabErrorMarker.init($form);
    		});
    
    	});
    
    })(jQuery);
    

    And here is the CSS to highlight the tabs and field groups that have errors.

    
    .acf-tab-button.acf-tab-validation-errors {
    	border-color: #F55E4F !important;
    	color: #F55E4F !important;
    }
    .acf-postbox.acf-tab-validation-errors > .hndle {
    	border-color: #F55E4F !important;
    	color: #F55E4F !important;
    }
    .acf-postbox.acf-tab-validation-errors > .handlediv {
    	color: #F55E4F !important;
    }
    

    The result looks like the image below.

    ACF Tab Error Highlight