Implementing Ajax deferred/promise patterns

I have a test case where I want to send a request to the server every time a form field change event occurs. The implementation below works as expected until I submit the form and check for any empty values (this is the only front-end validation carried out, the rest is done via ajax). If a field is empty I trigger a change event so validation can be carried out on the server side.

In the example below I had to set async=>false so each trigger would work as expected. I realize this is not ideal and there is a better way around this using deferred/promise patterns.

I am already using somewhat of the pattern .promise and .then however I think I need to use the .when method but I am unsure how to work it into my partially working example.

I am also a little unsure of the amount of request being sent to the server. Is it viable to send this many, i.e.: each time an event occurs?

Please ignore the block comments, I just use them for code separation.

(function($){ var Registration= {}; /** * * @type type **/ Registration.fields = {}; /** * * @type type **/ Registration.options = { cache : false, type : 'POST', dataType : 'json', url : SITE_URL + '/members/validateFieldOnChange', context : undefined, data : undefined, async : false // TODO }; /** * * @returns {undefined} **/ Registration.init = function(){ //caching this.Form =$('form#form-register');

this.fields = {
email       : this.Form.find('#email'),
};

// register event handlers
this.Form.on('change', 'input', $.proxy(this.handleEvents, this)); this.Form.on('submit',$.proxy(this.handleEvents, this));
};
/**
*
* @param {type} event
* @returns {undefined}
**/
Registration.handleEvents = function(event){
var type, target

event.preventDefault();

type   = event.type;
target = event.target;

if(type == 'change'){
return this.handleChangeEvent(event.target);
}

return this.handleSubmitEvent();
};

/**
*
* @param {type} target
* @returns {undefined}
**/
Registration.handleChangeEvent = function(target){

this.options.context = target;

this.options.data = { field : target.name, value : target.value}

return this.validate();
};

/**
*
* @returns {undefined}
**/
Registration.handleSubmitEvent = function(){

// Ugly testcase if values are empty
// TODO
if($('#username').val() == ''){$('#username').trigger('change');
}

if($('#email').val() == ''){$('#email').trigger('change');
}

if($('#password').val() == ''){$('#password').trigger('change');
}

};
/**
*
* @returns {_L2.Registration@call;doAjax@call;then}
**/
Registration.validate = function(){
return this.doAjax().then(
$.proxy(this.handleResponse, this),$.proxy(this.handleError, this)
);
};

/**
*
* @param {type} response
* @returns {undefined}
**/
Registration.handleResponse = function(response){

var field = $(this.options.context); if(response.msg == 'success') { field.addClass('valid'); } else { field.val(''); field.attr('placeholder', response.responseError); field.addClass('invalid'); } return; }; /** * * @param {type} error * @returns {undefined} **/ Registration.handleError = function(error){ switch(error.code) { case 404: return console.error('Not found'); break; case 401: return console.error('un-authorized access!'); break; case 500: return console.error('system error!'); break; } }; /** * * @returns {unresolved} **/ Registration.doAjax = function(){ return$.ajax(this.options).promise();
}

Registration.init();
})(jQuery);
• It is unclear to me exactly what the problem is upon form submission? Why did you have to set async to false. Is it because you need the three change events you generate to finish processing before the form submits? Is that the problem you're trying to solve? If so, I don't understand why you're manually validating each field with the server and then always sending the whole form to the server. Why not either stop the form submission if something doesn't validate or just validate the whole form when it is received on the server and return a response from the form submission? – jfriend00 Apr 2 '15 at 23:00
• Hi @jfriend00 thanks for taking the time to respond. Yes the triggers get called in succession. This is whats causing the issue and the need for synchronous ajax requests. Design wise not very elegant, I get that. However this is just a testcase. – Philip Apr 2 '15 at 23:39
• I'm asking you why they have to be called in a particular sequence? Why did async not work when you tried it? Also, if you're just going to revalidate everything on the server, why do you have to do client-side validate before submit? You aren't preventing the submission if something is invalid so it's always getting submitted, thus you will just revalidate on the server again anyway. I'm questioning the point of your current design and it is that design that is leading to the problem you have. – jfriend00 Apr 2 '15 at 23:48
• @jfriend00 Yes it is a design flaw, I agree with that. I was just trying to come up with a way of solving validation without having to write or use any client side validation libraries. You are correct everything would need to get validated again on submit, ie another request to the server. The code is very flawed, I see that now. Thanks – Philip Apr 3 '15 at 0:11
• Client-side validation makes sense if you're doing it live as fields are edited or if you're going to abort the submission of the form if something doesn't validate. But, if you're sending the form to the server anyway, there doesn't seem to be a point to doing the client-side validation before you send the form. The server is just going to revalidate anyway so it might as well just return back to the client what didn't validate. – jfriend00 Apr 3 '15 at 0:14