Skip to content

Commit

Permalink
New IModelForm interface for fields containing model/object like values
Browse files Browse the repository at this point in the history
  • Loading branch information
mever committed Jul 3, 2016
1 parent 55509a1 commit 1d68603
Show file tree
Hide file tree
Showing 3 changed files with 189 additions and 6 deletions.
Expand Up @@ -18,7 +18,7 @@
************************************************************************ */

/**
* @ignore(qx.test.data.controller.fixture.ArrayField)
* @ignore(qx.test.data.controller.fixture.ArrayField, qx.test.data.controller.fixture.ModelField)
*/

qx.Class.define("qx.test.data.controller.FormWithArrayAndModel",
Expand All @@ -30,6 +30,9 @@ qx.Class.define("qx.test.data.controller.FormWithArrayAndModel",
/** @type {qx.test.data.controller.fixture.ArrayField} */
__arrayField : null,

/** @type {qx.test.data.controller.fixture.ModelField} */
__modelField : null,

/** @type {qx.ui.form.Form} */
__form : null,

Expand All @@ -39,7 +42,7 @@ qx.Class.define("qx.test.data.controller.FormWithArrayAndModel",

setUp : function() {

// imagine me being a table like widget containing two columns
// imagine me being a table like widget containing two columns (e.g. an miniature todo-list)
qx.Class.define("qx.test.data.controller.fixture.ArrayField", {
extend : qx.ui.core.Widget,
implement : [ qx.ui.form.IArrayForm, qx.ui.form.IForm ],
Expand Down Expand Up @@ -75,22 +78,86 @@ qx.Class.define("qx.test.data.controller.FormWithArrayAndModel",
}
});

// imagine me being a multi-field widget (e.g. address form embedded in user form)
qx.Class.define("qx.test.data.controller.fixture.ModelField", {
extend : qx.data.controller.Form,
implement : [ qx.ui.form.IArrayForm, qx.ui.form.IForm ],
include : [ qx.ui.form.MForm ],

events : {
changeValue : "qx.event.type.Data",

// implement IForm interface
changeEnabled : "qx.event.type.Data"
},

members : {
// implement IForm interface
setEnabled : function() {},
getEnabled : function() {return true;},

/**
* @param value {qx.core.Object|null}
* @returns void
*/
setValue : function(value) {
this.setModel(value);
},

/**
* @returns {qx.core.Object|null}
*/
getValue : function() {return this.getModel();},

/**
* @returns void
*/
resetValue : function() { this.resetModel(); },

// overwritten
_applyModel : function(value, old) {
this.base(arguments, value, old);
this.fireDataEvent("changeValue", value, old);
}
}
});

this.__arrayField = new qx.test.data.controller.fixture.ArrayField();
this.__modelField = new qx.test.data.controller.fixture.ModelField();

this.__form = new qx.ui.form.Form();
this.__form.add(this.__arrayField, "One", null, "f1");
this.__form.add(this.__modelField, "Two", null, "f2");

this.__model = qx.data.marshal.Json.createModel({f1: null, f2: null});
this.__model = qx.data.marshal.Json.createModel({f1: null, f2: null, f3: null});
},


tearDown : function() {
this._disposeObjects("__arrayField", "__form", "__model");
this._disposeObjects("__arrayField", "__modelField", "__form", "__model");
qx.Class.undefine("qx.test.data.controller.fixture.ArrayField");
qx.Class.undefine("qx.test.data.controller.fixture.ModelField");
},


/**
* Reusable address form.
*
* @returns {qx.ui.form.Form} Address form.
*/
__makeAddressForm : function() {
var houseNr = new qx.ui.form.TextField();
var streetName = new qx.ui.form.TextField();
var addressForm = new qx.ui.form.Form();
addressForm.add(houseNr, "houseNr");
addressForm.add(streetName, "streetName");
qx.util.DisposeUtil.disposeTriggeredBy(houseNr, addressForm);
qx.util.DisposeUtil.disposeTriggeredBy(streetName, addressForm);
return addressForm;
},


"test self update" : function() {
"test self update: array" : function() {
var arr = qx.data.marshal.Json.createModel([{c1: "1a1", c2: "1a2"}, {c1: "1b1", c2: "1b2"}]);
arr.setAutoDisposeItems(true);
this.__arrayField.setValue(arr);
Expand All @@ -110,6 +177,28 @@ qx.Class.define("qx.test.data.controller.FormWithArrayAndModel",
},


"test self update: model" : function() {
var addressForm = this.__makeAddressForm();
this.__modelField.setTarget(addressForm);

var ctrl = new qx.data.controller.Form(this.__model, this.__form, true);
this.assertNull(this.__arrayField.getValue());
this.assertNull(this.__modelField.getValue());

// let's make an address for this user (this.__model being a user now ;) )
this.__modelField.createModel(false);
addressForm.getItem("houseNr").setValue("42");
addressForm.getItem("streetName").setValue("Nowhere Ln");
ctrl.updateModel();

// imagine f2 now being a user address
this.assertIdentical("42", this.__model.getF2().getHouseNr());
this.assertIdentical("Nowhere Ln", this.__model.getF2().getStreetName());
ctrl.dispose();
addressForm.dispose();
},


"test updating view" : function() {
var arr = qx.data.marshal.Json.createModel([{c1: "2a1", c2: "2a2"}, {c1: "2b1", c2: "2b2"}]);
arr.setAutoDisposeItems(true);
Expand All @@ -129,7 +218,7 @@ qx.Class.define("qx.test.data.controller.FormWithArrayAndModel",
},


"test updating model" : function() {
"test updating model: array field" : function() {
var arr = qx.data.marshal.Json.createModel([{c1: "2a1", c2: "2a2"}, {c1: "2b1", c2: "2b2"}]);
arr.setAutoDisposeItems(true);

Expand All @@ -141,6 +230,22 @@ qx.Class.define("qx.test.data.controller.FormWithArrayAndModel",
this.assertIdentical(arr, this.__arrayField.getValue());
ctrl.dispose();
arr.dispose();
},


"test updating model: model field" : function() {
var addressForm = this.__makeAddressForm();
this.__modelField.setTarget(addressForm);

var ctrl = new qx.data.controller.Form(this.__model, this.__form);
this.assertNull(this.__arrayField.getValue());
this.assertNull(this.__modelField.getValue());

this.__modelField.createModel(false);
this.assertIdentical(this.__modelField.getModel(), this.__model.getF2());

ctrl.dispose();
addressForm.dispose();
}
}
});
77 changes: 77 additions & 0 deletions framework/source/class/qx/ui/form/IModelForm.js
@@ -0,0 +1,77 @@
/* ************************************************************************
qooxdoo - the new era of web development
http://qooxdoo.org
Copyright:
2016 Martijn Evers, The Netherlands
License:
LGPL: http://www.gnu.org/licenses/lgpl.html
EPL: http://www.eclipse.org/org/documents/epl-v10.php
See the LICENSE file in the project's top-level directory for details.
Authors:
* Martijn Evers (mever)
************************************************************************ */

/**
* Form interface for all form widgets which have an
* model object (i.e. {qx.core.Object}) as their primary data type.
*/
qx.Interface.define("qx.ui.form.IModelForm",
{
/*
*****************************************************************************
EVENTS
*****************************************************************************
*/

events :
{
/** Fired when the value was modified */
"changeValue" : "qx.event.type.Data"
},



/*
*****************************************************************************
MEMBERS
*****************************************************************************
*/

members :
{
/*
---------------------------------------------------------------------------
VALUE PROPERTY
---------------------------------------------------------------------------
*/

/**
* Sets the element's value.
*
* @param value {qx.core.Object|null} The new value of the element.
*/
setValue : function(value) {
return arguments.length == 1;
},


/**
* Resets the element's value to its initial value.
*/
resetValue : function() {},


/**
* The element's user set value.
*
* @return {qx.core.Object|null} The value.
*/
getValue : function() {}
}
});
1 change: 1 addition & 0 deletions framework/source/class/qx/ui/form/Resetter.js
Expand Up @@ -245,6 +245,7 @@ qx.Class.define("qx.ui.form.Resetter",
qx.Class.hasInterface(clazz, qx.ui.form.IDateForm) ||
qx.Class.hasInterface(clazz, qx.ui.form.INumberForm) ||
qx.Class.hasInterface(clazz, qx.ui.form.IArrayForm) ||
qx.Class.hasInterface(clazz, qx.ui.form.IModelForm) ||
qx.Class.hasInterface(clazz, qx.ui.form.IStringForm)
);
}
Expand Down

0 comments on commit 1d68603

Please sign in to comment.