Announcement

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

    DynamicForm acts different to updated data than ListGrid (5.1p) (Bug?)

    Hi Isomorphic,

    I have an issue in current 5.1p (v10.1p_2017-03-02), but it is so basic, I'm not sure my expectation is correct.
    If I update a record or send updated data via serverside addRelatedUpdate(), this data is updated in the GUI in ListGrids displaying the selected record.
    This does not happen for DynamicForm. Neither DataSource.updateCaches() nor DataBoundComponent docs say anything about why this should not happen for DynamicForms as well.
    Is this a bug? See this BuiltInDS-based testcase.

    Steps to reproduce:
    • Edit the row in one of the ListGrids to see the data changed in the other ListGrid as well. DynamicForms are unchanged (unexpected).
    • Edit the record in the DynamicForm and hit "save" to see the data changed in both ListGrids. The other DynamicForm is unchanged (unexpected).
    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.data.AdvancedCriteria;
    import com.smartgwt.client.data.Criterion;
    import com.smartgwt.client.data.DataSource;
    import com.smartgwt.client.types.Alignment;
    import com.smartgwt.client.types.OperatorId;
    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.form.DynamicForm;
    import com.smartgwt.client.widgets.form.fields.ButtonItem;
    import com.smartgwt.client.widgets.form.fields.FormItem;
    import com.smartgwt.client.widgets.grid.ListGrid;
    import com.smartgwt.client.widgets.grid.ListGridField;
    import com.smartgwt.client.widgets.layout.VLayout;
    
    public class BuiltInDS implements EntryPoint {
        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();
                }
            });
    
            VLayout mainLayout = new VLayout(20);
            mainLayout.setWidth100();
            mainLayout.setHeight100();
    
            {
                IButton btn = new IButton("Recreate");
                btn.addClickHandler(new ClickHandler() {
                    @Override
                    public void onClick(ClickEvent event) {
                        recreate();
                    }
                });
                mainLayout.addMember(btn);
            }
            recreate();
            mainLayout.draw();
        }
    
        private void recreate() {
            Window w = new Window();
            w.setWidth("95%");
            w.setHeight("95%");
            w.setMembersMargin(30);
            w.setModalMaskOpacity(70);
            w.setTitle(" (" + Version.getVersion() + "/" + Version.getSCVersionNumber() + ")");
            w.setTitle("DataBoundComponent update behavior" + w.getTitle());
            w.setShowMinimizeButton(false);
            w.setIsModal(true);
            w.setShowModalMask(true);
            w.centerInPage();
    
            w.addItem(new DynamicFormSupplyItem());
            w.addItem(new DynamicFormSupplyItem());
            w.addItem(new ListGridSupplyItem());
            w.addItem(new ListGridSupplyItem());
            w.show();
        }
    
        private final class DynamicFormSupplyItem extends DynamicForm {
            public DynamicFormSupplyItem() {
                {
                    setDataSource(DataSource.get("supplyItem"));
                    setIsGroup(true);
                    setGroupTitle("To see DynamicForm dimensions");
                    setWidth(400);
    
                    final FormItem itemID = new FormItem("itemID");
                    final FormItem itemName = new FormItem("itemName");
                    final FormItem SKU = new FormItem("SKU");
                    final FormItem description = new FormItem("description");
                    final FormItem category = new FormItem("category");
                    final ButtonItem save = new ButtonItem("SAVE", "Save") {
                        {
                            setWidth(100);
                            setColSpan(2);
                            setAlign(Alignment.RIGHT);
                            addClickHandler(new com.smartgwt.client.widgets.form.fields.events.ClickHandler() {
                                @Override
                                public void onClick(com.smartgwt.client.widgets.form.fields.events.ClickEvent event) {
                                    getForm().saveData();
                                };
                            });
                        }
                    };
                    setFields(itemID, itemName, SKU, description, category, save);
                    fetchData(new AdvancedCriteria(new Criterion("SKU", OperatorId.EQUALS, "58074602")));
                }
            }
        }
    
        private final class ListGridSupplyItem extends ListGrid {
            public ListGridSupplyItem() {
                {
                    setDataSource(DataSource.get("supplyItem"));
                    setAutoFetchData(false);
                    setWidth(800);
                    setHeight(100);
                    setCanEdit(true);
    
                    final ListGridField itemID = new ListGridField("itemID");
                    final ListGridField itemName = new ListGridField("itemName");
                    final ListGridField SKU = new ListGridField("SKU");
                    final ListGridField description = new ListGridField("description");
                    final ListGridField category = new ListGridField("category");
    
                    setFields(itemID, itemName, SKU, description, category);
                    fetchData(new AdvancedCriteria(new Criterion("SKU", OperatorId.EQUALS, "58074602")));
                }
            }
        }
    }
    Best regards
    Blama

    #2
    Hi Isomorphic,

    also see this answer of yours - As DataSource.updateCaches() is most likely(?) called during the processing of a DSResponse, I'd assume even more that a DynamicForm should reflect the changes as well.

    Best regards
    Blama

    Comment


      #3
      A form will only update with changes if it is the form that initiated the save. This is by design.

      Consider: if you have more than one form in the same app simultaneously editing the same record, you've possibly got a serious UX problem: having two ways of editing the same data are one screen is very likely to be confusing, for example, what happens if both forms are edited and then one is saved?

      For cases where there are updates to data that is being edited in a form and it's not a UX design mistake, such as receiving a notification of edits by another user, just wiping the data currently being edited is again the wrong default - you'll want some kind of reconciliation UI.

      If your app includes some situation where form values should be updated mid-edit and it's not a UX design mistake, add application logic to do so, because it wouldn't be a good framework behavior to do this by default.

      Comment


        #4
        Hi Isomorphic,

        all understood and agreed. Could you add this to the docs, either DynamicForm or the docs I linked in #1? I think it is missing, even though I completely understand your argumentation and I (and every other user) could think that the behavior is the best practice.


        My use case is the following:
        • "My User" administration GUI with:
          • 1 DF for Name / eMail / Telephone + "Save"-ButtonItem
          • 1 DF for password + "Save"-ButtonItem
          • 1 DF for vacation substitute + "Save"-ButtonItem
        "Normal" way would be a ValuesManager, but I thought it would be also possible without, because of simpler code.

        Problem:
        If I load a record, the DF keeps all fields even if they are not displayed and also sends them with the save operation.
        Now if I change 2 DF and then click save in both (every DF has a "Save"-button), the changes from the 1st safe are overwritten to default.

        Is it possible to have a DF only manage (and send on "Save") the fields where it has FormItems for (+the primaryKey)? Then I could solve my use case without a ValueManager, IMHO.

        Thank you & Best regards
        Blama

        Comment


          #5
          Yours seems a use case for a ValuesManager. We wouldn't want to come up with an alternate solution when this is well handled.

          Do you have a suggestion for where it would appear in the docs that a DynamicForm does *not* do cache sync? Seems an odd thing to state on its own.

          Comment


            #6
            Hi Isomorphic,

            I'd put the information into DataBoundComponent docs, as there are possibly many Components where this holds:
            • DynamicForm
            • ValuesManager (pretty sure)
            • DetailViewer (?)

            Regarding my use case: I think I can solve it with existing APIs by using DynamicForm.clearValue() for all fields I do not want to be updated.
            It works in this EE-sample using DeveloperConsole and isc_DynamicForm_59.clearValue("trackingNumber"); I'll try in my application next.

            Best regards
            Blama

            Comment

            Working...
            X