Reset all screen's control values

早过忘川 提交于 2020-01-04 14:30:59

问题


I have an "Add New…" screen with multiple sap.m.Input fields. Everything is working. I submit the form and the values are stored in the DB. But once I re-open this "Add New…" screen, I get the form with previously entered values.

Currently, I can solve the issue iterating over all sap.m.Input fields with sap.ui.core.Element, resetting the values:

Element.registry.forEach(el => {
    if (el.isA("sap.m.Input") && el.sId.includes(inputFieldsMask)) {
        sap.ui.getCore().byId(el.sId).setValue("");
    }
});

Where inputFieldsMask is a mask for all input fields of the relevant screen.

As far as I understand, Element.registry.forEach iterates over all controls in the app, therefore I'm not sure that, from a performance point of view, it's an optimal approach to clean up the fields.

My question:
Is there a better way to reset input fields from the previously entered values?


回答1:


There are several ways to reset the control values depending on what kind of approach you took to create the new entry. Generally, we can make use of the following APIs:

  1. targetContainer.bindElement(sPathToNewItem) which resolves relative bindings in that container
  2. <user enters some values and submits ...>
  3. targetContainer.unbindElement(sModelName) after exiting the edit view

By unbinding element, relatively bound control values are reset automatically.

Example (using client-side model):

sap.ui.getCore().attachInit(() => sap.ui.require([
  "sap/ui/core/mvc/XMLView",
  "sap/ui/model/json/JSONModel",
  "sap/base/util/uid",
], (XMLView, JSONModel, createPseudoUniqueID) => XMLView.create({
  definition: `<mvc:View xmlns:mvc="sap.ui.core.mvc" height="100%">
    <App xmlns="sap.m">
      <Page backgroundDesign="List" title="Resetting inputs via Model and Context">
        <headerContent>
          <Button id="addBtn" text="Add Item" type="Emphasized" />
        </headerContent>
        <List id="myList" growing="true" items="{
          path: '/myItems',
          key: 'key',
          templateShareable: false
        }">
          <StandardListItem title="{value}" info="Key: {key}"/>
        </List>
      </Page>
      <dependents>
        <Dialog id="myDialog"
          icon="sap-icon://ui-notifications"
          title="New Item"
          draggable="true"
          class="sapUiResponsiveContentPadding"
        >
          <Input id="myInput"
            placeholder="&lt;New value>"
            valueLiveUpdate="true"
            value="{
              path: 'value',
              type: 'sap.ui.model.type.String',
              constraints: {
                minLength: 1
              }
            }"
          />
          <beginButton>
            <Button
              text="Submit"
              enabled="{= !!%{value} &amp;&amp; !%{messages>/}.length}"
            />
          </beginButton>
        </Dialog>
      </dependents>
    </App>
  </mvc:View>`,
  models: {
    undefined: new JSONModel({
      "myItems": [],
    }),
    "messages": sap.ui.getCore().getMessageManager().getMessageModel()
  },
  afterInit: function() {
    sap.ui.getCore().getMessageManager().registerObject(this, true);
    this.byId("addBtn").attachPress(handleAddPress.bind(this));
    this.byId("myInput").attachSubmit(handleSubmit.bind(this));
    this.byId("myDialog").setEscapeHandler(onESCPress.bind(this))
      .attachAfterClose(onAfterClose.bind(this))
      .getBeginButton().attachPress(handleSubmit.bind(this));
    
    function handleAddPress(event) {
      const dialog = this.byId("myDialog");
      const listBinding = this.byId("myList").getBinding("items");
      listBinding.suspend(); // Do not update the list yet
      this._currentItems = this.getModel().getProperty("/myItems"); // temp in case user cancels
      dialog.getModel().setProperty("/myItems", this._currentItems.concat({})); // new empty item
      dialog.bindElement("/myItems/" + listBinding.getLength()); // enable data synchronization via TwoWay binding
      dialog.open();
    }
    
    function onESCPress(promise) {
      const model = this.getModel();
      model.setProperty("/myItems", this._currentItems, /*context*/null, /*async*/true);
      return promise.resolve(); // continue closing dialog
    }
    
    function onAfterClose(event) {
      handleAfterClose(event.getSource(), this.byId("myList").getBinding("items"));
    }
    
    function handleAfterClose(dialog, listBinding) {
      dialog.unbindElement(); // reset data
      dialog.setBusy(false);
      listBinding.resume();
    }
    
    function handleSubmit() {
      const dialog = this.byId("myDialog");
      if (!dialog.getBeginButton().getEnabled()) return; // something is wrong
      dialog.setBusy(true);
      if (!this._isStillRequesting) {
        this._isStillRequesting = true;
        /* send request */setTimeout(mySuccessHandler.bind(this), 3000)
      };
    }
    
    function mySuccessHandler(newKeyFromServer = createPseudoUniqueID()) {
      const dialog = this.byId("myDialog");
      this._isStillRequesting = false;
      if (!dialog.isOpen()/* request was aborted e.g. by pressing ESC */) {
        return; // exit early
      }
      const context = dialog.getBindingContext();
      const value = context.getProperty("value");
      dialog.getModel().setProperty(context.getPath("key"), newKeyFromServer);
      dialog.close();
      sap.ui.require([
        "sap/m/MessageToast"
      ], MT => window.requestAnimationFrame(() => MT.show(`${value} created`)));
    }

  },
}).then(view => view.placeAt("content"))));
<script id="sap-ui-bootstrap" src="https://ui5.sap.com/resources/sap-ui-core.js"
  data-sap-ui-libs="sap.ui.core, sap.m"
  data-sap-ui-theme="sap_fiori_3"
  data-sap-ui-async="true"
  data-sap-ui-compatversion="edge"
  data-sap-ui-xx-waitForTheme="init"
></script>
<body id="content" class="sapUiBody sapUiSizeCompact"></body>

Binding and unbinding element also applies to server-side models such as ODataModel.

Benefits

  • ✅ Reduced overload: no need to iterate over all existing controls. Reset only those automatically that need to be reset.
  • ✅ Control agnostic: does not rely on control specific APIs such as myInput.setValue, mySwitch.setState, etc..
  • ✅ Reduced maintenance costs: no need to maintain list of model properties in controller that application needs to reset manually.



回答2:


Best practice is to use a model to store your application data and to bind any input field to that model. I added an example here. For the sake of simplicity the model data is cleared when the button is pressed.

In a real world application you would place any setup of the model to the onRouteMatched handler to ensure that the data is in an initial state.

onRouteMatched : function(event) {
    this.getView().getModel().setData({
        "firstName": "",
        "lastName": ""
    });
}



回答3:


Bind all your control values to a model. Then reset this model after you've successfully saved the data.

Example:

control1.bindProperty("value", "/controlValues/control1Value"); // Binding
// control1.bindProperty("value", "/controlValues/name");
// <Input value="{/controlValues/name}" /> // <-- ideal binding in xml view

this.getView().getModel().setProperty("/controlValues", this.resetFormData()); // Clear Model

resetFormData: function () {
    var emptyControlValues = {
        "control1Value": "", // "name": "", <-- bind to control
        "control2Value": 0,  // "age": 0,
        "control3Value": "", // "address": "",
        "control4Value": ""  // "tel": ""
    };
    return emptyControlValues;
};


来源:https://stackoverflow.com/questions/56920185/reset-all-screens-control-values

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!