Save as you go forms (User does not have to hit submit)

This is a useful bit of code for long forms which saves the data from radio button submissions and sends them as view based put calls before pressing the submit button on the form.

Add/ Remove objects from the bind_to_inputs section to customize the # of pages, views and questions the code will trigger on.

Change the selection parameter for other types of inputs. Hope this helps someone. :)

bindListToInputs([
{
page_name: "page_xxx",
view_name: "view_yyy",
fields: [16, 18, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 101, 103, 105, 107, 109, 111, 113, 115, 117, 119, 121, 123, 125 ]
},
{
page_name: "page_zzz",
view_name: "view_nnn",
fields: [55, 57, 59, 61 ]
},
{
page_name: "page_ttt",
view_name: "view_jjj",
fields: [63, 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87 ]
},
{
page_name: "page_etc",
view_name: "view_etc",
fields: [89, 91, 93, 95, 97, 99 ]
},

]);

function bindListToInputs(list){
list.forEach(function(inputs){
bindToInputs(inputs);
})
}

function bindToInputs(inputs){
var page_name = inputs.page_name,
view_name = inputs.view_name,
fields = inputs.fields;



$(document).on("knack-view-render." + view_name, function(event, view, data) {
fields.forEach(function(fieldnum){
$("#kn-input-field_" + fieldnum).change(function(){
handleChange(fieldnum).then(function(result){
console.log("Record Updated with this data: ", result.input);
Knack.hideSpinner();
}, function(result){
alert('Update Failed!');
console.log(result.output.error);
})
});
})
});
function handleChange(fieldnum){
var fieldname = 'input[name=' + view_name + '-field_' + fieldnum + ']';
var data = {};

//change this attribute if you want a selector other than radio input.
var selection =$(fieldname + ':checked').val();

data['field_' + fieldnum] = selection;
console.log("selection is" + selection);
return makeRequest(data).then(function(resp){
return {
input: data,
output: resp
}
}, function(resp){
throw {
input: data,
output: resp
}
});
}

function makeRequest(data){
var url = window.location.href.split("/");
var recordid = url[url.length - 2];
var requestUrl = 'https://api.knack.com/v1/pages/' + page_name + '/views/' + view_name + '/records/'+recordid;
return $.ajax({
url: requestUrl,
type: 'put',
headers: {
'Authorization': Knack.getUserToken(),
'X-Knack-Application-Id': Knack.application_id,
'Content-Type': 'application/json'
},
data: JSON.stringify(data)
});
}

}

Absolutely brilliant! Thanks Justin - I refreshed the API token.

This has helped me hugely - Thank you.

Hi Kim, Page and scene are interchangable. Either should work.403 is a permissions error. I'd refresh the token. the only other thing I can think of that I forgot to mention when I posted this script is that this will only work on an edit form, not an add record form. This is for the simple reason that the record needs to have a record id to identify it and it has to exist in the database already so that put request has a valid destination. So, if you're trying to add it to an 'add record' form, it will not work.

Hi there. Does this script need to be updated to show pages as scenes or am I missing something? I can't seem to make it work at the moment. Although on inspection through Chrome when I fill in detail on the form it says this:

PUT https://api.knack.com/v1/pages/scene_180/views/view_412/records/xxxxxxxxxxxxxxxxxx 403 (Forbidden)

Can anyone help? Do I need to update for anything in the new version of knack (what was the beta version)?

Thanks in advance!

Kim

I've updated this script to handle all field types. This is really useful now. You can make sure that if a user abandons a form before completing it you will have saved their answers. Great for 'contact us' embeds, surveys, & popup forms that may be accidentally closed. etc. Just point to the scenes, views, and fields you want to trigger the code on.

//GET VALUES of inputs - all types
bindListToInputs([
{
page_name: "page_113",
view_name: "view_206",
fields: [16, 18, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 101, 103, 105, 107, 109, 111, 113, 115, 117, 119, 121, 123, 125 ]
},
{
page_name: "page_114",
view_name: "view_207",
fields: [55, 57, 59, 61 ]
},
{
page_name: "page_115",
view_name: "view_208",
fields: [63, 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87 ]
},
{
page_name: "page_116",
view_name: "view_209",
fields: [89, 91, 93, 95, 97, 99 ]
},
{
page_name: "page_117",
view_name: "view_210",
fields: [101, 103, 105, 107, 109, 111, 703, 704, 705, 706 ]
}
]);

function retrieveValueFromInput(view_name, fieldnum){
var fieldname = 'input[name=' + view_name + '-field_' + fieldnum + ']';
var elems = $(fieldname);
if(elems.length > 0){
return $(fieldname + ':checked').val();
}

elems = $('#' + view_name + '-field_' + fieldnum);
if(elems.length > 0){
var selector = '#' + view_name + '-field_' + fieldnum;
if(elems.prop("tagName").toLowerCase() !== "select"){
throw new Error(view_name + " " + fieldnum + " should be a select");
}
if(elems.prop("multiple")){
var value = [];
$(selector + ' > option:selected').map(function(index, elem){
value.push($(elem).val());
}); // for multiple choice // works
return value;
}
return $(selector + ' > option:selected').val();
}

elems = $('#field_' + fieldnum);
if(elems.length > 0){
return $('#field_' + fieldnum).val();
}

throw new Error("cannot handle " + view_name + " " + fieldnum);
}

function bindListToInputs(list){
list.forEach(function(inputs){
bindToInputs(inputs);
});
}

function bindToInputs(inputs){
var page_name = inputs.page_name,
view_name = inputs.view_name,
fields = inputs.fields;

$(document).on("knack-view-render." + view_name, function(event, view, data) {
fields.forEach(function(fieldnum){
$("#kn-input-field_" + fieldnum).change(function(){
handleChange(fieldnum).then(function(result){
console.log("Record Updated with this data: ", result.input);
Knack.hideSpinner();
}, function(result){
alert('Update Failed!');
console.log(result.output.error);
});
});

});
});
function handleChange(fieldnum){
var data = {};
data['field_' + fieldnum] = retrieveValueFromInput(view_name, fieldnum);
console.log("selection is" + data);
return makeRequest(data).then(function(resp){
return {
input: data,
output: resp
};
}, function(resp){
throw {
input: data,
output: resp
};
});
}

function makeRequest(data){
var url = window.location.href.split("/");
var recordid = url[url.length - 2];
var requestUrl = 'https://api.knack.com/v1/pages/' + page_name + '/views/' + view_name + '/records/'+recordid;
return $.ajax({
url: requestUrl,
type: 'put',
headers: {
'Authorization': Knack.getUserToken(),
'X-Knack-Application-Id': Knack.application_id,
'Content-Type': 'application/json'
},
data: JSON.stringify(data)
});
}

}