Announcement

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

    HowTo: 5.1p ComboBoxItem with PickList ListGrid with buttons?

    Hi Isomorphic,

    I'm developing a search window for my application that lets the user search though all records.
    In the end, the user will want to do something with a found record.
    Is it somehow possible to have anything from this sample in the PickList shown for a ComboBoxItem?

    I know about ComboBoxItem.setPickListProperties() and the general restriction that this wont allow me to feed a ListGrid with @overrides, making RecordComponents impossible (do you have this doc'd somewhere? I just remember this from a forums post).
    But anything like it? A column with a button that reacts on click would be fine. Otherwise I'll only have the change handler of the ComboBoxItem, making only 1 action possible
    With buttons + click handlers I'd have different actions for different buttons.

    Thank you & Best regards
    Blama

    #2
    You don't need buttons for multiple actions. Just add a click handler that looks at what column was hit.

    In theory, the AutoChild system allows you to replace the pickListConstructor with a custom class and use the recordComponents subsystem. However, we wouldn't recommend trying this - the pickList has a lot of complex stuff going on with auto-sizing, modality, keyboard focus, accessibility support, as well as handling asynchronous data arrival, and a bunch of complicated browser workarounds in play as well. This is not a good place to try out deep AutoChild surgery. In addition, future features of the PickList are likely to use the recordComponents system as well, clashing with your usage.

    A safer approach would be to either:
    1. use a formatter to render something that looks like a link or button
    2. use record.embeddedComponent with an optionDataSource to return actual components without getting into the recordComponent system as such. This will work for small numbers of records

    Comment


      #3
      Hi Isomorphic,

      thank you for the hint. addCellClickHandler() for my setPickListProperties()-ListGrid works as expected, but there are UI improvements possible, where I don't know how to do them.
      The use case is a search ComboBoxItem where I don't care for the selected value - in fact I only want the clicks on my action ListGridFields (with type e.g. actionHistoryField.setType(ListGridFieldType.IMAGE)) to have an effect.

      1) Currently, if I click another column, this gets registered as "selection" and the value of the ComboBoxItem changes. Is it possible to suppress this, so that only the clicks on my action icons have an effect?
      event.cancel in the addCellClickHandler() does not stop the selection in the ComboBoxItem.

      2) In my CellClickHandler I can only use hardcoded comparisons to event.getColNum(). SearchListGrid.this.getFields() returns an empty array, likewise SearchListGrid.this.getField(event.getColNum()) returns null. Is this correct?

      3) I'm not perfectly happy with the design of the pickList-ListGrid with header. I'm using 5.1p with Simplicity, but you can also see my issue in this 6.0 Enterprise skin sample:
      Click image for larger version

Name:	Border missing.PNG
Views:	459
Size:	11.3 KB
ID:	237966

      You can see the border ".pickListMenuBody { border: 1px solid #8fa7c7 }" around the ListGrid content. I'd like the border to be around the whole ListGrid.
      The whole ListGrid has this css class without any rules: "scrollingMenu".

      This worked for me as addition at the end of my css file, but I don't know if it is supported usage:
      Code:
      /* Move the border from PickLists with headers from data-border to header+data-border */
      .scrollingMenu {
          border: 1px solid #000;
      }
      
      .pickListMenuBody {
          border: none;
      }
      Also, in a perfect world I would change this only for my SearchComboBox (which really is more a custom control based on ComboBoxItem) and set border thickness to 2 or 3, which looks ugly for normal PickLists.
      I saw ComboBoxItem.setPickListConstructor() and think it is possible to change the 2nd rule only for this ComboBoxItem using a PickListMenu with different setBodyStyleName().
      But how to customize the "scrollingMenu"-class? Is this possible?

      Thank you & Best regards
      Blama

      Comment


        #4
        The ComboBoxItem is a control that allows searching a set of options and selecting one - if you want to completely turn off the ability to select things, what part of the ComboBox are you actually using here? Just search? Starting with ComboBoxItem might not be the best approach giving that your usage is so very different from the primary purpose of a combobox. You could instead just float a ListGrid or other component underneath a TextItem.

        As far as your questions:
        1. the listGrid setting selectionType can turn off selection, but this is so odd in a ComboBox (as previously mentioned) that this may not be enough - you might need styling overrides to just turn off the styling instead

        2. why would you manually traverse the field name array when there is a getField() accessor?

        3. you could do this, or just use the usual styling properties on ListGrid via pickListProperties, to avoid styling other instances

        Comment


          #5
          Hi Isomorphic,

          yes, I'm using just search (+ the click handler on the pickList for actions).
          In retroperspective, using a TextItem + free floating ListGrid might have been the better choice, but as it is working, I'll stay with it for now.

          1) I'll try a different setting for selectionType.

          2) Sorry for not being clearer. I tried that one before and it returns null. The reason for that is that getFields() is empty.

          3) I'll try that.

          Best regards
          Blama

          Comment


            #6
            2) this doesn't make much sense, as obviously there are fields.. can you show code that reproduces this issue?

            Comment


              #7
              Hi Isomorphic,

              the testcase for 2) using is v10.1p_2016-05-07 is:

              BuiltInDS.java:
              Code:
              package com.smartgwt.sample.client;
              
              import com.google.gwt.core.client.EntryPoint;
              import com.smartgwt.client.Version;
              import com.smartgwt.client.core.KeyIdentifier;
              import com.smartgwt.client.util.Page;
              import com.smartgwt.client.util.PageKeyHandler;
              import com.smartgwt.client.util.SC;
              import com.smartgwt.client.widgets.IButton;
              import com.smartgwt.client.widgets.Window;
              import com.smartgwt.client.widgets.events.ClickEvent;
              import com.smartgwt.client.widgets.events.ClickHandler;
              import com.smartgwt.client.widgets.layout.VLayout;
              
              public class BuiltInDS implements EntryPoint {
                  private VLayout mainLayout;
                  private IButton recreateBtn;
              
                  public void onModuleLoad() {
                      KeyIdentifier debugKey = new KeyIdentifier();
                      debugKey.setCtrlKey(true);
                      debugKey.setKeyName("D");
              
                      Page.registerKey(debugKey, new PageKeyHandler() {
                          public void execute(String keyName) {
                              SC.showConsole();
                          }
                      });
              
                      mainLayout = new VLayout(20);
                      mainLayout.setWidth100();
                      mainLayout.setHeight100();
              
                      recreateBtn = new IButton("Recreate");
                      recreateBtn.addClickHandler(new ClickHandler() {
                          @Override
                          public void onClick(ClickEvent event) {
                              recreate();
                          }
                      });
                      mainLayout.addMember(recreateBtn);
                      recreate();
                      mainLayout.draw();
                  }
              
                  private void recreate() {
                      Window w = new Window();
                      w.setWidth("95%");
                      w.setHeight("95%");
                      w.setMembersMargin(0);
                      w.setModalMaskOpacity(70);
                      w.setTitle(" (" + Version.getVersion() + "/" + Version.getSCVersionNumber() + ")");
                      w.setTitle("" + w.getTitle());
                      w.setShowMinimizeButton(false);
                      w.setIsModal(true);
                      w.setShowModalMask(true);
                      w.centerInPage();
              
                      w.addItem(new SearchComboForm());
                      w.show();
                  }
              }
              SearchComboForm.java:
              Code:
              package com.smartgwt.sample.client;
              
              import com.smartgwt.client.data.AdvancedCriteria;
              import com.smartgwt.client.data.Criteria;
              import com.smartgwt.client.data.Criterion;
              import com.smartgwt.client.data.DataSource;
              import com.smartgwt.client.types.Alignment;
              import com.smartgwt.client.types.AutoFitWidthApproach;
              import com.smartgwt.client.types.ListGridFieldType;
              import com.smartgwt.client.types.OperatorId;
              import com.smartgwt.client.util.SC;
              import com.smartgwt.client.widgets.form.DynamicForm;
              import com.smartgwt.client.widgets.form.fields.ComboBoxItem;
              import com.smartgwt.client.widgets.form.fields.FormItemCriteriaFunction;
              import com.smartgwt.client.widgets.form.fields.FormItemFunctionContext;
              import com.smartgwt.client.widgets.form.fields.events.EditorExitEvent;
              import com.smartgwt.client.widgets.form.fields.events.EditorExitHandler;
              import com.smartgwt.client.widgets.grid.ListGrid;
              import com.smartgwt.client.widgets.grid.ListGridField;
              import com.smartgwt.client.widgets.grid.events.CellClickEvent;
              import com.smartgwt.client.widgets.grid.events.CellClickHandler;
              
              public class SearchComboForm extends DynamicForm {
                  public SearchComboForm() {
                      setWidth(550);
              
                      SearchComboBoxItem searchComboBoxItem = new SearchComboBoxItem();
                      searchComboBoxItem.setWrapTitle(false);
                      setItems(searchComboBoxItem);
                  }
              
                  private class SearchComboBoxItem extends ComboBoxItem {
                      public SearchComboBoxItem() {
                          SearchListGrid searchListGrid = new SearchListGrid();
                          setPickListProperties(searchListGrid);
                          setPickListHeaderHeight(35);
                          setOptionDataSource(DataSource.get("employees"));
              
                          ListGridField employeeId = new ListGridField("EmployeeId");
                          employeeId.setHidden(true);
                          employeeId.setCanHide(false);
                          ListGridField name = new ListGridField("Name");
                          ListGridField gender = new ListGridField("Gender");
                          ListGridField salary = new ListGridField("Salary");
                          ListGridField reportsTo = new ListGridField("ReportsTo");
                          ListGridField job = new ListGridField("Job");
                          ListGridField maritalStatus = new ListGridField("MaritalStatus");
              
                          ListGridField actionHistoryField = new ListGridField("ACTIONHISTORY");
                          actionHistoryField.setAlign(Alignment.CENTER);
                          actionHistoryField.setType(ListGridFieldType.IMAGE);
                          actionHistoryField.setImageURLPrefix("[SKINIMG]silk/");
                          actionHistoryField.setImageURLSuffix(".png");
                          actionHistoryField.setCanHide(false);
              
                          ListGridField actionEditField = new ListGridField("ACTIONEDIT");
                          actionEditField.setAlign(Alignment.CENTER);
                          actionEditField.setType(ListGridFieldType.IMAGE);
                          actionEditField.setImageURLPrefix("[SKINIMG]silk/");
                          actionEditField.setImageURLSuffix(".png");
                          actionEditField.setCanHide(false);
              
                          setPickListFields(actionHistoryField, actionEditField, employeeId, name, gender, salary, reportsTo, job, maritalStatus);
                          setPickListWidth(700);
                          setWidth(200);
                          setShowPickerIcon(false);
                          setTextBoxStyle("textItem");
                          setMinimumSearchLength(3);
                          setHint("Search");
                          setShowHintInField(true);
                          setShowTitle(false);
              
                          setPickListFilterCriteriaFunction(new FormItemCriteriaFunction() {
                              @Override
                              public Criteria getCriteria(FormItemFunctionContext itemContext) {
                                  if (itemContext.getFormItem().getValue() != null) {
                                      AdvancedCriteria containInputsAC = new AdvancedCriteria();
                                      containInputsAC.setOperator(OperatorId.AND);
              
                                      // trim keyword inputs to keyword list
                                      String userInput = itemContext.getFormItem().getValue().toString();
                                      String[] userInputList = userInput.split("\\s+");
              
                                      for (String inputKeyword : userInputList) {
                                          Criterion nameContainsCriterion = new Criterion("Name", OperatorId.ICONTAINS, inputKeyword);
                                          Criterion jobStartsWithCrit = new Criterion("Job", OperatorId.ISTARTS_WITH, inputKeyword);
                                          Criterion msStartsWithCrit = new Criterion("MaritalStatus", OperatorId.ISTARTS_WITH, inputKeyword);
                                          AdvancedCriteria containKeywordAC = new AdvancedCriteria();
                                          containKeywordAC.buildCriterionFromList(OperatorId.OR, new Criterion[] { nameContainsCriterion, jobStartsWithCrit,
                                                  msStartsWithCrit });
              
                                          containInputsAC.appendToCriterionList(containKeywordAC);
                                      }
                                      return containInputsAC;
                                  } else
                                      return null;
                              }
                          });
              
                          addEditorExitHandler(new EditorExitHandler() {
                              @Override
                              public void onEditorExit(EditorExitEvent event) {
                                  clearValue();
                              }
                          });
                      }
              
                      private class SearchListGrid extends ListGrid {
                          public SearchListGrid() {
                              setAutoFitFieldsFillViewport(true);
                              setShowClippedValuesOnHover(true);
                              setAutoFitWidthApproach(AutoFitWidthApproach.BOTH);
                              setCanGroupBy(false);
                              setCanMultiGroup(false);
                              setCanMultiSort(false);
                              setCanReorderFields(false);
                              setCanEdit(false);
                              setShowFilterEditor(false);
                              setCanFreezeFields(false);
                              setCellHeight(30);
                              setFixedRecordHeights(true);
              
                              addCellClickHandler(new CellClickHandler() {
                                  @Override
                                  public void onCellClick(CellClickEvent event) {
                                      int colNum = event.getColNum();// --> Action 1 or Action 2
                                      ListGridField clicked = SearchListGrid.this.getField(colNum);
                                      SC.logWarn("Clicked field: " + (clicked != null ? clicked.getName() : "is null"));
              
                                      ListGridField name = SearchListGrid.this.getField("Name");
                                      SC.logWarn("Test \"Name\": " + (name != null ? name.getName() : "is null"));
                                  }
                              });
                          }
                      }
                  }
              }
              This closely resembles my application setup. When search for a name and click it, you'll get this log:
              Code:
              [ERROR] [builtinds] - 11:19:03.078:MUP2:WARN:Log:Clicked field: is null
              [ERROR] [builtinds] - 11:19:04.350:MUP2:WARN:Log:Test "Name": is null
              Best regards
              Blama

              Comment


                #8
                You've made a scoping error here: "SearchListGrid.this" is going to be the properties you passed to setPickListProperties(), not the actual PickListMenu instance.

                One way to fix your code would be to set a custom pickListConstructor so that the created pickList is actually an instance of your SearchListGrid class.

                Another would be to keep the code as is, but use EventHandler.getTarget() to get to the GridBody instance that was hit.
                Last edited by Isomorphic; 20 May 2016, 07:28.

                Comment


                  #9
                  Hi Isomorphic,

                  thank you. It seems that the method is not exposed in CellClickEvent in SmartGWT 5.1.

                  Best regards
                  Blama

                  Comment


                    #10
                    ?

                    What method are you referring to? EventHandler.getTarget() is a static API, it's not on CellClickEvent.

                    Comment


                      #11
                      Hi Isomorphic,

                      sorry, I missed that. I tried to cast / convert to listGrid, but were not successful.
                      I used this code to test:
                      Code:
                                              Object o = EventHandler.getTarget();
                                              ListGrid lg = null;
                                              try {
                                                  lg = (ListGrid) EventHandler.getTarget();
                                              } catch (Exception e) {
                                                  SC.logWarn("Could not cast click target to ListGrid");
                                              }
                      
                                              try {
                                                  lg = new ListGrid(EventHandler.getTarget().getJsObj());
                                              } catch (Exception e) {
                                                  SC.logWarn("Could not cast click target to ListGrid");
                                              }
                      
                                              PickListMenu plm = null;
                                              try {
                                                  plm = (PickListMenu) EventHandler.getTarget();
                                              } catch (Exception e) {
                                                  SC.logWarn("Could not cast click target to PickListMenu");
                                              }
                      
                                              try {
                                                  plm = new PickListMenu(EventHandler.getTarget().getJsObj());
                                              } catch (Exception e) {
                                                  SC.logWarn("Could not cast click target to PickListMenu");
                                              }
                      This seems not to be correct. I tried this because in Eclipse Dev Mode the EventHandler.getTarget() looks like this:
                      Code:
                      GridBody{ID: "isc_PickListMenu_0_body",
                      creator: [PickListMenu ID:isc_PickListMenu_0],
                      grid: [PickListMenu ID:isc_PickListMenu_0],
                      fields: Array[13],
                      styleName: "pickListMenuBody",
                      alternateRowStyles: true,
                      dragTarget: [PickListMenu ID:isc_PickListMenu_0],
                      dragAppearance: "none",
                      screenReaderCellSeparator: "/",
                      screenReaderRowSeparator: ",",
                      locatorParent: [PickListMenu ID:isc_PickListMenu_0],
                      selectionAppearance: "rowStyle",
                      selectionType: "single",
                      cellHeight: 30,
                      autoFitMaxRecords: 50,
                      autoFitMaxColumns: 50,
                      allowRowSpanning: false,
                      scrollWheelRedrawDelay: 250,
                      printMaxRows: 100,
                      fastCellUpdates: false,
                      showRollOver: true,
                      showClippedValuesOnHover: true,
                      hoverDelay: 500,
                      hoverStyle: "gridHover",
                      cellHoverOutset: 5,
                      showEmptyMessage: true,
                      emptyMessageStyle: "emptyMessage",
                      useCellRecords: false,
                      rowSpanSelectionMode: "forward",
                      showFocusOutline: true,
                      remapOverStyles: Array[13],
                      position: "absolute",
                      className: "pickListMenuBody",
                      width: 1198,
                      height: 263,
                      top: 35,
                      parentElement: [PickListMenu ID:isc_PickListMenu_0],
                      topElement: [PickListMenu ID:isc_PickListMenu_0],
                      autoFitData: "vertical",
                      autoFitMaxWidth: 400,
                      mozOutlineOffset: "0px",
                      mozOutlineColor: "white",
                      tabIndex: 1713,
                      ruleScope: "isc_PickListMenu_0",
                      cacheOffsetCoords: true,
                      zIndex: 202034,
                      vscrollOn: true,
                      hscrollOn: false,
                      selection: [Selection ID:isc_PickListMenu_0_selection],
                      vscrollbar: [Scrollbar ID:isc_PickListMenu_0_body_vscroll],
                      peers: Array[1],
                      lastOverRow: 3,
                      lastOverCol: 3,
                      lastMouseOverRow: 3,
                      lastMouseOverCol: 3,
                      hasFocus: false,
                      }
                      How do I get a ListGrid Object from EventHandler.getTarget()?I searched the forums, but the threads coming up did not help.

                      Best regards
                      Blama

                      Comment


                        #12
                        What gets hit by the event is the listGrid.body AutoChild. The ListGrid is its parent. Remember, the Watch Tab makes these relationships easy to see.

                        Comment


                          #13
                          Hi Isomorphic,

                          OK, thanks. I now tried:
                          Code:
                                                  ListGrid lg = null;
                                                  try {
                                                      Canvas c = EventHandler.getTarget();
                                                      lg = (ListGrid) c.getParent();
                                                  } catch (Exception e) {
                                                      SC.logWarn("Could not cast click target to ListGrid");
                                                  }
                          but c.getParent() is null.
                          Generally speaking what you say about the watch tab is true. But in this special case, the pickList is dimissed on any click, so I can never hit "Refresh" in the watch tab.
                          From other ListGrids I can see that the inner class of a ListGrid is "GridBody". This JS class has no matching Java class, has it?

                          Best regards
                          Blama

                          Comment


                            #14
                            getParentCanvas() not getParent(). Note the return type of getParent() - it's a core GWT API and returns GWT objects. This API doesn't apply in SmartGWT (aside from not being of any use in your situation).

                            The SmartClient GridBody class has no SmartGWT wrapper and doesn't need one for any use case we've run into. Certainly not this one.

                            The Watch Tab has settings to allow you to see hidden widgets, and you can also look up widgets by ID (and you know the ID), so you have many ways of finding this widget in the component tree.

                            Comment


                              #15
                              Hi Isomorphic,

                              thanks a lot, now it is working. Missing the return type of getParent() wasn't the smartest thing to do.
                              In the Watch Tab I can see isc_PickListMenu_0_body after selecting "Show hidden".

                              Thank you
                              Blama

                              Comment

                              Working...