Announcement

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

    Send array of field names as request property in ListGrid

    Is there a way to send an array of field names as request parameters from a ListGrid? This way the server gets instructed which fields to return (it will check access rights). I have a similar construction in a ComboBoxItem where I set optionFilterContext.outputs to the list of fields in the pick list.

    I'm asking this because I'm trying to combine server code that returns data for grids and for combo boxes. I'm using SmartClient 11.0 (latest nightly build), with a RubyOnRails back-end.
    Last edited by wallytax; 9 Jun 2016, 01:44.

    #2
    We don't recommend doing this in general, since it would potentially require re-fetching all data when showing and hiding fields, and sending additional fields is relatively inexpensive.

    However if you have an unusual case where this makes sense, you could use DataSource.transformRequest() as a place to add outputs to the outbound DSRequest.

    Comment


      #3
      I'm get the feeling I'm doing something extraordinary but it doesn't feel like it is. I have a situation where I have a grid of customers, showing 10 fields. I also have a form where I can enter orders. In it I have a combo box item for the customer. There I only need two fields (id and name). At the server I want to have one server action that handles both use cases. Simply returning all fields seems to be inefficient and besides that, some fields are looked up in other tables. I'm not using the whole SmartClient stack and I'm aware there are some properties in the data sources that can handle these situations. My goal is to minimize SQL statements.

      But I actually use the approach of DataSource.transformRequest() but I don't know how to add an extra request parameter from the ListGrid telling me which fields I want the server to return. For ComboBoxItems I managed to do so by setting optionFilterContext.outputs to ['fieldA', 'fieldB', 'fieldC'] (in a dynamic matter, looking at the real grid fields and some extra properties). Then in the DataSource I have this "outputs" property in the request. I can't manage to do the same for ListGrid.
      Last edited by wallytax; 9 Jun 2016, 11:39.

      Comment


        #4
        I'm wondering how to make this more clear. It is quite logical to think of situations where you want to retrieve a different set of columns for the same model (database table). Most likely for combo boxes and overview grids.

        I'm working with SmartClient for a couple of years now and am (fortunately) still learning things, but somehow still this approach isn't clear to me. Until now I managed to retrieve two different URLs. In the ComboBoxItem I set optionOperationId (giving it a value of "combo"):

        Code:
          isc.defineClass('MyComboBoxItem', isc.ComboBoxItem).addProperties({
            optionOperationId: 'combo'
          });
        Then I overruled getDataURL() in RestDataSource so that it returns /customers/combo.json as URL.

        Code:
          isc.defineClass('MyDataSource', isc.RestDataSource).addProperties({
            dataFormat: 'json',
            getDataURL: function (request) {
              url = [this.Super('getDataURL', arguments)];
              // in transformRequest() I set this _id property (code not included)
              if (request._id != null) {
                url.push(request._id);
              }
              if (request.operationId != null) {
                url.push(request.operationId);
              }
              return [url.join('/'), this.dataFormat].join('.');
            }
          });
        
          isc.defineClass('CustomersDataSource', isc.MyDataSource).addProperties({
            dataURL: '/customers'
          });
        So far, so good, until I started using a TreeGrid component that seems to be sending an operationId as well. Gone was my generic solution for "custom" URLs. So now I try to get rid of the operationId method. So somehow I have to tell the server that I'm requesting from a combo box. The optionFilterContext.outputs option seemed useful in that it helped sending the list of fields that I want to retrieve from the server, so I created this init() method in MyComboBoxItem:

        Code:
          // my original source code is in coffeescript, so I "translated" it to JavaScript below
          // (maybe there are some errors in it that aren't there in my real code)
          init: function () {
            var field, i, len, ref;
            outputs = [];
            if (this.displayField != null) {
              outputs.push(this.displayField);
            }
            outputs = outputs.concat(this.extraPickListFields || []);
            ref = this.pickListFields || [];
            for(i = 0, len = ref.length; i < len; i++) {
              field = ref[i];
              results.push(field.name);
            }
            this.optionFilterContext = isc.addProperties({
              outputs: outputs.getUniqueItems()
            }, this.optionFilterContext);
            this.Super('init', arguments);
          }
        I all examples I never see this approach of creating a subclass for a certain resource data source (in my case "CustomersDataSource"), but always an instance with a global ID. And in all examples this ID is used as value for the dataSource property of components. I've tried this approach in the beginning and somehow it failed. It's too much to type to explain what happened (and frankly, I can't remember it exactly), so I decided to use more that one instance of the data sources and using just one global version so that it can be used as field type in certain cases.

        My whole store might be sort of messy, but the general message is that SmartClient is great, but because some things don't work out, I decide to create "work-arounds". And from one thing, this leads to another. So basically, I'm quite unsure at the moment if I'm doing it the right way.
        Last edited by wallytax; 9 Jun 2016, 23:13.

        Comment


          #5
          By the way, the reason I'm overruling RestDataSource is to create a data source that fits RubyOnRails better (I've read the WIKI pages about integration with Rails, but I wasn't satisfied with the solution). Rails knows about these URLs:
          • GET /customers.json (to retrieve a list of customers)
          • GET /customers/1.json (to retrieve a single customer); thus not GET /customers.json?id=1
          • POST /customers.json (to add a single customer)
          • PUT /customers/1.json (to update a single customer)
          • DELETE /customers/1.json (to delete a single customer)
          I'm just mentioning this as a litte background of why I extended RestDataSource and use that "_id" property in the request.

          Again, if I'm doing it (completely) wrong, please let me know, but please with some background.

          Comment


            #6
            Fetching just some fields is a common thing, that's why we have dsRequest.outputs for doing that, as well as a shortcut property on ComboBoxItem/SelectItem: fetchDisplayedFieldsOnly (so setting optionFilterContext.outputs isn't really needed).

            TreeGrids don't set an operationId on the request unless you've set treeGrid.fetchOperation.

            Overall, we're not sure where your confusion is. There are a few straightforward ways to set dsRequest.outputs - the requestProperties argument to fetchData() is one way. You can also implement a transformRequest that adds the dsRequest.outputs you want based on the operationId, and then for any component where you want that same set of outputs, use that operationId.

            Comment


              #7
              Thanks for the answer. I've seen that fetchDisplayedFieldsOnly before and there is an issue with it. The issue (in short) is that although optionFilterContext.outputs is set, it also changes the list of fields of the pick list itself. That seems be invalid. If that can be fixed (if you agree with my assumption), that would be very helpful.

              Comment


                #8
                This line of code in the source of PickList should probably be changed:

                Code:
                var fields = this.pickListFields || [];
                Changing the fields later in the code, also changes this.pickListFields. Building a new array from scratch is probably better.

                Comment


                  #9
                  As stated in the thread that you pointed out (issue), the changes in pickList should have no impact, and no test case has been provided that demonstrates any problem there.
                  So if you can provide a test case where this issue causes any problem, please provide it and we will try to fix it.

                  Comment


                    #10
                    Just found out that this seems to be addressed and fixed! Just writing this to inform others. I've noticed the duplicate() call in the code region I wrote about in an earlier post.

                    Comment

                    Working...
                    X