Need help with Models please !!!!

classic Classic list List threaded Threaded
29 messages Options
12
Reply | Threaded
Open this post in threaded view
|

Re: The SOLUTION!!! (Was Re: Need help with Models please !!!!)

jwhitten

Well, I definitely agree that it seems quite a bit over the top in terms of effort just to get data to the back-end. The js / qooxdoo side is nearly verbatim from some example I found on the net. All I did was modify it a little with try/catch blocks and added some debug messages to see what was happening.

The back-end is about as plain-jane RPC as you can get. I've got two servers I've written, one in Perl, the other in PHP which toss RPC pretty generically. I think I wrote them some months back when I was testing various JS / Ajax frameworks. They've just always worked with very little tinkering. I wrote another one out of CPAN parts more recently that's even more generic-- JSON::RPC::Dispatcher.

(shrug) :-)

All my own JS code in the past has been trivial. This really seemed.. not sure how to even describe it-- somewhere between frustrating and absurd! :-)  Had even been considering ditching Qooxdoo for something else. The documentation for the thing seems to alternate between pretty good and just-barely. I spend a lot of my time just trying to figure out what they're doing in places or compensating for something that doesn't seem to be there.

I realize that it's an evolving effort. And I'm not meaning to knock anybody's efforts in any way-- you know, I'm pretty happy and thrilled at having a cool, open source toolkit to work with. But its a lot different than many of the GUI paradigms I've used in the past with other languages, I can certainly say that!

Anyway-- if you know of an easier way-- heh, I'm all ears!! I'd love to look at some "well-built" Qooxdoo apps for style and best-practice tips & pointers. I'm just kind of feeling my way along trying to get a feel for it.


John
Reply | Threaded
Open this post in threaded view
|

Re: The SOLUTION!!! (Was Re: Need help with Models please !!!!)

panyasan
This post was updated on .
Hi,

just to toss in my 2 cents: having used JSON-RPC w/ qooxdoo extensively in the past without any problems, I think that RPC  is not the way to go. All the new development in qooxdoo has been gone towards REST and there are good reasons for that, because it is the "native" web app data communication. I'd say that to be future-proof, it is either REST or a bidirectional protocol such as websockets/socket.io (which are not very well supported by PHP, of course).

I haven't looked at your code in detail, but I saw something about "synchronous", and I think that synchronous JSONRPC is a bad idea anyways. Many problems in JavaScript arise arise when you try to avoid the asynchronous model. Once you embrace it, it becomes much clearer how the program flow is and why stuff doesn't work. But maybe you have done that, then disregard my comment.
C.
Reply | Threaded
Open this post in threaded view
|

Re: The SOLUTION!!! (Was Re: Need help with Models please !!!!)

jwhitten

Yes, I have been using RPC-Sync temporarily, but have already set up and tested the async code. It is not my plan to stay with synchronous. However, in this instance, the problem was not in the communication, but in being able to alter the parameters that were being sent to the back-end. If someone has a lighter-weight way to do it, I'm really interested. Not that it's a big problem any more. I have _a_ way to do it, and at this point I can easily stuff it into the background and not worry about it until a cleaner solution presents itself.

John
Reply | Threaded
Open this post in threaded view
|

Re: Need help with Models please !!!!

slah
In reply to this post by jwhitten
Hi,
an out of topic question and sorry for that.
What editor are you using, seems it gives interesting features I don't have in SPKet.

Regards

jwhitten wrote
This is what it looks like just before I call RPC Sync...

Reply | Threaded
Open this post in threaded view
|

Re: Need help with Models please !!!!

Jim Hunter
Was that question directed at me? If so, I use SPKet also, but everything I have entered in this exchange was done manually inside GMail. What features are you refering to that you are missing?

Jim

On Thu, Oct 11, 2012 at 4:51 PM, slah <[hidden email]> wrote:
Hi,
an out of topic question and sorry for that.
What editor are you using, seems it gives interesting features I don't have
in SPKet.

Regards


jwhitten wrote
> This is what it looks like just before I call RPC Sync...
<http://qooxdoo.678.n2.nabble.com/file/n7581647/10-10-2012_2-22-30_PM.png>




--
View this message in context: http://qooxdoo.678.n2.nabble.com/Need-help-with-Models-please-tp7581630p7581681.html
Sent from the qooxdoo mailing list archive at Nabble.com.

------------------------------------------------------------------------------
Don't let slow site performance ruin your business. Deploy New Relic APM
Deploy New Relic app performance management and know exactly
what is happening inside your Ruby, Python, PHP, Java, and .NET app
Try New Relic at no cost today and get our sweet Data Nerd shirt too!
http://p.sf.net/sfu/newrelic-dev2dev
_______________________________________________
qooxdoo-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/qooxdoo-devel


------------------------------------------------------------------------------
Don't let slow site performance ruin your business. Deploy New Relic APM
Deploy New Relic app performance management and know exactly
what is happening inside your Ruby, Python, PHP, Java, and .NET app
Try New Relic at no cost today and get our sweet Data Nerd shirt too!
http://p.sf.net/sfu/newrelic-dev2dev
_______________________________________________
qooxdoo-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/qooxdoo-devel
Reply | Threaded
Open this post in threaded view
|

Re: The SOLUTION!!! (Was Re: Need help with Models please !!!!)

fritz
In reply to this post by jwhitten
Just for the record:

We have been using Qooxdoo's RPC for communication with the server backend
(Perl) for several years now using either RpcPerl Classic or RpcPerl with
Mojolicious (see http://qooxdoo.org/contrib/project) very sucessfully for
various projects. I don't understand why that is considered "absurd" or
"complicated".

Some of my bachelor students also managed to get this working with an RpcPhp
backend (I don't do Php if I can avoid it).

Cheers,
Fritz

On Thu, 11 Oct 2012, jwhitten wrote:

>
> Well, I definitely agree that it seems quite a bit over the top in terms of
> effort just to get data to the back-end. The js / qooxdoo side is nearly
> verbatim from some example I found on the net. All I did was modify it a
> little with try/catch blocks and added some debug messages to see what was
> happening.
>
> The back-end is about as plain-jane RPC as you can get. I've got two servers
> I've written, one in Perl, the other in PHP which toss RPC pretty
> generically. I think I wrote them some months back when I was testing
> various JS / Ajax frameworks. They've just always worked with very little
> tinkering. I wrote another one out of CPAN parts more recently that's even
> more generic-- JSON::RPC::Dispatcher.
>
> (shrug) :-)
>
> All my own JS code in the past has been trivial. This really seemed.. not
> sure how to even describe it-- somewhere between frustrating and absurd! :-)
> Had even been considering ditching Qooxdoo for something else. The
> documentation for the thing seems to alternate between pretty good and
> just-barely. I spend a lot of my time just trying to figure out what they're
> doing in places or compensating for something that doesn't seem to be there.
>
> I realize that it's an evolving effort. And I'm not meaning to knock
> anybody's efforts in any way-- you know, I'm pretty happy and thrilled at
> having a cool, open source toolkit to work with. But its a lot different
> than many of the GUI paradigms I've used in the past with other languages, I
> can certainly say that!
>
> Anyway-- if you know of an easier way-- heh, I'm all ears!! I'd love to look
> at some "well-built" Qooxdoo apps for style and best-practice tips &
> pointers. I'm just kind of feeling my way along trying to get a feel for it.
>
>
> John
>
>
>
> --
> View this message in context: http://qooxdoo.678.n2.nabble.com/Need-help-with-Models-please-tp7581630p7581660.html
> Sent from the qooxdoo mailing list archive at Nabble.com.
>
> ------------------------------------------------------------------------------
> Don't let slow site performance ruin your business. Deploy New Relic APM
> Deploy New Relic app performance management and know exactly
> what is happening inside your Ruby, Python, PHP, Java, and .NET app
> Try New Relic at no cost today and get our sweet Data Nerd shirt too!
> http://p.sf.net/sfu/newrelic-dev2dev
> _______________________________________________
> qooxdoo-devel mailing list
> [hidden email]
> https://lists.sourceforge.net/lists/listinfo/qooxdoo-devel
>
>

--
Oetiker+Partner AG              tel: +41 62 775 9903 (direct)
Fritz Zaucker                        +41 62 775 9900 (switch board)
Aarweg 15                            +41 79 675 0630 (mobile)
CH-4600 Olten                   fax: +41 62 775 9905
Schweiz                         web: www.oetiker.ch

------------------------------------------------------------------------------
Don't let slow site performance ruin your business. Deploy New Relic APM
Deploy New Relic app performance management and know exactly
what is happening inside your Ruby, Python, PHP, Java, and .NET app
Try New Relic at no cost today and get our sweet Data Nerd shirt too!
http://p.sf.net/sfu/newrelic-dev2dev
_______________________________________________
qooxdoo-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/qooxdoo-devel
Reply | Threaded
Open this post in threaded view
|

Re: The SOLUTION!!! (Was Re: Need help with Models please !!!!)

jwhitten
I never said the back-end was complicated. In fact, I pointed out that I've written THREE different back-end "servers" and each of them was TRIVIAL-- the most recent of which was the most trivial of all. What I DID say seemed complicated and absurd was the machinations required to get data packaged up and ready to GO to the back-end. As Jim and I were discussing, it should be really easy-- a JSON object or something similar. It SHOULDN'T take three whole days to figure out how to add extra parameters or turn a model into a regular array or to have to hoist it into being an object again in order to get it to the back-end. But that's what happened. Everything that seemed like it should be simple and obvious turned out to be complicated and obscure. And in fact, I wasn't able to reach a satisfactory conclusion without digging through the bowels of the framework code to figure out how they pick apart the object. If any of that is documented in the manual someplace, I've completely missed it.
Reply | Threaded
Open this post in threaded view
|

Re: The SOLUTION!!! (Was Re: Need help with Models please !!!!)

fritz
I don't package up the data at all. I just send a JS data structure to the
backend and everything else is done by the existing backends:

Qx frontend:

   rpc.callAsync( callback, 'backend_method', data);

Perl backend:

sub backend_method {
     my $error = shift;
     my $data  = shift;
}

Qx and the Rpc backend do all the magic for converting the frontend JS data
structure to JSON and then to the appropriate Perl data structure (an JS
array becomes a Perl array, a JS object becomes a Perl hash, etc).

I think all you need is already there. If you decide to write it from
scratch, I guess that might get complicated.

Cheers,
Fritz

On Fri, 12 Oct 2012, jwhitten wrote:

> I never said the back-end was complicated. In fact, I pointed out that I've
> written THREE different back-end "servers" and each of them was TRIVIAL--
> the most recent of which was the most trivial of all. What I DID say seemed
> complicated and absurd was the machinations required to get data packaged up
> and ready to GO to the back-end. As Jim and I were discussing, it should be
> really easy-- a JSON object or something similar. It SHOULDN'T take three
> whole days to figure out how to add extra parameters or turn a model into a
> regular array or to have to hoist it into being an object again in order to
> get it to the back-end. But that's what happened. Everything that seemed
> like it should be simple and obvious turned out to be complicated and
> obscure. And in fact, I wasn't able to reach a satisfactory conclusion
> without digging through the bowels of the framework code to figure out how
> they pick apart the object. If any of that is documented in the manual
> someplace, I've completely missed it.
>
> --
> View this message in context: http://qooxdoo.678.n2.nabble.com/Need-help-with-Models-please-tp7581630p7581687.html
> Sent from the qooxdoo mailing list archive at Nabble.com.
>
> ------------------------------------------------------------------------------
> Don't let slow site performance ruin your business. Deploy New Relic APM
> Deploy New Relic app performance management and know exactly
> what is happening inside your Ruby, Python, PHP, Java, and .NET app
> Try New Relic at no cost today and get our sweet Data Nerd shirt too!
> http://p.sf.net/sfu/newrelic-dev2dev
> _______________________________________________
> qooxdoo-devel mailing list
> [hidden email]
> https://lists.sourceforge.net/lists/listinfo/qooxdoo-devel
>
>

--
Oetiker+Partner AG              tel: +41 62 775 9903 (direct)
Fritz Zaucker                        +41 62 775 9900 (switch board)
Aarweg 15                            +41 79 675 0630 (mobile)
CH-4600 Olten                   fax: +41 62 775 9905
Schweiz                         web: www.oetiker.ch

------------------------------------------------------------------------------
Don't let slow site performance ruin your business. Deploy New Relic APM
Deploy New Relic app performance management and know exactly
what is happening inside your Ruby, Python, PHP, Java, and .NET app
Try New Relic at no cost today and get our sweet Data Nerd shirt too!
http://p.sf.net/sfu/newrelic-dev2dev
_______________________________________________
qooxdoo-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/qooxdoo-devel
Reply | Threaded
Open this post in threaded view
|

Re: The SOLUTION!!! (Was Re: Need help with Models please !!!!)

jwhitten
Not really interested in writing it from scratch. I agree what you wrote is what I'd prefer to do, and the way I've always done it.

If you don't mind, here is some code I've written to handle forms. The essential form and RPC code is pretty much an example I copied off the net... Please ignore the fact that I'm using RPC-SYNC instead of ASYNC. I've highlighted what I think is the relevant portions of the code, aside from creating the form itself.

If all you're doing is putting together a request to the backend, I agree, it's very simple. It's working with the form model that apparently complicates things. I will happily stipulate that there could easily be something I'm missing or have overlooked in my efforts to figure it all out. But what I needed / wanted to do was get the form model, add some additional parameters to it (my "crud" parameters, which I want / use on the backend) and then send it over. And that's where it stopped being simple for me.

I am HAPPY to LEARN-- I'm ALL EARS-- what should I do different from what I'm doing to accomplish this? It has nothing to do with the backend. My backend code works beautifully and I'm very happy with it for the moment. My issue is on the front-end, on the Qooxdoo / JS side. How do I get the form model, add additional parameters, and then pass it into the UriParameter serializer in a simpler, easier way???

I am not being in the slightest way facetious or sarcastic in my request-- it is a genuine question. I do not have a lot of JS experience. I am well-versed in programming in a variety of other languages but this is my first really big, major JS project.

John


The Form Part:


qx.Class.define("reilly.ui.form.Test",
{
        extend : reilly.ui.form.Generic,

        properties :
        {
        },

        events :
        {
        },

        construct : function()
        {
                this.base(arguments);
                this.setService('new');
                this.setUrl("MY_BACKEND_URL");
                this.setCrudMode("new");
                this.setCrudName("test");

                // set up model for form
                var myData = {
                        id : "__NEWID__", // serial
                        name : "testname", // varchar
                        network_id : null, // integer
                        quantity : "6" // integer
                        };
                var formModel = qx.data.marshal.Json.createModel( myData );


                //--------------------------------------------------------------------------------
                // ID Field
                this.add(new qx.ui.form.TextField().set({readOnly: true}), "Id", null, "id");

                //--------------------------------------------------------------------------------
                // NAME Field
                this.add(new qx.ui.form.TextField().set({required: true}), "Name", null, "name");

                //--------------------------------------------------------------------------------
                // NETWORK_ID Field
                // lookup data for selectbox control
                var rpc = new reilly.db.reibase.Lookup();
                rpc.setService("lookup");
                rpc.setName("MyShinyObject");
                rpc.setUrl("URL_TO_MY_BACKEND");
                var lookup_data = rpc.execute();

                //--------------------------------------------------------------------------------
                // use lookup date to populate selectbox control
                var network_id = this._getSelectBox(rpc.getDisplay(), lookup_data);
                this.add(network_id, "Network", null, "network_id");

                //--------------------------------------------------------------------------------
                // QUANTITY Field
                this.add(new qx.ui.form.TextField().set({required: true}), "Quantity", null, "quantity");

                //--------------------------------------------------------------------------------
                // save button
                this.addButton(this._getButton("Cancel", "onCancel"));
                this.addButton(this._getButton("Save", "onSubmit"));

                //--------------------------------------------------------------------------------
                // create form controller & model
                var formCtlr = new qx.data.controller.Form(formModel, this);
                this.initController(formCtlr);
                this.initModel(formModel);


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

        members :
        {
        }
});



The "Generic" Part, handles setting up form and RPC on the Qooxdoo / JS side:



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

        properties :
        {
                url: { init: null }, // back-end service url
                crudMode: { init: null },
                crudName: { init: null },
                controller : { deferredInit : true },
                model : { deferredInit : true },
                service : { init: "read" } // service name for backend
        },

        events :
        {
                "onSubmit" : "qx.event.type.Data", // called when Save / Submit button pressed
                "onCancel" : "qx.event.type.Data", // called when Cancel button pressed
                "onFinish" : "qx.event.type.Data" // called when form action is complete
        },

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

        members :
        {
                _getSelectBox : function(display_field, data)
                {
                        // set up device type combo box
                        var selectbox = new qx.ui.form.SelectBox().set({required: true});

                        if (display_field) { // multi-dimensional data
                                // new qx.data.controller.List(new qx.data.Array(data), selectbox); // bind list model to selectbox-list
                                var selectboxModel = qx.data.marshal.Json.createModel(data);
                                new qx.data.controller.List(selectboxModel, selectbox, display_field); // bind list model to selectbox-list
                                }
                        else {
                                new qx.data.controller.List(new qx.data.Array(data), selectbox); // bind list model to selectbox-list
                                // var selectboxModel = qx.data.marshal.Json.createModel(data);
                                // new qx.data.controller.List(selectboxModel, selectbox); // bind list model to selectbox-list
                                }



                        return selectbox;
                },

                _getButton : function(caption, fire_event_name, listen_event_name)
                {
                        var button = new qx.ui.form.Button(caption);
                        if (!listen_event_name) { listen_event_name = "execute"; } // default listener event name
                        button.addListener(listen_event_name, function(e) {
                                this.fireDataEvent(fire_event_name, this);
                                }, this);
                        return button;
                },

                //---------------------------------------------------------------------
                // Manage RPC Calls
                //---------------------------------------------------------------------


                //----------------------------------------------------------------------
                _getService : function(item)
                {

                        try { // try to get the service name
                                var service = item.getService();
                                qx.core.Init.getApplication().debug("RPC Service will be: " + service);
                                return service;
                                }
                        catch (exc) { // don't care what the error is, just don't bomb
                                qx.core.Init.getApplication().debug("Item has no service property: " + exc);
                                }
                        return "echo";
                },

                //----------------------------------------------------------------------
                _callRpcAsync : function(handler, service, url, params) // asynchronous model
                {
                        var rpc = new qx.io.remote.Rpc(url, service);

                        try {
                                return rpc.callAsync(handler, service, qx.util.Serializer.toUriParameter(params));
                                }
                        catch (exc) {
                                qx.core.Init.getApplication().debug("Exception occured during RPC-ASYNC call: " + exc);
                                }
                },

                //----------------------------------------------------------------------
                _callRpcSync : function(service, url, params) // synchronous model
                {
                        var rpc = new qx.io.remote.Rpc(url, service);

                        try {
//                              var results = rpc.callSync(service, qx.util.Serializer.toUriParameter(params));
                                var uriParams = qx.util.Serializer.toUriParameter(params);
                                var results = rpc.callSync(service, uriParams);
                                qx.core.Init.getApplication().getMainWindow().logEntry(results);
                                return results;
                                }
                        catch (exc) {
                                qx.core.Init.getApplication().debug("Exception occured during RPC-SYNC call: " + exc);
                                }
                },


                _enumProperties : function(caption, obj) // we can use this to enumerate properties of an object
                {
                        qx.core.Init.getApplication().getMainWindow().logEntry(caption);
                        var properties = qx.util.PropertyUtil.getAllProperties(obj.constructor);
                        for (var name in properties) {
                                var value = obj["get" + qx.lang.String.firstUp(name)]();
                                qx.core.Init.getApplication().getMainWindow().logEntry("Property name [" + name + "] = [" + value + "]");
                                }
                },

                _objToArray : function(obj)
                {
                        var arry = {};
                        var properties = qx.util.PropertyUtil.getAllProperties(obj.constructor);
                        for (var name in properties) {
                                if (properties[name].group != undefined) {
                                        continue;
                                        }
                                var value = obj["get" + qx.lang.String.firstUp(name)]();
                                // qx.core.Init.getApplication().getMainWindow().logEntry("Property name [" + name + "] = [" + value + "]");
                                arry[name] = value;
                                }
                        return arry;
                },


                //----------------------------------------------------------------------
                _handleSubmit : function(e)
                {
                        var item = e.getData();
                        qx.core.Init.getApplication().debug("Model: " + item.getModel());
                        qx.core.Init.getApplication().getMainWindow().logEntry(item.getModel());
                        var service = this._getService(item);
                        var model = item.getModel();
                        var arry = this._objToArray(model);
                        arry._crudMode = this.getCrudMode();
                        arry._crudName = this.getCrudName();
                        var new_model = qx.data.marshal.Json.createModel( arry, true );
                        // this._enumProperties("Our new model...", new_model);
                        this._callRpcSync(service, this.getUrl(), new_model);
                }

        }
});


12