Announcement

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

    ListGrid record components

    Issues with record components:

    1. I want to reuse my SplitDateTimeItem in a ListGrid. So I use a DynamicForm as a record component. However, I can still see the original DateItem below my Dynamic Form when editing.

    2. If a ListGrid is set to save locally, and if the ListGrid has displayed one or more records, and I try to edit a new record that has no values for the ListGrid, or I want to view a record that does not have values for the ListGrid I get the following kind of errors:



    Note that MissionPlanForm along with SensorTransitionList essentially is a reproduction of your JPA One-to-Many Relation example. Where a mission has many SensorTransitions.

    Any help would be greatly appreciated. It would probably be simpler to create a test case using your example, and including a dateTime value in city. As I have significantly more code than above, but it would demonstrate everything except the use of a valuesManager.
    Last edited by jpappalardo; 24 Sep 2014, 09:39.

    #2
    A recordComponent won't automagically tie into the ListGrid editing system (tabbing order, validation, coordinated saving etc) so what you probably want to do is use listGridField.setEditorType() with a CanvasItem. This would eliminate the extra DateItem.

    As far as issues with new records being added, bear in mind the Record is null for an unsaved row, the unsaved edits are available via getEditedRecord() and related APIs. See the Grid Editing overview for details.

    Comment


      #3
      Although I would like to believe the answer is that simple. I cannot use my custom list grid that adds buttons to each record either in this way without getting the same errors
      Last edited by jpappalardo; 24 Sep 2014, 09:39.

      Comment


        #4
        Running your second test, we're not seeing the bad or negative size warnings.
        Here's our full test case based on your sample code:

        Code:
        import java.util.ArrayList;
        import java.util.Arrays;
        import java.util.List;
        
        import com.google.gwt.core.client.EntryPoint;
        import com.smartgwt.client.widgets.*;
        
        import com.smartgwt.client.widgets.events.*;
        import com.smartgwt.client.widgets.grid.*;
        
        import com.smartgwt.client.data.*;
        import com.smartgwt.client.types.*;
        
        public class EmbeddedComponentBugs implements EntryPoint {
            
        
            @Override
            public void onModuleLoad() {
                ListGrid grid = new DefaultListGrid(true, true, true, true);
                grid.setWidth(500);
                grid.setHeight(500);
                grid.setDataSource(new TestDS());
                grid.draw();
                
            }
        
            public class DefaultListGrid extends ListGrid {
        
                private final boolean canView;
                private final boolean canCopy;
                private final boolean canRemove;
        
                private ListGridField[] specifiedFields;
        
                /**
                 * Create a new instance
                 * @param useAllDataSourceFields Display all DataSource fields if true
                 * @param canView   Display view icon for records if true
                 * @param canCopy   Display copy icon for records if true
                 * @param canRemove Display remove icon for records if true
                 */
                public DefaultListGrid(boolean useAllDataSourceFields, boolean canView, boolean canCopy, boolean canRemove) {
                    super();
                    setUseAllDataSourceFields(useAllDataSourceFields);
        
                    this.canView = canView;
                    this.canCopy = canCopy;
                    this.canRemove = canRemove;
                    
                    setShowRecordComponents(true);
                    setShowRecordComponentsByCell(true);
                    setLeaveScrollbarGap(false);
                    setCanEdit(false);
                    setAutoFetchData(true);
                }
        
        //        private DefaultListGridListener listener;
        
                @Override
                protected Canvas createRecordComponent(final ListGridRecord listGridRecord, Integer col) {
                    String fieldName = getFieldName(col);
                    if(fieldName.equals("viewField")) {
                        ImgButton view = new ImgButton();
                        view.setSrc("[SKIN]/actions/view.png");
                        view.setPrompt("View");
                        view.setSize(16);
                        view.setShowDown(false);
                        view.setShowRollOver(false);
                        view.setAlign(Alignment.CENTER);
                        view.addClickHandler(new ClickHandler() {
                            @Override
                            public void onClick(ClickEvent clickEvent) {
        //                        if(listener != null) {
        //                            listener.onView(listGridRecord);
        //                        }
                            }
                        });
                        return view;
                    } else if(fieldName.equals("copyField")) {
                        ImgButton copy = new ImgButton();
                        copy.setSrc("[SKIN]/RichTextEditor/copy.png");
                        copy.setPrompt("Copy");
                        copy.setSize(16);
                        copy.setShowDown(false);
                        copy.setShowRollOver(false);
                        copy.setAlign(Alignment.CENTER);
                        copy.addClickHandler(new ClickHandler() {
                            @Override
                            public void onClick(ClickEvent clickEvent) {
        //                        if (listener != null) {
        //                            listener.onCopy(listGridRecord);
        //                        }
                            }
                        });
                        return copy;
                    } else if(fieldName.equals("removeField")) {
                        ImgButton remove = new ImgButton();
                        remove.setSrc("[SKIN]/actions/remove.png");
                        remove.setPrompt("Remove");
                        remove.setSize(16);
                        remove.setShowDown(false);
                        remove.setShowRollOver(false);
                        remove.setAlign(Alignment.CENTER);
                        remove.addClickHandler(new ClickHandler() {
                            @Override
                            public void onClick(ClickEvent clickEvent) {
        //                        if (listener != null) {
        //                            listener.onRemove(listGridRecord);
        //                        }
                            }
                        });
                        return remove;
                    } else {
                        return null;
                    }
                }
        
                @Override
                public void setFields(ListGridField... fields) {
                    // remember the explicitly specified fields.
                    specifiedFields = fields;
                    this.setCombinedFields();
                }
        
                private void setCombinedFields() {
        
                    ListGridField[] fields;
                    if (specifiedFields == null) {
                        fields = new ListGridField[] {};
                    } else {
                        fields = specifiedFields;
                    }
        
                    List<ListGridField> list = Arrays.asList(fields);
                    ArrayList<ListGridField> allFields = new ArrayList<ListGridField>(list);
        
                    // We need to explicitly combine with dataSource fields. Cases to consider:
                    // - no explicit fields passed in:
                    // In this case we want to show all dataSource fields, even if the
                    // useAllDataSourceFields flag isn't explicitly set. Grab all the fields from the dataSource
                    // and slot the custom fields after it.
                    // - useAllDataSourceFields is true:
                    // In this case the dataSource fields show up in the order defined in the DS.
                    // In order to have the custom fields show up on the right, we need to include
                    // the last field defined in the dataSource in our explicit fields array, and slot the
                    // custom fields after it.
                    DataSource ds = this.getDataSource();
                    boolean emptyFields = list.size() == 0;
                    if (ds != null && (getUseAllDataSourceFields() || emptyFields)) {
                        DataSourceField[] dsFields = ds.getFields();
                        if (emptyFields) {
                            for (int i = 0; i < dsFields.length; i++) {
                                allFields.add(new ListGridField(dsFields[i].getName()));
                            }
                        } else if (getUseAllDataSourceFields()) {
                            String lastDSField = dsFields[dsFields.length-1].getName();
                            boolean hasLastField = false;
                            for (int i = 0; i < list.size(); i++) {
                                if (list.get(i).getName().equals(lastDSField)) {
                                    hasLastField = true;
                                    break;
                                }
                            }
                            if (!hasLastField) {
                                allFields.add(new ListGridField(lastDSField));
                            }
                        }
                    }
        
        
                    if(canView) {
                        allFields.add(new ViewField());
                    }
                    if(canCopy) {
                        allFields.add(new CopyField());
                    }
                    if(canRemove) {
                        allFields.add(new RemoveField());
                    }
                    ListGridField[] array = new ListGridField[allFields.size()];
                    super.setFields(allFields.toArray(array));
                }
        
                @Override
                public void setDataSource(DataSource dataSource, ListGridField... fields) {
                    super.setDataSource(dataSource);
                    setFields(fields);
                }
        
                @Override
                public void setDataSource(DataSource dataSource) {
                    super.setDataSource(dataSource);
                    setCombinedFields();
                }
        
        //        public void setListener(DefaultListGridListener listener) {
        //            this.listener = listener;
        //        }
                
                private class ViewField extends ListGridField {
        
                    private ViewField() {
                        super("viewField", " ");
                        setWidth(22);
                        setCanHide(false);
                        setCanSort(false);
                        setCanGroupBy(false);
                        setCanFreeze(false);
                        setCanDragResize(false);
                    }
        
                }
                
                private class CopyField extends ListGridField {
        
                    private CopyField() {
                        super("copyField", " ");
                        setWidth(22);
                        setCanHide(false);
                        setCanSort(false);
                        setCanGroupBy(false);
                        setCanFreeze(false);
                        setCanDragResize(false);
                    }
        
                }
                
                private class RemoveField extends ListGridField {
        
                    private RemoveField() {
                        super("removeField", " ");
                        setWidth(22);
                        setCanHide(false);
                        setCanSort(false);
                        setCanGroupBy(false);
                        setCanFreeze(false);
                        setCanDragResize(false);
                    }
        
                }
            }
            
            public class TestDS extends DataSource {
                public TestDS () {
                    setClientOnly(true);
                    
                    DataSourceField pkField = new DataSourceField("pk", FieldType.SEQUENCE);
                    pkField.setPrimaryKey(true);
                    DataSourceField f1 = new DataSourceField("f1", FieldType.TEXT);
                    DataSourceField f2 = new DataSourceField("f2", FieldType.TEXT);
                    DataSourceField parent = new DataSourceField("parent", FieldType.INTEGER);
                    parent.setForeignKey("pk");
                    DataSourceField bool = new DataSourceField("bool", FieldType.BOOLEAN);
                    setFields(pkField, f1,f2, parent, bool);
                    
                    ListGridRecord[] testData = new ListGridRecord[20];
                    
                    for (int i = 0; i < 20; i++) {
                        
                        
                        ListGridRecord r1 = new ListGridRecord();
                        r1.setAttribute("pk", 0);
                        r1.setAttribute("f1", "Record " + i);
                        r1.setAttribute("f2", "Another Value");
                        
                        testData[i] = r1;
        
                    }
                    
                    setTestData(testData);
                    
                }
            }
        
        }
        We're still investigating as we have seen what looks like a possible bug with row heights in some cases but can you
        - verify what exact build is causing the warnings for you, and
        - see if you can boil your test case to a standalone example we can run verbatim that shows the problem in action?

        This will help us make sure we're really looking at the same issue.
        Thanks

        Comment


          #5
          Sorry for the long delay, I've been quite busy on other things.

          SmartClient Version: v8.2p_2012-04-03/PowerEdition Deployment (built 2012-04-03)

          This is much closer to our actual use case
          Last edited by jpappalardo; 24 Sep 2014, 09:40.

          Comment


            #6
            We have made a change to the 3.0p and 3.1d branch that should take care of this. Please try the next nightly and let us know if this issue still occurs.

            Thanks
            Isomorphic Software

            Comment


              #7
              Thank you kindly for the fix.

              If we can go back to where this post started. Can I use My SplitDateTimeItem as a recordComponent to display the current value, and then create a SplitDateTimeEditor for editing. So that the component is consistent for both viewing and editing data?

              Comment


                #8
                There's no reason that we know of that you'd use it for display since you can do this with just a CellFormatter and that's far faster and less complex. But yes, you can use it as a CanvasItem via setEditorType(), like other custom editors.

                Comment


                  #9
                  Let me explain the requirements I have here, and perhaps you can help me to understand how I can apply a CellFormatter to implement this requirement.

                  The default behavior when creating a new DateTime is for the time segment to default 00:00. Although this is a clearly a valid value it is not the desired behavior. The desired behavior is to enter a date or select one via a date picker, and force the user to manually enter the time.

                  If you look at the implementation of the SplitDateTimeItem I have added RequiredIf validators to both the DateItem and TimeItem. So that entry into either field causes the other to become required. If the user fails to enter both values, upon save the resulting DateTime value is null.

                  I have tried adding my current implementation of SplitDateTimeItem as an editor on the ListGridField and I end up with a lot of exceptions. From what I have read in the documentation the implementation of FormItem as a ListGrid editor is a bit different from that which will work in a DynamicForm. So it would seem that I actually would have to create a different class that implements the same logic to get it to work successfully as an editor in a ListGrid.

                  If you can enlighten me as to how this can be accomplished via CellFormatter, or the CanvasItem I have already written I would be quite pleased to be spared the effort :)

                  Comment


                    #10
                    You've got two separate things to accomplish here:

                    1. just showing the date when the user isn't editing. Do not use recordComponents for this, if you need to customize the way a datetime is shown *when not editing* you can use APIs on DateUtil to set system-wide datetime formatting rules, or use a CellFormatter on your ListGridField if you want to do something specific to this ListGrid.

                    2. your custom editor. If you want to use it in a grid, yes you do need to follow the rules laid out in the setEditorType() docs, which should involve just a few small adjustments.

                    Comment


                      #11
                      Here is my code which I believe is following the setEditorType API correctly.


                      Is my code not implemented correctly?

                      Is this an anomaly due to how editor fields are expected to behave?

                      I would assume that since you have a multiple field date editor that the last couldn't possibly be the issue. Which leads me to believe either there is a bug in my code, or I have exposed a bug in the API.
                      Last edited by jpappalardo; 24 Sep 2014, 09:40.

                      Comment


                        #12
                        As a side note in the interim I am using a normal DateTime item in a list grid. It behaves as expected in Firefox, but in IE I get the following error:



                        When not in edit mode the if there exists a date, it is displayed as expected in the text field. Invoking editing the field, causes the editor to appear with no value. Clicking inside the editor or selecting a date via the date picker both invoke the above error. Is this a know issue with 4/06 patch?
                        Last edited by jpappalardo; 24 Sep 2014, 09:40.

                        Comment


                          #13
                          We'll comment on your revised SplitDateTimeEditor code soon. As far as the getOffsetLeft() problem, no that's not a known problem - are you able to reproduce this by adding code to a sample?

                          Comment


                            #14
                            We'd recommend you not mark the inner-form as 'autoFocus' true as every time this item is drawn anywhere on the page it will attempt to focus in itself with possibly unexpected results.
                            Other than that, the Split DateTime editor code all appears to be basically fine.

                            There was a framework issue that was causing the entire grid to redraw more often than necessary, in response to clicks anywhere on the item.
                            On every redraw, the ShowValueHandler is re-run to ensure the item is displaying the current value correctly. As a result your partially entered values were being wiped out by the underlying record edit value (most likely null) while you were in the process of setting them.

                            We've resolved this issue (The fix will be present in the next nightly build in the 3.0p branch).

                            The warnings about observation should be safe to ignore. We'll look into whether we can clean them up, but they shouldn't impact the application behavior for the end-user.

                            If you have specific thoughts on how you'd like the item to look to make it more attractive, let us know and we can probably tell you how to achieve this.

                            -----
                            Update:
                            One more thing to mention here - for normal grid-editing the user hitting "Enter" will save the edit and "Escape" will dismiss the edit.
                            This is not the case with a CanvasItem based custom editor like this - you'll have to add an explicit keypress handler (probably easiest via an itemKeyPress handler on the inner form) to take care of this.
                            In the 3.1d branch the keyboard events are already "plumbed through" such that a custom keypress handler isn't necessary but we don't have this code in place in the 3.0p branch. Let us know if you can't get this part working correctly.
                            Last edited by Isomorphic; 11 Apr 2012, 16:40.

                            Comment


                              #15
                              I had to make sure that the editor does not overlap any other fields, and setEditByCell(true) and it seems to function appropriately. I think this is good enough to call this matter closed.
                              Last edited by jpappalardo; 12 Apr 2012, 06:24.

                              Comment

                              Working...
                              X