Announcement

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

    Problem with databound ComboBoxItem

    Hello Isomorphic,

    I have a ComboBoxItem which is bound to custom DataSource. Looks like being in the pre-populated field and just pressing Shift or exiting from the field with "Tab" etc mark item as "Pending" and cause unnecessary DataSource Fetch call. This is especially bad when current field display value (what's displayed and what's user is tabbing from) is not processed by server in the way that could be resolved back to the code. See example below. Steps to reproduce:
    1. Click onto first field to focus into it
    2. Click "Tab"
    3. You will see round-trip is made (in "DataSource Log" field below) while no any single change is made

    In my case it's really not about inefficiency but rather about not being able to resolve display value back to stored value. Please help!!!

    <html>
    <!-- =================== Smart Client Loading ======================================= -->
    <SCRIPT>window.isomorphicDir = "/SmartClient/"</SCRIPT>
    <SCRIPT SRC="/SmartClient/system/modules/ISC_History.js"></SCRIPT>
    <SCRIPT SRC="/SmartClient/system/modules/ISC_Core.js"></SCRIPT>
    <SCRIPT SRC="/SmartClient/system/modules/ISC_Foundation.js"></SCRIPT>
    <SCRIPT SRC="/SmartClient/system/modules/ISC_Containers.js"></SCRIPT>
    <SCRIPT SRC="/SmartClient/system/modules/ISC_Grids.js"></SCRIPT>
    <SCRIPT SRC="/SmartClient/system/modules/ISC_Forms.js"></SCRIPT>
    <SCRIPT SRC="/SmartClient/system/modules/ISC_DataBinding.js"></SCRIPT>
    <SCRIPT SRC="/SmartClient/skins/Enterprise/load_skin.js"></SCRIPT>

    <body onload="initialize()">

    <script>
    function initialize() {
    isc.DataSource.create({
    ID: "someDataSource1",
    clientOnly: true,
    dataProtocol: "clientCustom",
    dataFormat: "json",

    fields: [{ name: "id" }, {name: "name"}],
    cacheData: [
    { id: 1, name: "Item 1" },
    { id: 2, name: "Item 2" },
    { id: 3, name: "Item 3" },
    { id: 4, name: "Item 4" }
    ],
    transformRequest: function(dsRequest) {
    var data = dsRequest.data ? JSON.stringify(dsRequest.data) : "--"
    var logItem = theForm.getItem("dsLog")
    logItem.setValue((logItem.getValue() || "") + "DS1 Request: " + data + "\n")

    var dsResponse = {
    clientContext: dsRequest.clientContext,
    status: 0,
    data: this.cacheData
    }

    var me = this
    setTimeout(function() {
    me.processResponse(dsRequest.requestId, dsResponse)
    }, 0)
    }
    });
    isc.DataSource.create({
    ID: "someDataSource2",
    clientOnly: true,
    dataProtocol: "clientCustom",
    dataFormat: "json",

    fields: [{ name: "id" }, {name: "name"}],
    cacheData: [
    { id: 1, name: "Item 1" },
    { id: 2, name: "Item 2" },
    { id: 3, name: "Item 3" },
    { id: 4, name: "Item 4" }
    ],

    transformRequest: function(dsRequest) {
    var data = dsRequest.data ? JSON.stringify(dsRequest.data) : "--"
    var logItem = theForm.getItem("dsLog")
    logItem.setValue((logItem.getValue() || "") + "DS2 Request: " + data + "\n")

    var dsResponse = {
    clientContext: dsRequest.clientContext,
    status: 0,
    data: this.cacheData
    }

    var me = this
    setTimeout(function() {
    me.processResponse(dsRequest.requestId, dsResponse)
    }, 0)
    }

    });
    var theForm = isc.DynamicForm.create({
    values: { x: 3, y: 3 },
    items: [
    { name: "theComboBox1", dataPath: "x", editorType: "comboBox", optionDataSource: "someDataSource1", valueField: "id", displayField: "name", minimumSearchLength: 3,
    title: "addUnknownValues: false", showPending: true, addUnknownValues: false, cachePickListResults: false, width: 300 },
    { name: "theComboBox2", dataPath: "y", editorType: "comboBox", optionDataSource: "someDataSource2", valueField: "id", displayField: "name",
    title: "addUnknownValues: true", showPending: true, width: 300 },
    { name: "dsLog", title: "DataSource log", editorType: "textArea", height: 200, width: 300 }
    ]
    });

    }

    </script>
    </body>


    #2
    First, update to the latest patched version of whatever version and edition of SmartClient you're using (see smartclient.com/builds). If the problem is still there, post your exact edition and version and let us know what browser(s) are affected. Remember to do this every time you post.

    Also, use "code" tags around any sample code or all indentation is lost.

    Comment


      #3
      Hello,

      I've rechecked the issue with latest SmartClient build (SmartClient_v110p_2017-02-14_LGPL) and the problem still happens. I'm checking this in Google Chrome (Version 56.0.2924.87). The problem demoo code:
      Code:
       <html>
      
          <!-- =================== Smart Client Loading ======================================= -->
      <SCRIPT>window.isomorphicDir = "/SmartClient/"</SCRIPT>       
      
      <SCRIPT SRC="/SmartClientLatest/system/modules/ISC_History.js"></SCRIPT>
      <SCRIPT SRC="/SmartClientLatest/system/modules/ISC_Core.js"></SCRIPT>
      <SCRIPT SRC="/SmartClientLatest/system/modules/ISC_Foundation.js"></SCRIPT>
      <SCRIPT SRC="/SmartClientLatest/system/modules/ISC_Containers.js"></SCRIPT>
      <SCRIPT SRC="/SmartClientLatest/system/modules/ISC_Grids.js"></SCRIPT>
      <SCRIPT SRC="/SmartClientLatest/system/modules/ISC_Forms.js"></SCRIPT>
      <SCRIPT SRC="/SmartClientLatest/system/modules/ISC_DataBinding.js"></SCRIPT>
      <SCRIPT SRC="/SmartClientLatest/skins/Enterprise/load_skin.js"></SCRIPT>
      
      
      <body onload="initialize()">
      
      
      
      
      <script>
      
      function initialize() {
      
       isc.DataSource.create({
        ID: "someDataSource1",
        clientOnly: true,
        dataProtocol: "clientCustom",
        dataFormat: "json",
      
        
        fields: [{ name: "id" }, {name: "name"}],
        cacheData: [
         { id: 1, name: "Item 1" },
         { id: 2, name: "Item 2" },
         { id: 3, name: "Item 3" },
         { id: 4, name: "Item 4" }
        ],
        transformRequest: function(dsRequest) {
         var data = dsRequest.data ? JSON.stringify(dsRequest.data) : "--"
         var logItem = theForm.getItem("dsLog")
         logItem.setValue((logItem.getValue() || "") + "DS1 Request: " + data + "\n")
         
         var dsResponse = {
          clientContext: dsRequest.clientContext,
          status: 0,    
          data: this.cacheData
         }
         
         var me = this   
         setTimeout(function() {
          me.processResponse(dsRequest.requestId, dsResponse)
         }, 0)
        }
       });
      
       isc.DataSource.create({
        ID: "someDataSource2",
        clientOnly: true,
        dataProtocol: "clientCustom",
        dataFormat: "json",
      
      
        fields: [{ name: "id" }, {name: "name"}],
        cacheData: [
         { id: 1, name: "Item 1" },
         { id: 2, name: "Item 2" },
         { id: 3, name: "Item 3" },
         { id: 4, name: "Item 4" }
        ],
        
        transformRequest: function(dsRequest) {
         var data = dsRequest.data ? JSON.stringify(dsRequest.data) : "--"
         var logItem = theForm.getItem("dsLog")
         logItem.setValue((logItem.getValue() || "") + "DS2 Request: " + data + "\n")
         
         var dsResponse = {
          clientContext: dsRequest.clientContext,
          status: 0,    
          data: this.cacheData
         }
         
         var me = this   
         setTimeout(function() {
          me.processResponse(dsRequest.requestId, dsResponse)
         }, 0)
        }
        
       });
      
       var theForm = isc.DynamicForm.create({  
        values: { x: 3, y: 3 },
        items: [
         { name: "theComboBox1", dataPath: "x", editorType: "comboBox", optionDataSource: "someDataSource1", valueField: "id", displayField: "name", minimumSearchLength: 3,   
          title: "addUnknownValues: false", showPending: true, addUnknownValues: false, cachePickListResults: false, width: 300 },
         { name: "theComboBox2", dataPath: "y", editorType: "comboBox", optionDataSource: "someDataSource2", valueField: "id", displayField: "name",
          title: "addUnknownValues: true", showPending: true, width: 300 },
         { name: "dsLog", title: "DataSource log", editorType: "textArea", height: 200, width: 300 }
        ]
       });
        
      }
      
      
      </script>
      
      </body>

      Comment


        #4
        Hi Nick,
        There are a couple of things to talk about here.

        Firstly: In the sample here the display value "Item 3" differs from the actual data value (3).
        Typically a fetch against the dataSource would be required to initially show the display value to the user (this would occur when the form is drawn). You would then not see a second fetch for the display value while tabbing through the items.
        In this sample you have a full cache of data attached to the DataSource directly and this makes things behave a bit differently. The framework is smart enough to recognize that it needs a display value and there is a full data cache loaded on the client so reaches into it directly without an explicit fetch occurring.
        However when you then tab through the items, it has never performed a fetch and does so now.

        You can see this explicitly if you rework your sample slightly to avoid giving the DataSources explicit cacheData and instead having the array of records picked up by your custom 'transformRequest' logic be stored elsewhere. Note that you'll also have to tweak the method to avoid assuming 'theForm' has already been created when transformRequest runs, as this makes the fetch occur during the initialization flow of the form itself. We'd recommend using the 'isc.logWarn()' and 'isc.showConsole()' methods to log information about the app for debugging purposes like this.
        Having done this you should see an initial fetch against the dataSource to pick up the display value, but no second fetch attempting to map the display value back to a data value as the user tabs through the fields. This is also what you'd see with a typical server-backed dataSource (a SmartClient SQL dataSource, or RESTDataSource, say).

        If you want to avoid a server side fetch at init time (even without a cacheData array attached to the DataSource) you can achieve this by providing an explicit valueMap to the item.

        Those two changes (an explcit valueMap, plus a DataSource without a full clientOnly cache of data) should therefore resolve this issue for you.

        However, we agree it is surprising that tabbing through the items causes a fetch when the data value was supplied and the display value derived from it (using the dataSource's cacheData).
        We're looking into whether this can easily be avoided.

        One other note: If you haven't already, you may also want to consider whether a SelectItem makes more sense for your usage than a ComboBoxItem. This gets rid of the 'freeform text entry' aspect of the control, but user-driven filtering of the options is still available via the 'showFilterEditor' option on the pickList, as demonstrated in this sample.

        Regards
        Isomorphic Software

        Comment


          #5
          Thanks, I will give it a try

          Comment

          Working...
          X