Announcement

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

    ComboBoxItem doesn't show displayField with value in record

    SmartClient Version: SNAPSHOT_v11.1d_2016-10-16/Enterprise Development Only (built 2016-10-16)

    Chrome on OSX El Capitan

    Hello, please try this code:
    Code:
    isc.DynamicForm.create({
      ID:"testForm",
      fields:[
        {name:"foo", valueField:"itemID", displayField:"itemName", optionDataSource:"supplyItem", fetchMissingValues:false, editorType:"ComboBoxItem"}
      ]
    });
    
    testForm.setValues({foo:3958, itemName:"bar"});
    as you may see, the field displays '3958'.
    Reading the docs for displayField:
    Specifies an alternative field from which display values should be retrieved for this item. The display field can be either another field value in the same record
    I thought that the presence of the itemName value in the record would guaranteed that it will be displayed.
    Of course if I set fetchMissingValue to true, it would fetch the value and display it, but I am trying to avoid that extra fetch.
    Am I misunderstanding something?

    #2
    Hi claudiobosticco,

    IMHO the data you set is for the DynamicForm, so this would be displayed if you have an field itemName in the form as well.
    The editor-ComboBoxItem has its own ResultSet/ValueMap you can't set with myForm.setValues(). Perhaps if you provide a valueMap with editorProperties?

    Best regards
    Blama

    Comment


      #3
      Hi Claudio,
      The feature by which a form item will pick up a displayField value from the record currently being edited by the form is limited to fairly specific circumstances (by design).
      Basically this will only occur if the item has no explicit optionDataSource (so it's using the form's dataSource to provide the possible set of options), and the "valueField" for the item matches the item's "name".
      This essentially guarantees that the record being edited by the form is the same record that would be fetched to resolve a data value to a display value by the item, and that the system would be looking at the same attributes on the record to perform that mapping.
      What you're trying to do appears to be slightly different - you want to supply an initial display value as well as an initial data value for the field in question.
      The right way to achieve this is to simply specify an explicit valueMap mapping the display value to the data value. This will show the display value when the item is initially displayed, and will not interfere with the normal fetching of data from the optionDataSource when the user changes the value or shows the pickList.

      Regards
      Isomorphic Software

      Comment


        #4
        Originally posted by Isomorphic View Post
        What you're trying to do appears to be slightly different - you want to supply an initial display value as well as an initial data value for the field in question.
        yes, because actually, in the dataSource record, the display value is already present (via a join on the optionDataSource), so it seems unnecessary to fetch against the optionDataSource.
        Originally posted by Isomorphic View Post
        The right way to achieve this is to simply specify an explicit valueMap mapping the display value to the data value. This will show the display value when the item is initially displayed, and will not interfere with the normal fetching of data from the optionDataSource when the user changes the value or shows the pickList.
        I can confirm that what you are suggesting is working.

        But I don't understand what you're saying here:
        Originally posted by Isomorphic View Post
        This essentially guarantees that the record being edited by the form is the same record that would be fetched to resolve a data value to a display value by the item, and that the system would be looking at the same attributes on the record to perform that mapping.
        What about a more general solution like an override of DynamicForm.setValues and ValuesManager.setValues like this:
        Code:
        setValues: function (newData) {
                var items = this.getItems();
                for (var index = items.getLength() - 1; index >= 0; index--) {
                    var item = items.get(index);
                    var displayFieldName = item.displayField;
                    var itemValue = newData[item.name];
                    var itemDisplayValue = newData[displayFieldName];
                    if (itemValue && displayFieldName && item.optionDataSource && itemDisplayValue) {
                        var valueMap = {};
                        valueMap[itemValue] = itemDisplayValue;
                        item.setValueMap(valueMap);
                    }
                }
                this.Super("setValues", arguments);
            }
        For my use case it seems to work. Would it be reliable in general? Or why wouldn't it be feasible?

        Comment


          #5
          It sounds like perhaps you're looking our the behavior described in our "dataSourceField.includeFrom" feature:
          http://www.smartclient.com/smartclie...ld.includeFrom
          See the chunk on editing fields in that documentation block.

          Essentially, by specifying a field in a DataSource with 'includeFrom' set up, and ensuring there is a foreignkey relationship between two dataSources defined, you tell the framework to perform a join automatically and fetch the result for the field in question.
          If you need editing behavior, you can have the foreignKey relationship field be visible and editable, and set the displayField to this included field. You don't need to explicitly set and optionDataSource, or valueField yourself - these'll be derived from the optionDataSource automatically.

          Let us know if this doesn't give you the behavior you want or you need further information.

          Comment


            #6
            My actual use case is like this:

            Code:
            <DataSource
                ID="largeValueMap_orderItem"
                serverType="sql"
                tableName="valMapOrderItem"
                testFileName="/examples/shared/ds/serverExamples/test_data/orderItem.data.xml"
            >
                <fields>
                    <field name="pk" type="sequence" primaryKey="true" hidden="true" />
                    <field name="orderID" type="integer" />
                    <field name="orderDate" type="date" />
                    <field name="itemID" type="integer" foreignKey="supplyItem.itemID" displayField="supplyItemName" />
                    <field name="unitPrice" type="float" />
                    <field name="quantity" type="integer" />
                    <field name="supplyItemName" type="text" includeFrom="supplyItem.itemName"/>
                </fields>
            </DataSource>
            Code:
            isc.DynamicForm.create({
              ID:"testForm",
              dataSource:"largeValueMap_orderItem",
              fields:[
                {name:"itemID", editorType:"ComboBoxItem", canEdit:true, optionDataSource:"supplyItem"}
              ]
            });
            
            testForm.fetchData({pk:1});
            If I don't explicitly set the optionDataSource, it won't display the supplyItemName value, but if I set it, a fetch on supplyItem with criteria {itemID:1} will occur.
            Am I overlooking something?

            Comment


              #7
              Interesting.
              If you change your included field's name from "supplyItemName" to "itemName" (so it matches the secondary dataSource's field name), you can get rid of the optionDataSource setting on the item and it'll work.
              If that's an option for you in your app, it, (or using and explicit valueMap + explicit optionDataSource) should work to get you going.

              In the meantime, we've got one of our engineers taking a look at this use case to see if there's a framework bug or if this is just a strange edge case.
              We'll follow up here when we have more information

              Regards
              Isomorphic Software

              Comment


                #8
                Originally posted by Isomorphic View Post
                Interesting.
                If you change your included field's name from "supplyItemName" to "itemName" (so it matches the secondary dataSource's field name), you can get rid of the optionDataSource setting on the item and it'll work.
                If that's an option for you in your app, it, (or using and explicit valueMap + explicit optionDataSource) should work to get you going.
                Unfortunately this isn't an option in my app, because I have more than one foreign key, with different optionDataSources, but where the secondary dataSource's field names are the same.
                Last edited by claudiobosticco; 7 Nov 2016, 13:22.

                Comment


                  #9
                  We've actually made a change to address this in the 11.1d branch (which you are using from the original post). This change went in last week so if you pick up the latest nightly build, (Nov 7), you should get the change.
                  Can you re-test with this build and let us know if the problem is indeed addressed for you.

                  Thanks
                  Isomorphic Software

                  EDIT: Just a quick note to add: This change has also been made in 11.0p, but that edit was made today so will not be available publicly until the Nov 8th nightly build
                  Last edited by Isomorphic; 7 Nov 2016, 14:29.

                  Comment


                    #10
                    SmartClient Version: SNAPSHOT_v11.1d_2016-11-07/Enterprise Development Only (built 2016-11-07)

                    Hello, the test case of post #6 now is working, but my actual use case does not work.

                    But actually, in those two dataSources from the showcase, there are fields with the same name, which is something I haven't got.

                    Please modify supplyItem.ds.xml:

                    Code:
                    <DataSource
                        ID="supplyItem"
                        serverType="sql"
                        tableName="supplyItem"
                        titleField="itemName"
                        testFileName="/examples/shared/ds/test_data/supplyItem.data.xml"
                        dbImportFileName="/examples/shared/ds/test_data/supplyItemLarge.data.xml"
                    >
                        <fields>
                            <field name="ID" nativeName="itemID"      type="sequence" hidden="true"       primaryKey="true"/>
                            <field name="name" nativeName="itemName"    type="text"     title="Item"        length="128"       required="true"/>
                        </fields>
                    </DataSource>
                    and largeValueMap_orderItem.ds.xml

                    Code:
                    <DataSource
                        ID="largeValueMap_orderItem"
                        serverType="sql"
                        tableName="valMapOrderItem"
                        testFileName="/examples/shared/ds/serverExamples/test_data/orderItem.data.xml"
                    >
                        <fields>
                            <field name="pk" type="sequence" primaryKey="true" hidden="true" />
                            <field name="orderID" type="integer" />
                            <field name="orderDate" type="date" />
                            <field name="itemID" type="integer" foreignKey="supplyItem.ID" displayField="supplyItemName" />
                            <field name="unitPrice" type="float" />
                            <field name="quantity" type="integer" />
                            <field name="supplyItemName" type="text" includeFrom="supplyItem.name"/>
                        </fields>
                    </DataSource>
                    then if you run this js code:
                    Code:
                    isc.DynamicForm.create({
                      ID:"testForm",
                      dataSource:"largeValueMap_orderItem",
                      fields:[
                        {name:"itemID", editorType:"ComboBoxItem", canEdit:true, optionDataSource:"supplyItem", valueField:"ID", foreignDisplayField:"name"}
                      ]
                    });
                    
                    testForm.fetchData({pk:1});
                    you'll see the extra fetch against supplyItem, even if the supplyItemName value is already in the record fetched against largeValueMap_orderItem.

                    Comment


                      #11
                      Sorry for the pause in responding here.
                      After some internal re-analysis we've come up with a solution which we believe resolves this issue.

                      There is some logic built into the framework to determine in which cases it is appropriate to use the display field from the record being currently edited (as opposed to issuing a fetch).
                      We've made two changes to this logic:
                      Firstly - if (as in your case) the specified displayField is being picked up from a related dataSource using the "includeFrom" feature we go ahead and use this record even if the field name differs from the valueField for the item.
                      Secondly - it has become clear that the built in default behavior was somewhat tricky to get just right and had a nasty tendency to feel like "black magic". We've therefore beefed up our documentation around formItem.displayField and related properties, and also added a new Boolean attribute "formItem.useLocalDisplayFieldValue" which, if specified, will explicitly cause the display field value to be picked up from the record currently being edited instead of relying on the built in algorithm to determine whether this is appropriate. We're hoping this will resolve the ambiguity and confusion in this area.

                      The changes will be present in the next nightly build (Nov 16 or above) on the 11.1d branch

                      Regards
                      Isomorphic Software

                      Comment


                        #12
                        SmartClient Version: SNAPSHOT_v11.1d_2016-11-30/Enterprise Development Only (built 2016-11-30)

                        Thank you very much for the effort on this. And sorry for my pause in responding, also.

                        For now I've tested the use case from post #10, and it doesn't work as expected, as I see the extra fetch against supplyItem.
                        There isn't the extra fetch if I set the new useLocalDisplayFieldValue attribute, though.
                        But if I understood correctly your first point and the updated docs, it must work without setting it, right?

                        Comment


                          #13
                          We'll re-check this.
                          It sounds like you can just make use of the useLocalDisplayFieldValue attribute in any case so you're no longer stuck, right?

                          Thanks
                          Isomorphic Software

                          Comment


                            #14
                            Hello, I've just tested the useLocalDisplayFieldValue attribute in my actual application (which is in development), and it's working as intended, no more extra fetches, so, yes I can let it in place.

                            The usage as in your first point, would be a nice optimization for another, older application, where I've got a big form with many ComboBoxes which are triggering unneeded fetches.
                            So please let me know if you'll fix that use case, too.

                            Thank you very much!

                            Comment


                              #15
                              We've come up with a solution for this. We were attempting to refer to dataSourceField.includeFrom directly in our client-side framework code, but for security reasons that property is actually stripped out of the DataSource definition before the ds is served to the client. Therefore we can't access it directly on the client.
                              Instead we now have logic to set the default value of "useLocalDisplayFieldValue" to true on such fields (though developers may override this property in their .ds.xml file if they want different behavior).

                              This change will be present in the next 11.1d nightly build (Dec 2 or above)

                              Regards
                              Isomorphic Software

                              Comment

                              Working...
                              X