2
\$\begingroup\$

I'm getting into jQuery and I figured I'd start with log in / sign up form. (As an aside, I'm fully aware log in / sign up forms exist ad infinitum; this is more as a learning exercise than anything)

The idea is that the form fields will fade in depending on whether the user wants to log in or sign up to the site. Most of the CSS is via Twitter Bootstrap.

JSFiddle

HTML

 <head>
   <!-- _csrf is generated server side -->
   <meta name="_csrf" content="TEST_CSRF">
 </head>
 <body>
   <div class="login"></div>
   <div class="buttonArea"></div>
 </body>

JavaScript / jQuery

$(document).ready(function () {
  // Variables for various HTML elements
  var initSignUp = $('<input type="button" value="Sign Up" class="btn btn-primary showSignUp">');
  var initLogin  = $('<input type="button" value="Login" class="btn btn-primary showLogin">');
  var sSignUp    = $('<input type="button" value="Sign Up" class="btn btn-primary" id="sSignUp">');
  var sLogin     = $('<input type="button" value="Login" class="btn btn-primary" id="sLogin">');
  var spacer     = $('<input type="button" value="" class="btn btn-primary emptyLabel">');
  var csrf       = $("meta[name='_csrf']").attr("content");

  addButtons(initLogin, spacer, initSignUp);

  function addButtons(left, mid, right) {
    addDivs(1, '.buttonArea', true);
    $('.buttonArea').find('.control-group').addClass('form-horizontal');
    $('.buttonArea').find('.controls').append(left);
    $('.buttonArea').find('.controls').append(mid);
    $('.buttonArea').find('.controls').append(right);
  }

  function fadeIn() {
    $('.hiddenForm').css('visibility', 'visible').hide().fadeIn('slow');
  }

  function clearCanvas() {
    $('.login').empty();
    $('.buttonArea').empty();
  }

  // Helper to insert the actual div element HTML
  function addDivs(numForms, baseClass, skipForm) {
    var formHorizontal = '.form-horizontal';

    var formHtml = '<form id="target" class="form-horizontal" method="post"></form>';
    var csrfHtml = '<input type="hidden" name="_csrf" value="' + csrf + '">';
    var controlGroupDiv = '<div class="control-group"><div class="controls"></div></div>';

    if (skipForm) {
      for (i = 0; i < numForms; i += 1) {
        $(baseClass).append(controlGroupDiv);
      }
    } else {
      $(baseClass).append(formHtml);
      $('#target').append(csrfHtml);
      for (i = 0; i < numForms; i += 1) {
          $('#target').append(controlGroupDiv);
      }
    }
  }

  function getControlGroup(index) {
    return $('.control-group')[index];
  }

  function getControls(index) {
    return $('.controls')[index];
  }

  function addFormElement(index, label, input) {
    var group = getControlGroup(index);
    var control = getControls(index);
    $(group).addClass('hiddenForm');
    $(control).append(input);
    $(group).prepend(label);
  }

  function addBlankLabel(index) {
    var label = '<label class="control-label emptyLabel">Hidden Label</label>';
    var control = getControls(index);
    $(control).append(label);
  }

  function addUserNameForm(index) {
    var label = '<label for="username" class="control-label">Username</label>';
    var input = '<input id="username" type="text" name="username" placeholder="Username" value="">';
    addFormElement(index, label, input);
  }

  function addEmailForm(index) {
    var label = '<label class="control-label" for="inputEmail">Email</label>';
    var input = '<input id="inputEmail" type="text" name="email" placeholder="Email" value="">';
    addFormElement(index, label, input);
  }

  function addPasswordForm(index) {
    var label = '<label class="control-label" for="inputPassword">Password</label>';
    var input = '<input id="inputPassword" type="password" name="password" placeholder="password" value="">';
    addFormElement(index, label, input);
  }

  // Helper to clear the old forms and generate divs for new form elements
  function drawDivs() {
    clearCanvas();
    addDivs(3, '.login');
  }

  // Generate log in form
  $('.buttonArea').on('click', '.showLogin', function () {
    drawDivs();

    addBlankLabel(0);
    addEmailForm(1);
    addPasswordForm(2);
    $('#target').attr('action', '/users/session');
    $('#target').attr('method', 'post');

    fadeIn();

    addButtons(sLogin, spacer, initSignUp);
  });

  // Generate sign up form
  $('.buttonArea').on('click', '.showSignUp', function () {
    drawDivs();

    addUserNameForm(0);
    addEmailForm(1);
    addPasswordForm(2);
    $('#target').attr('action', '/users');
    $('#target').attr('method', 'post');

    fadeIn();

    addButtons(initLogin, spacer, sSignUp);
  });

  // Submit sign up form
  $('.buttonArea').on('click', '#sSignUp', function () {
    $('#target').trigger('submit');
  });

  // Submit login form
  $('.buttonArea').on('click', '#sLogin', function () {
    $('#target').trigger('submit');
  });
});
\$\endgroup\$
4
\$\begingroup\$

If your looking to find performance improvements i've always know this to be faster

$('<input>', {
   type: "button", 
   value: "", 
   'class': "btn btn-primary emptyLabel"
});

Than this

$('<input type="button" value="" class="btn btn-primary emptyLabel">');

That would be a good start

Also you should cache your elements instead of calling a function 5+ times call it only once

$('.buttonArea').find('.control-group').addClass('form-horizontal');
$('.buttonArea').find('.controls').append(left);
$('.buttonArea').find('.controls').append(mid);
$('.buttonArea').find('.controls').append(right);

This ^ repeats throughout most of the code.

To this

var $buttonArea = $('.buttonArea'),
    $controls = $buttonArea.find('.controls');

$buttonArea.find('.control-group').addClass('form-horizontal');
$controls.append(left);
$controls.append(mid);
$controls.append(right);

also you call attr twice on the same element here

   $('#target').attr('action', '/users/session');
   $('#target').attr('method', 'post');

This basically finds the #target in the DOM then adds the action attribute. then if finds #target again and adds the method attribute you should do it with a Object

$('#target').attr({
   'method', 'post',
   'action': '/users/session'
});

Again here you are doing unnecessary stuff

$('.login').empty();
$('.buttonArea').empty();

When you can simple do this

$('.login, .buttonArea').empty();

I'm not 100% sure on this one but I'm sure you can use 1 eventListener instead of 2 here

  $('.buttonArea').on('click', '#sSignUp', function () {
    $('#target').trigger('submit');
  });

  // Submit login form
  $('.buttonArea').on('click', '#sLogin', function () {
    $('#target').trigger('submit');
  });

You should try this

  $('.buttonArea').on('click', '#sLogin, #sSignUp', function () {
    $('#target').trigger('submit');
  });

I'm sure that's enough to keep you busy for now :)

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.