Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    More intuitive databinding to nested datasets

    There is already a similar thread, but I want to more specifically explain what I would like. First of all, let me say that this is an excellent framework, incredible performance, I can hardly believe this is dhtml. That grid is work of art.
    Now... I believe there is a flaw in the design of the databinding model. When binding to nested datasources, I currently have to use the 'name' field of the form item to match a property in the datasource. Furthermore, I have to call 'form.editRecord(record.nestedObj)' and set the datasource of the form to the datasource of the nested object. It would be much, much better if I could set the datasource of the form to the same as the parent record, and then have an explicit field on the fieldItems (i.e. 'datapath'), which I could set to something like 'nestedObj/field1' or 'nestedObj.field1'. The form would act as data container, allowing me to keep everthing more organized. The way it stands now, it seems like I have 3 options for showing multiple nested items in a form:
    1. create multiple forms, one for each nested item. Not that elegant.
    2. flatten my data in the dataset for each property w/ xpathvalue. I lose my intuitive hierarchy this way.
    3. use form.setValues and write plumbing code to pass custom object in, and out again. Ugh.

    Thanks,

    Chris

    #2
    Us too!

    +1

    We also want to be able to bind DynamicForm(s) to DataSouce(s) with nested DataSource(s).

    DataSources defined like:
    Code:
    isc.DataSource.create({
        ID: TOP_LEVEL_DS,
        recordXPath:'/rootNode',
        fields:[
                {name:'nestedStructA', type:NESTED_DS_A, childrenProperty:true, valueXPath:'nestedStructA'},	
                {name:'nestedStructB', type:NESTED_DS_B, childrenProperty:true, valueXPath:'nestedStructB'},
                {name:'nestedStructC', type:NESTED_DS_C, childrenProperty:true, valueXPath:'nestedStructC'},
    			...						
                ]
    });
    
    isc.DataSource.create({
        ID:NESTED_DS_A,
        recordXPath:'/rootNode/nestedStructA',
        fields:[
                {name:'field1', type:'text', valueXPath:'a_field1'},
                {name:'field2', type:'text', valueXPath:'a_field2'},
                {name:'field3', type:'text', valueXPath:'a_field3'}
    			...
                ]
    });
    
    isc.DataSource.create({
        ID:NESTED_DS_B,
        recordXPath:'/rootNode/nestedStructB',
        fields:[
                {name:'field1', type:'text', valueXPath:'b_field1'},
                {name:'field2', type:'text', valueXPath:'b_field2'},
                {name:'field3', type:'text', valueXPath:'b_field3'}
    			...
                ]
    });
    
    isc.DataSource.create({
        ID:NESTED_DS_C,
        recordXPath:'/rootNode/nestedStructC',
        fields:[
                {name:'field1', type:'text', valueXPath:'c_field1'},
                {name:'field2', type:'text', valueXPath:'c_field2'},
                {name:'field3', type:'text', valueXPath:'c_field3'}
    			...
                ]
    });
    Then the form's field array would be something like this
    Code:
    dataSource: TOP_LEVEL_DS,
    fields:
    [
        { name: ID:NESTED_DS_A + ".a_field1", type: "StaticTextItem", titleAlign: "left" },
        { name: ID:NESTED_DS_B + ".b_field1", type: "StaticTextItem", titleAlign: "left" },
        { name: ID:NESTED_DS_C + ".c_field1", type: "StaticTextItem", titleAlign: "left" },
    
        { name: ID:NESTED_DS_A + ".a_field2", type: "StaticTextItem", titleAlign: "left" },
        { name: ID:NESTED_DS_B + ".b_field2", type: "StaticTextItem", titleAlign: "left" },
        { name: ID:NESTED_DS_C + ".c_field2", type: "StaticTextItem", titleAlign: "left" },
    
        { name: ID:NESTED_DS_A + ".a_field3", type: "StaticTextItem", titleAlign: "left" },
        { name: ID:NESTED_DS_B + ".b_field3", type: "StaticTextItem", titleAlign: "left" },
        { name: ID:NESTED_DS_C + ".c_field3", type: "StaticTextItem", titleAlign: "left" },	
    ]

    Comment


      #3
      There more automatic behavior for this implemented in the 8.0 codeline, but if you lookat the Master-Detail Batch Load and Save sample for 7.0 you can see there only a couple of lines of code required at the moment, easily encapsulated as a custom class if you prefer.

      Comment


        #4
        I've hunted and pecked through the Featured Samples and am not finding it. The only Master/Detail I found was in Server Examples -> Transaction, but they do not make use of DynamicForm(s). Server Examples also has a Batch Uploader, but again, no use of DynamicForms.

        Some pointers to what you are referring to would be great.

        Thanks,
        TT

        Comment


          #5
          Next folder over, Server Examples -> Hibernate / Beans -> Master - Detail (Batch Load and Save).

          Here's the link.

          Comment


            #6
            OK, I see the example. And I see this

            Code:
            isc.DynamicForm.create({
                ID: "orderForm",
                dataSource: "masterDetail_orderHB",
                autoDraw: false,
                fields: [
                    { name: "orderID", title: "Order ID", disabled: true },
                    { name: "customerName", title: "Customer Name" },
                    { name: "orderDate", title: "Order Date", type: "date" }
                ]
            });
            Looking for the couple of lines that bind the form to the nested data. So, in this example specifically, I'm looking for where the "items" field is bound to the DynamicForm along with the fields already bound in the code snippet.

            Thanks,
            TT

            Comment


              #7
              There's really only a handful of lines of non-declarative code in the whole sample - those are the ones.

              In selectionChanged() a nested data structure is split between a form (the order itself) and a grid (the order items).

              In click() on the save button, the data from the grid is applied to the form before saving.

              The same pattern used with the nested grid here would apply to a singular subobject being edited by a nested form. And again, it could be encapsulated as a custom component straightforwardly.

              Comment


                #8
                I agree w/ the original poster in that creating nested forms for each nested item is not elegant. It's not really what is desired at all. A form and a grid, or a form and sub-form divide the UI based on DataSource nesting. This is not what is being asked for here.

                1) I'd like to have one form. This allows me to control the layout / placements for fields to meet my look and feel / requirements no matter where that field is nested in the data. 2) I have nested data sources, and need a way to set up the from fields[] to point to various root AND nested data items in order to achieve wish #1. The key point really is that fields arranged in the UI are not arranged the same way they are nested in the DataSource.

                Based on the comments it doesn't sound as if this is something 7.x can do. Will 8.0 be able to do this, or will it just automate the 7.x suggestion of dividing the UI into the form (for root fields) and sub-form (for nested fields) described above?

                Comment


                  #9
                  There are a number of ways to do this in 7.0. Take a step back and review a few basic concepts:

                  1. a DynamicForm is just a bunch of form controls in a tabular layout - think of it as a "FormLayout" instead if you wish, so you don't get hung up on trying to cram everything into one DynamicForm instance. It's common that a logical form is split across multiple DynamicForm instances (eg, splitting a form across tabs), and the ValuesManager class allows you to tie all these DynamicForms together so they behave as one logical form for the purposes of managing values, validation and saving.

                  2. a DataSource does not need to directly reflect a data model - a DataSource is a projection of the data model into the UI. It's common to flatten the data model at the DataSource level if the target UI is flat - see this sample and note there is both client and server-side support for flattening via XPath

                  3. You have the ability to completely override how the DynamicForm manages values. Consider FormItem.shouldSaveValue:false, which disables automatically applying values to the form, FormItem.changed() to detect changes, DynamicForm.setValue() to set the value in whatever way you want (eg, implement a "data path" concept), and DynamicForm.getEditorType() as an override point to customize what FormItems are used so as to better encapsulate a custom values handling strategy.

                  SmartClient has offered multiple approaches for handling the mapping of data structures to UI layouts for many years now - just have to be thorough in your review of available functionality.

                  Comment


                    #10
                    Thanks for the info. Something to think on for sure.

                    1. Roger that!

                    2. I've been forced to do this, but don't like it. With different forms needing to access some of some of the same data, I've been forced to create a separate DataSource per form. In my mind, this violates good coding practices, such as the DRY principle. Or, I guess a single giant DataSource with all the data needed for every form could work, but that feels wrong too.

                    3. This starts to get into areas I'm still learning. Implementing my own data path concept is tempting, but my attempts at it so far have turned out to be much harder than the duplicate code of options #2. As such, I like option #2 better. Also, I think my findings are that these methods do not fire all the time. Like the getValue and setValue only fire if the control is not disabled (I think I saw this, couldn't swear to it now). I do know that they were not always firing, and so I haven't found the correct touch point to the data that will let me do the data path thing all the way yet. Seems to be a lot of work. Give me another month on SC, and I could be singing a different tune, who knows.

                    Thanks again,
                    TT

                    Comment


                      #11
                      On #2, there's no way to comment without seeing a specific data model, save format, and two different target form renderings that seem to somehow require different DataSources. Suffice it to say, in our own consulting projects we frequently make use of projecting a simplified data model to the client, but rarely if ever project the same underlying data model two different ways.

                      It's possible that you are not yet aware of the ability to specify fields on *both* the component and the DataSource, to specialize the appearance of a DataSource on different screens - see this doc.

                      On #3, try using the specific combination of APIs we recommended rather than whatever overrides you were trying before.

                      Comment


                        #12
                        I can't give you my real code, and can't come up with a simple test app in short order that accurately represents my scenario. In general I have a wizard like flow, I subscribe to some third party xml service-like data feeds, the data in the xml is grouped/nested roughly how I need them per page of the wizard. Then there is the final step right before the update where a review form is shown, all StaticTextItems, of misc. data from the various pages in my flow. Making use of the nested DataSource technique in SmartClient I'm able to implement the wizard with SmartClient pretty much out of the box.

                        My wish is simply that DynamicForm be matured to the point where it can work with the nested DataSource(s) functionality provided by SmartClient.

                        If it were, I could implement the Review page pretty much with SmartClient out of the box as well. Not via a collection of overrides or a separate flat DataSource (my solution for now, and seems to be the easiest of the work arounds).

                        Comment

                        Working...
                        X