How to append a new form element to a form via AJAX not triggered inside the form?
You can add some custom value to the form_state and use it to determine whether to build a new form element or not. Please try the following example:

/**
 * An example form.
 */
function example_form($form, &amp;$form_state) {

  $form['#tree'] = TRUE;

  // Use this value to determine whether to build a new form element or not.  
  if (empty($form_state['add_new_item'])) {
    $form_state['add_new_item'] = FALSE;
  }

  $form['example_fieldset'] = array(
    '#type' =&gt; 'fieldset',
    '#title' =&gt; t('Example form'),
    // Set up the wrapper so that AJAX will be able to replace the fieldset.
    '#prefix' =&gt; '&lt;div id="example-fieldset-wrapper"&gt;',
    '#suffix' =&gt; '&lt;/div&gt;',
  );

  $form['example_fieldset']['name'] = array(
    '#type' =&gt; 'textfield',
    '#title' =&gt; t('Name'),
    '#required' =&gt; FALSE,
  );

  $form['actions'] = array(
    '#type' =&gt; 'actions'
  );

  // add field button.
  $form['actions']['add_field'] = array(
    '#type' =&gt; 'submit',
    '#value' =&gt; t('Add new form item'),
    '#submit' =&gt; array('field_add_one'),
    '#ajax' =&gt; array(
      'callback' =&gt; 'example_form_callback',
      'wrapper' =&gt; 'example-fieldset-wrapper',
    ),
    // hide this form element
    '#attributes' =&gt; array(
      'class' =&gt; array('element-invisible')
    )
  );

  // submit button.
  $form['actions']['submit'] = array(
    '#type' =&gt; 'submit',
    '#value' =&gt; t('Submit')
  );

  $form['#attached']['js'] = array(
    array(
      'type'  =&gt; 'file',
      'data' =&gt; drupal_get_path('module', 'YOUR_MODULE') . '/js/add_field.js',
    ),
  );

  // append a new form element (after ajax)
  if ($form_state['add_new_item'] == TRUE) {
    $form['example_fieldset']['new_item'] = array(
      '#type' =&gt; 'textfield',
      '#title' =&gt; 'My new item',
    );
  }

  return $form;
}


/**
 * Submit handler for the "add-field" button.
 *
 * - set the $form_state['add_new_item'] as TRUE.
 * - rebuild the form.
 */
function field_add_one($form, &amp;$form_state) {
  $form_state['add_new_item'] = TRUE;
  $form_state['rebuild'] = TRUE;
}

/**
 * Ajax callback.
 *
 * Returns the fieldset with all values in it.
 */
function example_form_callback($form, &amp;$form_state) {

  return $form['example_fieldset'];
}

/**
 * Final submit handler.
 *
 * Reports what values were finally set.
 */
function example_form_submit($form, &amp;$form_state) {
  $output = $form_state['values']['example_fieldset'];
  drupal_set_message('&lt;pre&gt;' . print_r($output, true) . '&lt;/pre&gt;');
}


add_field.js

(function($) {    
  Drupal.behaviors.your_module_name = {
    attach:function() {

      var form = $('#example-form');

      // the 'add-field' form element
      // this form element is invisible. It will be triggered by the custom link (not form element).
      var addField = $('#edit-actions-add-field'); 

      // add an example link
      $('#my-custom-link').remove(); // prevent from adding the custom link more than once
      form.after("&lt;span id='my-custom-link'&gt;&lt;a href='#'&gt;ADD FIELD&lt;/a&gt;&lt;/span&gt;"); // add custom link

      // Attach mousedown() to the custom link in order to activate ajax.
      // Notice: You can attach click() to a normal submit form element (without ajax)
      // but it has to be mousedown() if the form element has an ajax attribute.
      $('#my-custom-link').click(function() {
        addField.mousedown(); 
      });
    }
  };
}(jQuery));