Announcement

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

    ValueIcons for listgrid fields with SelectItem type and optionDatasource

    Hey guys,

    I am currently working on an optionDatasource for a listgrid field. The listgrid field is of type “SelectItem” and should also show valueIcons. The datasource works fine, but I have some Issues getting valueIcons to work.
    To do so I’ve overridden the getValueIcon method for the listgrid field. In this function the given value gets wrapped by imageURLPrefix and imageURLSuffix and is getting returned. If the value is undefined or null it will return null for not printing an icon.
    Code:
    getValueIcon : function (value) {
    	if (typeof(value) == "undefined" || value == null) {
    		return null;
    	}
    	return this.imageURLPrefix + value + this.imageURLSuffix;
    }
    This works for all elements inside the list but not for the selected object, which will have the imageURLSuffix twice (e.g. “US.png.png”) and thus it won’t show an icon (only US.png exists).
    Did I implement getValueIcon the wrong way or is this an issue of yours?

    Another issue appears when setting data to the list grid. When setting the value of entries (e. g. US) the listgrid will only show these values instead of the displayValue (e. g. USA) and also won’t show any icon. When setting the displayValue (which feels wrong) the correct name will be shown and also no icon. When starting to edit a record the select item appears and correctly shows the displayValue for the given value and without the first issue mentioned above the icon would show. For the set displayValue this won’t work anymore. The displayValue will stay as selected object, but the dataSource won’t find an entry with the displayValue as value and thus the select item will try to get the icon for the set displayValue (e. g. USA.png instead of US.png).
    How do I make the listGrid resolve values with the dataSource for getting the displayValue?
    Or am I going down the wrong road?


    You can see the values shown by the listgrid (US, DE & CU) instead of its displayValues (USA, Deutschland & Kuba) and without its icons. when clicking on a cell, the record will start editing and the select item will resolve the data for given value. You can’t see values for the selected objects because of the first issue mentioned. When opening the list everything is fine, but after end editing the displayValue is lost again.

    Code for reproducing the issues:
    Code:
    countryData = [{
    		"Code" : "DE",
    		"countryName" : "Deutschland"
    	}, {
    		"Code" : "IR",
    		"countryName" : "Iran, Islamische Republik"
    	}, {
    		"Code" : "IS",
    		"countryName" : "Island"
    	}, {
    		"Code" : "IL",
    		"countryName" : "Israel"
    	}, {
    		"Code" : "IT",
    		"countryName" : "Italien"
    	}, {
    		"Code" : "IT",
    		"countryName" : "Italien - Mailand"
    	}, {
    		"Code" : "IT",
    		"countryName" : "Italien - Rom"
    	}, {
    		"Code" : "JP",
    		"countryName" : "Japan"
    	}, {
    		"Code" : "JP",
    		"countryName" : "Japan - Tokio"
    	}, {
    		"Code" : "CM",
    		"countryName" : "Kamerun"
    	}, {
    		"Code" : "KZ",
    		"countryName" : "Kasachstan"
    	}, {
    		"Code" : "CO",
    		"countryName" : "Kolumbien"
    	}, {
    		"Code" : "KP",
    		"countryName" : "Korea, Demokr. Volksrep."
    	}, {
    		"Code" : "HR",
    		"countryName" : "Kroatien"
    	}, {
    		"Code" : "CU",
    		"countryName" : "Kuba"
    	}, {
    		"Code" : "LS",
    		"countryName" : "Lesotho"
    	}, {
    		"Code" : "LV",
    		"countryName" : "Lettland"
    	}, {
    		"Code" : "LT",
    		"countryName" : "Litauen"
    	}, {
    		"Code" : "MW",
    		"countryName" : "Malawi"
    	}, {
    		"Code" : "ML",
    		"countryName" : "Malediven"
    	}, {
    		"Code" : "MA",
    		"countryName" : "Marokko"
    	}, {
    		"Code" : "US",
    		"countryName" : "USA"
    	}
    ];
    isc.ListGrid.create({
    	ID : "countryList",
    	width : 500,
    	height : 224,
    	alternateRecordStyles : true,
    	showAllRecords : true,
    	canEdit : true,
    	editEvent : "click",
    	fields : [{
    			name : "countryField",
    			title : "Country",
    			canEdit : true,
    			editorType : "SelectItem",
    			imageURLPrefix : "https:\/\/www.cyon.ch\/img\/icons\/flags\/flags-iso\/shiny\/16\/",
    			imageURLSuffix : ".png",
    			editorProperties : {
    				ID : "dayCountryGridField_43Editor",
    				displayField : "countryName",
    				valueField : "Code",
    				getValueIcon : function (value) {
    					if (typeof(value) == "undefined" || value == null) {
    						return null
    					}
    					return this.imageURLPrefix + value + this.imageURLSuffix
    				},
    				optionDataSource : isc.DataSource.create({
    					dataFormat : "json",
    					ID : "countryDS",
    					clientOnly : true,
    					testData : countryData
    				}),
    				textMatchStyle : "substring",
    				loadingDisplayValue : null,
    			}
    		}
    	],
    	data :
    	[{
    			countryField : "US"
    		}, {
    			countryField : "DE"
    		}
    	],
    	autoFetchData : true
    })
    Best Regards

    #2
    Thanks for the test case. This is assigned to one of our developers for investigation.

    Regards
    Isomorphic Software

    Comment


      #3
      Your application code should not need to include the imageURLPrefix / suffix directly -- instead your getValueIcon function should return just the value and the prefix and suffix should be automatically prepended and appended...
      Code:
                                       getValueIcon : function (value) {
                                              if (typeof(value) == "undefined" || value == null) {
                                                     return null
                                              }
                                              return value;
                                       }
      Doing this will get your icon working in the "text box" part of the editor, but the icons are now failing to have the proper prefix/suffix applied in the pickList. We're looking into why this is happening, but you can workaround the problem by explicitly applying the imageURLPrefix and suffix to the column in the pickList using the pickListFields property, like this:
      Code:
          ... other sample code unchanged...     
          fields : [{
                  name : "countryField",
                  title : "Country",
                  canEdit : true,
                  editorType : "SelectItem",
                  imageURLPrefix : "https:\/\/www.cyon.ch\/img\/icons\/flags\/flags-iso\/shiny\/16\/",
                  imageURLSuffix : ".png",
                  editorProperties : {
                      ID : "dayCountryGridField_43Editor",
                      displayField : "countryName",
                      valueField : "Code",
                      pickListFields:[{name:"countryName",
                              imageURLPrefix : "https:\/\/www.cyon.ch\/img\/icons\/flags\/flags-iso\/shiny\/16\/",
                               imageURLSuffix : ".png"
                      }],
                      getValueIcon : function (value) {
                          if (typeof(value) == "undefined" || value == null) {
                              return null
                          }
                          return value;
                      },
                      optionDataSource : isc.DataSource.create({
                          dataFormat : "json",
                          ID : "countryDS",
                          clientOnly : true,
                          testData : countryData
                      }),
                      textMatchStyle : "substring",
                      loadingDisplayValue : null,
                  }
              }
          ],
      Regards

      Isomorphic Software

      Comment


        #4
        A quick follow-up on this: We've now also made a change to the framework to ensure the imageURLPrefix / suffix get applied to the auto-generated pick-list field in cases like this going forward, so you shouldn't need to explicitly apply them.
        This change will be in nightly builds on the 10.0p / 10.1d branches from Sep 10 on.

        Regards
        Isomorphic Software

        Comment


          #5
          Hey guys,
          thank you for your fast fix.
          The datasource now works fine for SelectItems.
          When using a ListGridField with SelectItem type an issue mentioned above still exists. Setting a value as selected object to such a listgrid field will show the value instead of the display value when the listgrid is not in editor mode. Entering editor mode will cause the datasource to fetch this record and will result in displaying the display value with its icon. Like in editor mode the display value with icon also should be visible before and after exiting editor mode.


          My example for reproducing the issues:
          Code:
            countryData = [{
                    "Code" : "DE",
                    "countryName" : "Deutschland"
                }, {
                    "Code" : "IR",
                    "countryName" : "Iran, Islamische Republik"
                }, {
                    "Code" : "IS",
                    "countryName" : "Island"
                }, {
                    "Code" : "IL",
                    "countryName" : "Israel"
                }, {
                    "Code" : "IT",
                    "countryName" : "Italien"
                }, {
                    "Code" : "JP",
                    "countryName" : "Japan"
                }, {
                    "Code" : "CM",
                    "countryName" : "Kamerun"
                }, {
                    "Code" : "KZ",
                    "countryName" : "Kasachstan"
                }, {
                    "Code" : "CO",
                    "countryName" : "Kolumbien"
                }, {
                    "Code" : "KP",
                    "countryName" : "Korea, Demokr. Volksrep."
                }, {
                    "Code" : "HR",
                    "countryName" : "Kroatien"
                }, {
                    "Code" : "CU",
                    "countryName" : "Kuba"
                }, {
                    "Code" : "LS",
                    "countryName" : "Lesotho"
                }, {
                    "Code" : "LV",
                    "countryName" : "Lettland"
                }, {
                    "Code" : "LT",
                    "countryName" : "Litauen"
                }, {
                    "Code" : "MW",
                    "countryName" : "Malawi"
                }, {
                    "Code" : "ML",
                    "countryName" : "Malediven"
                }, {
                    "Code" : "MA",
                    "countryName" : "Marokko"
                }, {
                    "Code" : "US",
                    "countryName" : "USA"
                }
            ];
            isc.ListGrid.create({
                ID : "countryList",
                width : 500,
                height : 224,
                alternateRecordStyles : true,
                showAllRecords : true,
                canEdit : true,
                editEvent : "click",
                fields : [{
                        name : "countryField",
                        title : "Country",
                        canEdit : true,
                        editorType : "SelectItem",
                        imageURLPrefix : "https:\/\/www.cyon.ch\/img\/icons\/flags\/flags-iso\/shiny\/16\/",
                        imageURLSuffix : ".png",
                        editorProperties : {
                            ID: "dayCountryGridField_43Editor",
                            displayField : "countryName",
                            valueField : "Code",
                            getValueIcon : function (value) {
                                if (typeof(value) == "undefined" || value == null) {
                                    return null
                                }
                                return value
                            },
                            optionDataSource : isc.DataSource.create({
                                dataFormat : "json",
                                ID : "countryDS",
                                clientOnly : true,
                                testData : countryData
                            }),
                            textMatchStyle : "substring",
                            loadingDisplayValue : null,
                        }
                    }
                ],
                data:
                [{
                        countryField: "US"
                    }, {
                        countryField: "IT"
                    }
                ],
                autoFetchData : true
            })
          Best Regards

          Comment


            #6
            You need to make 2 changes:
            1) Move the optionDataSource and displayField / valueField specification out of the editorProperties block and onto the field definition itself (they will still be passed through to the editor when in edit mode)
            2) Add a 'getValueIcon' implementation at the grid level

            Something like this:
            Code:
              isc.ListGrid.create({
                 // various properties...
                 ...
                  getValueIcon : function (field, value, record, rowNum) {
                    if (field.name == "countryField" && value != null) return value;
                    return this.Super("getValueIcon", arguments);
                  },
                  fields : [{
                          name : "countryField",
                          title : "Country",
                          canEdit : true,
                          editorType : "SelectItem",
                          imageURLPrefix : "https:\/\/www.cyon.ch\/img\/icons\/flags\/flags-iso\/shiny\/16\/",
                          imageURLSuffix : ".png",
                          displayField : "countryName",
                          valueField : "Code",
                          optionDataSource : isc.DataSource.create({
                              dataFormat : "json",
                              ID : "countryDS",
                              clientOnly : true,
                              testData : countryData
                          }),
                          editorProperties : {
                              ID: "dayCountryGridField_43Editor",
                              getValueIcon : function (value) {
                                  if (typeof(value) == "undefined" || value == null) {
                                      return null
                                  }
                                  return value
                              },
                              textMatchStyle : "substring",
                              loadingDisplayValue : null,
                          }
                      }
                  ]
            });
            Regards
            Isomorphic Software

            Comment


              #7
              Hey guys,
              thanks for yor your example code, works fine for my example.
              But in my example I was wrong taking the icon shortcuts as value, because they can appear several times for different records. When selecting a value which appears more than once this implies that the SelectItem wont be able to distinguish which of these is selected.
              So I have to use my countryName as value (and displayValue) and I am forced to give my records another attribute for holding the icon information (“icon” in this case).
              To get the records icon I adjusted the getValueIcon function like that:
              Code:
                getValueIcon : function (value) {
                    if (typeof(value) == "undefined" || value == null) {
                        return null
                    }
                    var record = this.optionDataSource.getCacheData().find("countryName", value);
                    if (record == null) {
                        return null
                    } else {
                        return record.icon
                    };
                }
              Doing so will work for all records which are present in cacheData (in my application this is only the selectedObject). For all uncached records I’m not able to find its appropriate record like that. Also I didn’t find an alternative for getting the record with the given value.
              Is there an API for receiving a record for a given value?
              Or is there an alternative for solving the issue when the records icon name isn’t equal to the its value?
              This seems to be a usual case when thinking of a list of persons with an icon for men and one for women (etc.). In cases like that you’ll always have multiple records in the valuemap with the same icon.
              The best solution for me in this case would be to either get the record itself as additional input of the getValueIcon method like getValueIcon(value, record) or be able to set an “iconField” for FormItems which would cause the FormItem to pass the right value to the getValueIcon(value) method.
              My adjusted example (dataSource stayed the same)
              Code:
                isc.ListGrid.create({
                    ID : "countryList",
                    width : 500,
                    height : 224,
                    alternateRecordStyles : true,
                    showAllRecords : true,
                    canEdit : true,
                    editEvent : "click",
                    getValueIcon : function (field, value, record, rowNum) {
                        if (field.name == "countryField" && value != null) {
                            var record = field.optionDataSource.getCacheData().find("countryName", value);
                            if (record == null) {
                                return null
                            } else {
                                return record.icon
                            }
                        } else {
                            return this.Super("getValueIcon", arguments)
                        }
                    },
                    fields : [{
                            name : "countryField",
                            title : "Country",
                            canEdit : true,
                            editorType : "SelectItem",
                            imageURLPrefix : "https:\/\/www.cyon.ch\/img\/icons\/flags\/flags-iso\/shiny\/16\/",
                            imageURLSuffix : ".png",
                            valueField : "countryName",
                            optionDataSource : isc.DataSource.create({
                                dataFormat : "json",
                                ID : "countryDS",
                                clientOnly : true,
                                testData : countryData
                            }),
                            editorProperties : {
                                ID : "dayCountryGridField_43Editor",
                                textMatchStyle : "substring",
                                loadingDisplayValue : null,
                                getValueIcon : function (value) {
                                    if (typeof(value) == "undefined" || value == null) {
                                        return null
                                    }
                                    var record = this.optionDataSource.getCacheData().find("countryName", value);
                                    if (record == null) {
                                        return null
                                    } else {
                                        return record.icon
                                    };
                                },
                                pickListFields :
                                [{
                                        "name" : "iconField",
                                        "type" : "text",
                                        "canEdit" : false,
                                        "canSort" : false,
                                        "showIf" : function () {
                                            return false
                                        }
                                    }, {
                                        "name" : "countryName",
                                        "type" : "text",
                                        "canEdit" : false,
                                        "canSort" : false
                                    }
                                ]
                            }
                        }
                    ],
                    data :
                    [{
                            countryField : "Marokko"
                        }, {
                            countryField : "USA"
                        }
                    ],
                    autoFetchData : true
                })
              Best Regards

              Comment


                #8
                We're not sure what your exact use case is at a high level, however in broad strokes here are some options:

                - if we're talking about a reasonably limited number of valueIcons, you can simply set the 'valueIcons' map on your field. This could be done statically [a hardcoded map], or you could set this map up dynamically in your application code
                - if we're talking about a bigger list of options, you probably want to make use of an optionDataSource / foreignKey type relationship.
                Take a look at the documentation for "dataSourceField.displayField" and "dataSourceField.includeFrom".
                In short this gives you a way to have a dataSource pick up a value for one of its fields from another DataSource, based on a foreignKey type lookup. [So if you had a "main" DataSource including a field for a unique "zipcode", it could pick up a separate "state" field value by looking it up from another DS, and the field value would be available on the record fetched from the "main" dataSource].

                Once you have the field value available [in our example a URL for an image], you can simply look at the record[fieldName] value directly in your getValueIcon function. For the ListGrid this is trivial - for the SelectItem you can use getSelectedRecord().

                You shouldn't need to be reaching into the cache data of the DS directly as you are attempting to do.


                If this doesn't give you enough to get things working, perhaps you could describe at a high level your actual use case. In other words - what UI are you actually building / what data structures are you working with / how is the data stored in terms of separate tables on the Server, etc.

                Regards
                Isomorphic Software

                Comment


                  #9
                  Hey guys,
                  sorry, I think I was too focused on my issue, such that I missed to give you an overview of my purpose.
                  My overall aim is to speed up a view of mine.

                  This view includes a ListGrid with a SelectItem typed ListGridField for choosing a country and several other ListGridFields. When the view is built the ListGrid is filled with all records and the saved country is set as selecteObject. This works fine and doesn’t take a long time. But filling the countries ListGridField currently takes too much time (countries getting selected and valueMap as well as valueIcons have to be built up). This can and should be done by an optionDataSource to reach a fast build up for this view.

                  Selecting and fetching these records with the optionDataSource works fine without icons. To include valueIcons I’m submitting both the value and the icon shortcut for each record. So my optionDataScource can deliver everything I need to display and there should be no need for a second datasource.
                  So far so good.

                  The problem for me now is, to tell my SelectItem and ListGrid how to get the valueIcons. For creating the right icon path these components may not use the value but the icon shortcut and I need to make them able to do so.

                  My approach to reach this behavior was to override the getValueIcon(value) method. The problem here is, I only got the value of the record and I can’t see a way to get the icon shortcut of the related record.

                  So in this case the easiest way to solve this would be to determine a valueField (in my earlier example it’s the “Code” field). Like that your system would be able to distinguish which value should be displayed and which can be used for creating the icon path.

                  Another option would be an API for using inside the getValueIcon method. This API should return a record for a given value. When getting the record I am also able to get the icon shortcut and thus can return the icon shortcut in the getValueIcon method.

                  If you still got questions just ask me again.
                  Thanks so far.

                  Best Regards

                  Comment


                    #10
                    We don't have an exact equivalent for "optionDataSource" / "displayField" / "valueField" for valueIcons built in.
                    That's not something that has been requested so we don't have any immediate plans to add such a feature, though we will have the development team consider whether such a feature might make sense at some point in the future.

                    There are a few options - the best one for you to use would depend on your exact use case - how your data is stored and retrieved / how big the set of possible options is, etc.

                    - You can set field.valueIcons to a mapping from all possible values to URLs. As we said before this could be done statically by being hardcoded into your source, or it could be assembled dynamically.
                    If the set of possible options is stored on the server, you'll probably need a one-time fetch to retrieve the options and build the map.
                    As described here, this is actually how the standard listGridField.optionDataSource sets up the set of possible display-field values.

                    - You could modify the data displayed in your ListGrid to include a value for an extra icon field as part of its data.
                    In your sample code, the data is being created on the client side [hardcoded into your source].
                    If in your real usage this is coming from the server, you change the ListGrid to be bound to a dataSource and issue a fetch request for the data rather than having the "data" attribute set to an array.
                    The 'icon' field can be populated by custom server-side logic, or for a SQL dataSource, you could make use of the  'includeFrom' feature.

                    If the record is being created and applied on the client, and doesn't lend itself to data binding, you can presumably still modify the record to include an extra field value for this icon field.
                    How you get the appropriate icon string for each record would again depend on your design, but you could issue either a queued series of fetches to pick up values for each option (would be a single client-server turnaround containing multiple fetch requests), or perhaps use AdvancedCriteria to request only the values you know you need.

                    Your actual 'getValueIcon()' implemenation would of course need to look at record.icon which would now be populated.

                    The other wrinkle would be editing - when the user changes the value of the field, if you aren't using a 'valueIcons' map you may need to modify the "icon" property of the record. This could be achieved via (say) a 'setEditValue(...)' call, using a notificaiton method such as field.cellChanged or editorExit().

                    Hopefully this gives you enough to get things working.

                    Regards
                    Isomorphic Software

                    Comment

                    Working...
                    X