<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width,initial-scale=1.0" />
    <title>Demo</title>
    <style>
      html, body {
        height: 100%;
        margin: 0;
      }
      .sapUiBody .myDemoSearchField {
        width: 23rem;
      }
    </style>
    <script id="sap-ui-bootstrap"
      src="https://sdk.openui5.org/nightly/resources/sap-ui-core.js"
      data-sap-ui-libs="sap.ui.core,sap.m,sap.ui.unified,sap.ui.layout"
      data-sap-ui-async="true"
      data-sap-ui-onInit="onUI5Init"
      data-sap-ui-resourceRoots='{"my.demo": "./"}'
      data-sap-ui-compatVersion="edge"
    ></script>
    <script>
      globalThis.onUI5Init = () => sap.ui.require([
        "my/demo/control/SearchField",
      ], (SearchField, Input) => {
        "use strict";
        const searchField = new SearchField("mySearchField", {
          myValue: "My Search Field",
          myButtonText: "My Button Text",
          search(event) {
            alert(event.getParameter("value"))
          }
        }).addStyleClass("sapUiTinyMargin");
        searchField.placeAt("content");
      });
    </script>
  </head>
  <body class="sapUiBody" id="content"></body>
</html>
sap.ui.define([
  "sap/ui/core/Control",
  "sap/ui/base/ManagedObject",
  "sap/m/Button",
  "sap/m/Input",
], (Control, ManagedObject, Button, Input) => {
  "use strict";

  return Control.extend("my.demo.control.SearchField", {
    metadata: {
      properties: {
        "myValue": {bindable: true},
        "myButtonText": {bindable: true},
      },
      aggregations: {
        "_input": {type: "sap.m.Input", multiple: false, visibility: "hidden"},
        "_btn": {type: "sap.m.Button", multiple: false, visibility: "hidden"}
      },
      events: {
        "search": {
          parameters: {
            "value": { type: "string" }
          }
        }
      }
    },

    init() {
      Control.prototype.init.apply(this, arguments);
      this.setAggregation("_input", this._getInput());
      this.setAggregation("_btn", this._getButton());
    },

    setMyValue(sValue) {
      this.setProperty("myValue", sValue, true);
      this._getInput()?.setValue(sValue?.trim());
      return this;
    },
    setMyButtonText(sText) {
      this.setProperty("myButtonText", sText, true);
      this._getButton()?.setText(sText?.trim());
      return this;
    },

    _getInput() {
      let oInput = this.getAggregation("_input");
      if (!oInput && !this.isDestroyStarted()) {
        oInput = new Input(this.getId() + "-input", {
          // Safeguard against unintentional binding interpretation
          value: ManagedObject.escapeSettingsValue(this.getMyValue()),
          change: (oEvent) => {
            this.setProperty("myValue", oEvent.getParameter("value"), true);
          }
        });
        this.setAggregation("_input", oInput);
      }
      return oInput;
    },

    _getButton() {
      let oButton = this.getAggregation("_btn");
      if (!oButton && !this.isDestroyStarted()) {
        oButton = new Button(this.getId() + "-btn", {
          // Safeguard against unintentional binding interpretation
          text: ManagedObject.escapeSettingsValue(this.getMyButtonText()),
          width: "100%",
          press: () => this.fireSearch({
            value: this._getInput().getValue()
          }),
        });
        this.setAggregation("_btn", oButton);
      }
      return oButton;
    },

    renderer: {
      apiVersion: 4,
      render(oRm, control) {
        oRm.openStart("div", control).class("myDemoSearchField").openEnd()
          .renderControl(control._getInput("_input"))
          .renderControl(control._getButton("_btn"))
        .close("div");
      }
    }

  });
});