Hi everybody, I'm still pretty new to Qooxdoo and have been having a good time 
coming up to speed on it. It seems like a really nice package, so far. You guys 
have really put a lot of EXCELLENT work into this. I'm super-impressed at the 
overall attention to detail and organization expressed in the code and 
documentation. It'd be nice if the documentation was fleshed out a little 
more-- but hey, if you spend all your time documenting you don't get to write 
as much cool code, eh? :-)


So anyway, can somebody help me a little please? I've been hammering on this 
most of the day and I'm just not understanding where it's going wrong?

My ultimate goal is to call a backend (via rpc) to retrieve JSON data (from an 
sql query), which will be returned in an "id / name" format. And then to use 
that data to load up a list object (select box, combo box, whatever). I'm not 
worried about the actual backend call for the moment-- I already know how to do 
that just fine, so for now I'm just faking that part with a static JSON data 
structure like so:

                var deviceModel = qx.data.marshal.Json.createModel([
                        { id: 1, name: "Router" },
                        { id: 2, name: "Switch" },
                        { id: 3, name: "Firewall" },
                        { id: 4, name: "WiFi AP" }
                        ]);


Before getting into the actual problem-- I'd also like to comment on the 
general subject itself. I've read through a number of the qooxdoo dev list 
postings and have seen numerous back-and-forth between people trying to figure 
stuff out and who I think are the developers and qooxdoo gurus (does that 
rhyme, btw?) and frankly it seems to me like the whole thing is more 
complicated than it ought to be. 

I have seen several statements seemingly questioning the fundamental necessity 
of such a construct. For example:


"First of all, you should ask yourself if its really necessary to work with 
id's here. You are in the JS
environment and you can use references to objects which is way more convenient 
than having the
indirection of an id. But thats just a side note..." -- Martin Wittemann
And similar.

My immediate rebuttal to that is-- Sure, objects are nice, but many times a 
List object is used to select an item which will then be handed off to a 
back-end for some sort of processing, in which case having a reference to an 
object could be considered more of a hindrance. It is not at all unusual to 
assume that transmitting an ID value would be the most effective method of 
communication to a back-end for the purpose of data lookup or something. And an 
ID value is probably more what a back-end data store (SQL database or 
something) is more likely to want anyway -- so NOT doing it that way actually 
adds to the overhead necessary to get it all coded up, on both the back-end and 
front-ends.

If I were thinking up the thing I think I would consider three typical cases:

  1. A simple list (array) of items-- strings, objects-- whatever. When one is 
selected, it is returned, whatever it is. As a variation, perhaps a flag could 
also be set to return the item's index value instead, so it'd be a configurable 
option which way to return the info.

  2. A simple array of arrays, each containing two items. The first is the 
return value (the 'id') the second is the display value (the 'name').

  3. A simple array of hashes with formally named elements (e.g. "id", "name", 
"foo", "bar", etc). Then the user could indicate which element should be the 
displayed element and which element should be the returned element. The user 
could opt to use the same element for both. And optionally, perhaps it could 
also accept a hash of hashes-- operation similar, list order not guaranteed-- 
i.e., however it comes out.

BONUS: And then if one of those pre-arranged scenarios wasn't suitable, THEN it 
would be fantastic to ALSO have the option of custom data binding / 
conversion-- whatever.

In the case of having many, many list items to worry about, it could work like 
your virtual list or virtual table model.


In that setup, I think you would cover probably (my guess) 70-80% of the 
required cases in the first two or three modes, and would easily cover the rest 
through your custom data binding mechanism.

That's my two cents on the matter :-)

Now, for what I actually need help with...

I found Martain Wittemann's write-up about using data binding along with his 
code sample on the demo.qooxdoo.org playground. I worked it around slightly 
just to make it work with my own example-- it was pretty much exactly what I 
wanted from the git-go. This is what I have, from Martin's code:

/* ************************************************************************

   qooxdoo - the new era of web development

   http://qooxdoo.org

   Copyright:
     2004-2008 1&1 Internet AG, Germany, http://www.1und1.de

   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:
     * Martin Wittemann (martinwittemann)

************************************************************************ */

/**
 * @tag databinding
 * @tag list contorller
 * @tag form controller
 */
qx.Class.define("demobrowser.demo.data.FormAndListController",
{
  extend : qx.application.Standalone,

  members :
  {
    main: function()
    {
      this.base(arguments);

      // create some dummy data
      var data = {
        firstname: "John",
        lastname: "Whitten",
        device: null
      };
      var model = qx.data.marshal.Json.createModel(data);

      var deviceModel = qx.data.marshal.Json.createModel([
          {id: "rtr", name: "Router"}, 
          {id: "sw", name: "Switch"}, 
          {id: "fw", name: "Firewall"}, 
          {id: "wap", name: "Wifi AP"}
        ]);

      // create the form
      var form = new qx.ui.form.Form();

      // firstname
      var firstname = new qx.ui.form.TextField();
      form.add(firstname, "Firstname");

      // lastname
      var lastname = new qx.ui.form.TextField();
      form.add(lastname, "Lastname");

      // device type
      var deviceBox = new qx.ui.form.SelectBox();
      new qx.data.controller.List(deviceModel, deviceBox, "name");
      form.add(deviceBox, "Device");

      // create the form and add it to the root
      this.getRoot().add(new qx.ui.form.renderer.Single(form), {left: 30, top: 
20});

      // create a form controller!
      var fc = new qx.data.controller.Form(model, form);
      fc.addBindingOptions("Device", {converter: function(data) {
        // model2target
        for (var i = 0; i < deviceModel.getLength(); i++) {
          if (deviceModel.getItem(i).getId() == data) {
            return deviceModel.getItem(i)
          }
        }
        return deviceModel.getItem(0);
      }}, {converter: function(data) {
        // target2model
        return data.getId();
      }});

      // A button to log the models content
      var logButton = new qx.ui.form.Button("Show model data in the log");
      this.getRoot().add(logButton, {left: 240, top: 20});
      logButton.addListener("execute", function() {
        this.debug(qx.dev.Debug.debugProperties(model));
      }, this);
    }
  }
});​


However, when I lifted the code from his example and plugged it into my own, I 
keep getting console errors (which you can see in context on down below) The 
first of which is appears to be the show-stopper:

               +  Uncaught TypeError: Cannot read property 'constructor' of 
undefined Form.js:360
               +  qx.Class.define.members.__isModelSelectable Form.js:360
               +  qx.Class.define.members.addBindingOptions Form.js:136
               +  qx.Class.define.construct Simple.js:53


Here is my code along with a comment block in the middle which illustrates 
where the problem is occurring. Note that in my example, I am not creating a 
form, but rather extending a form as a class. As an aside, I have several 
examples of the "form-as-class" that run without errors at all. So I know for 
certain it is directly related somehow to the data binding line. Note that in 
order to run it, it must be instantiated as a class by something else and 
rendered, etc.

qx.Class.define("reilly.ui.forms.Simple",
{
        extend : qx.ui.form.Form,

        properties :
        {
//              controller : { deferredInit : true },
//              model : { deferredInit : true },
                service : { init: "echo" }
        },

        events :
        {
                "onSave" : "qx.event.type.Data"
        },

        construct : function()
        {
                this.base(arguments);

                // set up model for form
                var formModel = qx.data.marshal.Json.createModel({
                        device: null
                        });

                // set up device type combo box
                var deviceName = "Device";
                var deviceModel = qx.data.marshal.Json.createModel([
                        { id: 1, name: "Router" },
                        { id: 2, name: "Switch" },
                        { id: 3, name: "Firewall" },
                        { id: 4, name: "WiFi AP" }
                        ]);

                var device = new qx.ui.form.SelectBox().set({required: true});
                new qx.data.controller.List(deviceModel, device, "name"); // 
bind list model to selectbox-list

                this.add(device, deviceName, null, "device");

                // save button
                var btnSave = new qx.ui.form.Button("Save");
                btnSave.addListener("execute", function(e) {
                        this.fireDataEvent("onSave", this);
                        }, this);
                this.addButton(btnSave);

                // create form controller
                var formCtlr = new qx.data.controller.Form(formModel, this);

                // 
=====================================================================================
                // ####   THE PROBLEM SEEMS TO BE HERE SOMEHOW - The errors 
generated are below.
                // ####   "Simple.js:53" is the first live line following this 
text
                // ####
                // #### +  Uncaught TypeError: Cannot read property 
'constructor' of undefined Form.js:360
                // #### +  qx.Class.define.members.__isModelSelectable 
Form.js:360
                // #### +  qx.Class.define.members.addBindingOptions Form.js:136
                // #### +  qx.Class.define.construct Simple.js:53
                // 
=====================================================================================

                // alter binding for 'device' control
                formCtlr.addBindingOptions(deviceName, {
                        converter: function(data) {
                                for (var i = 0; i < deviceModel.getLength(); 
i++) {
                                        if (deviceModel.getItem(i).getId() == 
data) {
                                                return deviceModel.getItem(i);
                                                }
                                        }
                                }
                        },
                        {
                        converter: function(data) {
                                return data.getId();
                                }
                        });
                // 
=====================================================================================

                this.setService("getSwitch");
        }
});


Here is a code fragment which illustrates using the form class from above:

                this.swForm = new reilly.ui.forms.Simple();
                this.swForm.addListener("onSave", this.__handleSubmit, this);
                this.swFormWindow = new reilly.ui.windows.PortalWindow("Switch 
Form");
                this.swFormWindow.add(new 
qx.ui.form.renderer.Single(this.swForm));
                this.swFormWindow.setVisibility("visible");
                this.getRoot().add(this.swFormWindow, {left: 25, top: 25});


Can anybody shed any light as to what I'm doing wrong? I'd sure like to get 
this figured out and move on to the next item.

Thanks for any help and comments!!

And thanks again for such an INCREDIBLY COOL toolkit!! 

I don't have a clue how to pronounce it-- but Qooxdoo ROCKS !!!  :-)


John Whitten
------------------------------------------------------------------------------
Live Security Virtual Conference
Exclusive live event will cover all the ways today's security and 
threat landscape has changed and how IT managers can respond. Discussions 
will include endpoint security, mobile security and the latest in malware 
threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/
_______________________________________________
qooxdoo-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/qooxdoo-devel

Reply via email to