Advanced DOM Manipulations

In a previous job, while working with a CMS in its infant stage, I often used jQuery to add a custom user experience to quickly satisfy a customer while giving time to the Scrum so that those features could be built in future sprints.

In one instance, a customer wanted one credit application for both individual and joint applicants. If the user needed to fill out a joint application, the client wanted to use the same form, as oppose to submitting two individual form. Furthermore, the client needed the same required field on the Individual form to be the same as the Joint Applicant form.

Review the final result.

Review the code on jsFiddle

Operating in an enterprise-level Content Management System, I needed to create the form with ALL the fields present on page load; I couldn’t just add the fields for the Joint application via javascript after page load. I also needed a way to toggle the required fields of the Joint application – if the user submitted an Individual app, the required fields for the Joint applicant need not to be required, and vice versa. Finally, I needed to make it look good and sensible to the end user.

The Process

As mentioned, I first had to create the form from inside a CMS. I had the ability to only specify a form field’s name and its ‘required’ state. I could not add classes to the form items. Furthermore, I had no ability to create form sections! Forms were basically delivered in one large UL element.

My first step was to separate the Joint Applicant fields from the Individual fields. When I created the form in the CMS, I made sure all the Joint Application fields were grouped together (prepending all Joint Application fields with ‘Co-Applicant’), and same with the fields for the Individual fields. I created two objects to act as pointers to let me keep track of the two group of fields within the DOM.

var primary = {
    start: 0,
    end: $('label:contains(Co-Applicant):first').parent().prev().index('#JointApp form > ul > li'),
    name: "Primary_Form_Section"
}

var coapp = { start: primary.end,
        end: $('label:contains(Co-Applicant):last').parent().index('#JointApp form > ul > li'),
        name: "Coapp_Form_Section"
}

Next, I built new containers for the Individual and Joint Applicant fields, and began placing the necessary fields in those containers.

    primary.items = 
    $('#JointApp form > ul > li').filter(function(i) { return filterEls(i, primary.start, primary.end); });
    
    coapp.items = $('#JointApp form > ul > li').filter(function(i) { return filterEls(i, coapp.start, coapp.end); })
    
    coapp.items.each(function(i, el) {
        var label = $(el).children('label');
        label.html(label.html().replace('Co-Applicant ', ''));
    });
    
    primary.items.appendTo('#'+primary.name+'-Tab').wrapAll('<ul/>');
    coapp.items.appendTo('#'+coapp.name+'-Tab').wrapAll('<ul/>');

Finally, I created a Tabbed interface so the user could easily toggle back and forth between Joint and Individual applications.

    	
	// Function used to make tabs for new tab panel
	function customTab(text, target, isActive) {
	   
		return $('<a href="#'+target+'" id="'+target+'" rel="'+target+'-Tab">'+text+'</a>').addClass('customTab ' + (isActive ? "active_customTab":"")).click(function(e) {
			e.preventDefault();
			var id = this.rel;
		   
			$('.active_customTab').removeClass('active_customTab');
		   
			$('.customTabContent').hide();
		   
			$(this).addClass('active_customTab');
		   
			$('#'+id).show();
		   
		});
	}
    
    // Menu for custom Tab Pane;
    $('<div class="tabMenuContainer"></div>').append(
        $('<ul id="customTabMenu" class=""></ul>').append(
            $('<li></li>').append(customTab('Primary Applicant', primary.name, true)))
        .append(
            $('<li></li>').append(customTab('Co-Applicant', coapp.name))
        )).prependTo('#CustomTabs');
    
    $('#customTabMenu').after('<br clear="both"/>');

    primary.items.last().after(
        $('<li class="text-right continueBtn"><a href="#formTop">Continue to Co-Applicant Part</a></li>')
            .click(function(e) { 
                $('html, body').animate({
                    scrollTop: $("#CustomTabs").offset().top
                }, 300);
                
                $('#'+coapp.name).trigger('click'); 
            }
        ).hide()					
    );
   
    // Activate first tab of tab panel
    $('a.customTab:first').addClass('active_customTab');

That’s the basics of the project. If you have read this far, you should really check out the code on jsFiddle and Review the final result.