diff --git a/src/jquery.jsForm.js b/src/jquery.jsForm.js index a7a7755..eb14ab8 100644 --- a/src/jquery.jsForm.js +++ b/src/jquery.jsForm.js @@ -36,6 +36,12 @@ * the prefix used to annotate theinput fields */ prefix: "data", + /** + * set to null to discourage the tracking of "changed" fields. + * Disabling this will increase performance, but disabled the "changed" functionality. + * This will add the given css class to changed fields. + */ + trackChanges: "changed", /** * set to false to only validate visible fields. * This is discouraged especially when you have tabs or similar elements in your form. @@ -344,6 +350,12 @@ $(line).data().pojo = {}; $(this).append(line); + // init controls + that._enableTracking($("input,textarea,select", line)); + // ne wline always has changes + if(that.options.trackChanges) + $("input,textarea,select", line).addClass(that.options.trackChanges); + that._addCollectionControls(line); // trigger a callback @@ -504,93 +516,6 @@ }); - - // manage - obsolete - $(".manage", form).each(function(){ - var fieldName = $(this).attr("data-field"); - if(!fieldName) { - return; - } - - // remember the collections - $(this).data("collections", collectionMap[fieldName]); - - // start the multi-select - $(this).click(function(){ - var dataService = $(this).attr("data-service"); - var collectionList = $(this).data("collections"); - - var btn = $(this); - var display = $(this).attr("data-display"); - if(display) { - display = display.split(","); - } - - DataUtils.run(dataService, function(data){ - var select = $(''); - select.data("collections", collectionList); - btn.data("select", select); - $.each(data, function(){ - var cur = this; - var optionDisplay = ""; - if(!display) { - optionDisplay = cur; - } else { - for(var j = 0; j < display.length; j++) { - optionDisplay += cur[display[j]] + " "; - } - } - var option = $(''); - // check if we need to "select" that option - $(collectionList).each(function() { - $(this).children().each(function(count, ele){ - if(cur.id === $(ele).data("pojo").id) { - option.prop("selected", true); - } - }); - }); - select.append(option); - option.data("pojo", cur); - }); - - btn.after(select); - btn.hide(); - - select.multiselect({ - autoOpen: true, - open: function(){ - //reposition - $(this).multiselect("widget").css("top", $(select).next().offset().top); - $(this).multiselect("widget").css("left", $(select).next().offset().left); - // hide button - $(select).next().hide(); - }, - close: function(){ - btn.show(); - select.remove(); - $(this).multiselect("destroy"); - } - }).multiselectfilter().bind("multiselectclick multiselectcheckall multiselectuncheckall", - function( event, ui ){ - var checkedValues = $.map($(this).multiselect("getChecked"), function( input ){ - // we only get the same "value" - so check the option list for the correct pojo - return $("option[value='"+input.value+"']", select).data("pojo"); - }); - - // update collection - $.each($(select).data("collections"), function(){ - that._fillList($(this), checkedValues, fieldName); - }); - // reposition - btn.hide(); - $(select).next().show(); - $(this).multiselect("widget").css("top", $(select).next().offset().top); - $(this).multiselect("widget").css("left", $(select).next().offset().left); - $(select).next().hide(); - }); - }); - }); - }); }; /** @@ -905,6 +830,23 @@ return pojo; }; + /** + * helper function to enable tracking on fields + * @param ele the element to track + */ + JsForm.prototype._enableTracking = function(ele) { + var that = this; + if(that.options.trackChanges && !$(ele).data().track) { + $(ele).data().track = true; + $(ele).change(function(){ + if($(this).val() !== $(this).data().orig) { + $(this).addClass(that.options.trackChanges); + }else { + $(this).removeClass(that.options.trackChanges); + } + }); + } + }; /** * fill a dom subtree with data. @@ -982,6 +924,7 @@ if(!name) { return; } + that._enableTracking(this); // ignore file inputs - they cannot be "prefilled" if($(this).attr("type") == "file") { @@ -1058,6 +1001,7 @@ $(this).val(cdata); } + $(this).data().orig = $(this).val(); $(this).change(); $(this).trigger("fill"); } @@ -1074,6 +1018,9 @@ if (prefix) { cname = cname.substring(prefix.length + 1); } + + that._enableTracking(this); + // remove "old" selected options $(this).children("option:selected").prop("selected", false); var pk = $(this).attr("data-key"); @@ -1093,6 +1040,7 @@ } $(this).children("option[value='"+value+"']").prop("selected", true); + $(this).data().orig = value; $(this).val(value).change(); $(this).trigger("fill"); } @@ -1886,8 +1834,20 @@ * * @returns {Boolean} true if the form has changed since the last fill */ - JsForm.prototype.changed = function(idField) { - return this.equals(this.options.data, idField) === false; + JsForm.prototype.changed = function() { + if(!this.options.trackChanges) + return false; + + var changed = false; + var that = this; + $.each(this._getForm(), function(){ + if($("." + that.options.trackChanges, this).size() > 0) { + changed = true; + return false; + } + }); + + return changed; }; JsForm.prototype._equalsCollection = function(form, prefix, pojo) { diff --git a/test/jquery.jsForm.test.js b/test/jquery.jsForm.test.js index 76569ac..618ae45 100644 --- a/test/jquery.jsForm.test.js +++ b/test/jquery.jsForm.test.js @@ -343,17 +343,18 @@ test("direct access simple arrays", function(){ equal($("#list1", basicForm).children().length, 5, "5 items in list1"); equal($("#list2", basicForm).children().length, 5, "5 items in list2"); - equal(basicForm.jsForm("equals", original), true, "form has not changed"); + equal(basicForm.jsForm("changed"), false, "form has not changed"); + equal(basicForm.jsForm("equals", original), true, "form data has not changed"); // add an item in each list $("#add1", basicForm).click(); $("#add2", basicForm).click(); equal($("#list1", basicForm).children().length, 6, "6 items in list1"); equal($("#list2", basicForm).children().length, 6, "6 items in list2"); - $("#list1", basicForm).children().first().find("input").val("1111"); - $("#list1", basicForm).children().last().find("input").val("1112"); - $("#list2", basicForm).children().first().find("input").val("2221"); - $("#list2", basicForm).children().last().find("input").val("2222"); + $("#list1", basicForm).children().first().find("input").val("1111").change(); + $("#list1", basicForm).children().last().find("input").val("1112").change(); + $("#list2", basicForm).children().first().find("input").val("2221").change(); + $("#list2", basicForm).children().last().find("input").val("2222").change(); var updated = basicForm.jsForm("get"); equal(updated.steps.length, 6, "6 steps"); equal(updated.steps[0], 1111, "first element: 1111"); @@ -361,7 +362,15 @@ test("direct access simple arrays", function(){ equal(updated.test.steps.length, 6, "6 steps in test"); equal(updated.test.steps[0], 2221, "first element: 2221"); equal(updated.test.steps[5], 2222, "last element: 2222"); - - equal(basicForm.jsForm("equals", original), false, "form has changed"); + + equal($("#list1", basicForm).children().first().find("input").hasClass("changed"), true, "first input changed"); + equal($("#list1", basicForm).children().eq(2).find("input").hasClass("changed"), false, "second input not changed"); + equal($("#list1", basicForm).children().last().find("input").hasClass("changed"), true, "last input changed"); + equal($("#list2", basicForm).children().first().find("input").hasClass("changed"), true, "first input changed"); + equal($("#list2", basicForm).children().last().find("input").hasClass("changed"), true, "last input changed"); + + equal(basicForm.jsForm("changed"), true, "form has changed"); + equal(basicForm.jsForm("equals", original), false, "form data has changed"); + // clean up basicForm.remove(); }); \ No newline at end of file