views:

45

answers:

1

Dear Stackoverflow,

I am refactoring my use of $.ajax to submit forms using the jQuery Forms Plugin. The API states that it is possible to pass any of the options passed to $.ajax to $.ajaxSubmit. I wish to modify the Options Object in the beforeSubmit, adding a data property. Alerting the value of options.beforeSubmit in processSubmit suggests that this is the Options Object initialised by the handler and that the data is set, but as the Options Object has already been initialised with no data property, it isn't included in the post sent to the server. Is it possible to modify the Options Object in the beforeSubmit, or in some other way?

When the document is ready I bind a handler to submit():

$("#myform").submit(function() {
    var options = { dataType: 'json',
            beforeSubmit: processSubmit,
            success: endSubmit };
    $(this).ajaxSubmit(options);
    return false;
});

The processSubmit(arr, $form, options) function packages up data to be sent to the server as JSON:

function processSubmit(arr, $form, options) {
    var followers =[];
    $($("#follower-multi-select").children().filter("li")).each(function() {
      if ($(this).hasClass("selected")) {
        var fwr =  $(this).attr("id");
        followers.push(fwr);
      }
    });

    var postData = { followers : followers };
    alert('beforeSubmit is: ' + options.beforeSubmit);

    options.data = 'json='+$.toJSON(postData);
    alert('data set: ' + options.data);
}

The form HTML:

<form id="myform" action="/myaction" method="post">
    <fieldset>
        <legend>Choose your competitors</legend>
        <ul id="follower-multi-select" class="follower-multi-select">
            {% for f in follower_thumbs %}
            <li id="{{ f.hashedkey }}"><img src='{{ f.thumb }}' alt="{{ f.name }}" /><span class="name-multi-select">{{ f.name }}</span></li>
            {% endfor %}
        </ul>
    </fieldset>
    <input id="send" type="submit" class="large" value="send" />
</form>
+1  A: 

Instead of beforeSubmit you should use the beforeSerialize option, so your data gets included when it's serialized. You're not setting .data on the options passed to $.ajax(), you're setting .data on the $.ajaxSubmit() options, which is a property on the plugin of extra data to include when it serializes. When beforeSubmit happens, the serialization has already been completed, you need to step in before that, like this:

$("#myform").submit(function() {
    var options = { dataType: 'json',
            beforeSerialize: processSubmit,
            success: endSubmit };
    $(this).ajaxSubmit(options);
    return false;
});

function processSubmit($form, options) {
    var followers = $("#follower-multi-select > li.selected").map(function() {
        return this.id;
    }).get();

    var postData = { followers : followers };
    alert('beforeSubmit is: ' + options.beforeSubmit);

    options.data = 'json='+$.toJSON(postData);
    alert('data set: ' + options.data);
}

I also used .map() and the > child-selector here to make the getting of your array much simpler, but your original method works...just note the important difference that the parameters are different on the callback from beforeSubmit, there's no arr parameter for the beforeSerialize callback.

Nick Craver
@NickCraver, thanks very much! Your use of map() is beautiful. The code now reads as you suggest. While the alert shows options.data as 'json={"followers": ["0c703d82ebfe2ebc34c7a0149708869e802f3428"]}', the console shows that the JSON passed to the server reads 'UnicodeMultiDict: UnicodeMultiDict([(u'0', u'j'), (u'1', u's'), (u'2', u'o'), (u'3', u'n'), (u'4', u'='), (u'5', u'{'), (u'6', u'"'), (u'7', u'f'), (u'8', u'o'), (u'9', u'l'), (u'10', u'l'), (u'11', u'o'), (u'12', u'w'), (u'13', u'e'), (u'14', u'r')...(u'63', u'}')])'. Am I missing something in how I am passing the JSON?
meg