<!DOCTYPE html>
<html style="height: 100%;">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Demo</title>
    <script id="sap-ui-bootstrap"
      src="https://openui5.hana.ondemand.com/resources/sap-ui-core.js"
      data-sap-ui-theme="sap_fiori_3"
      data-sap-ui-async="true"
      data-sap-ui-modules="sap/ui/thirdparty/sinon,sap/ui/thirdparty/datajs,demo/localService/mockserver"
      data-sap-ui-oninit="module:demo/init"
      data-sap-ui-compatversion="edge"
      data-sap-ui-excludejquerycompat="true"
      data-sap-ui-resourceroots='{ "demo": "./" }'
      data-sap-ui-xx-waitfortheme="init"
    ></script>
  </head>
  <body id="content" class="sapUiBody">
    <div style="height: 100%;"
      data-sap-ui-component
      data-id="rootComponentContainer"
      data-name="demo"
      data-height="100%"
      data-settings='{ "id": "rootComponent" }'
    ></div>
  </body>
</html>
sap.ui.define([
	"sap/ui/core/UIComponent",
	"sap/ui/core/BusyIndicator",
], function(UIComponent, BusyIndicator) {
	"use strict";

	return UIComponent.extend("demo.Component", {
		metadata: {
			manifest: "json",
      interfaces: [
        "sap.ui.core.IAsyncContentCreation",
      ],
		},

		init: async function() {
			UIComponent.prototype.init.apply(this, arguments);
			this.getRouter().initialize();
			await this.getModel("odata").metadataLoaded();
			BusyIndicator.hide();
		},

	});
});
{
  "_version": "1.33.0",
  "start_url": "index.html",
  "sap.app": {
    "id": "demo",
    "type": "application",
    "title": "Demo",
    "description": "Sample Code",
    "applicationVersion": {
      "version": "1.0.0"
    },
    "dataSources": {
      "MyNodes": {
        "uri": "/",
        "type": "OData",
        "settings": {
          "odataVersion": "2.0",
          "localUri": "localService/metadata.xml"
        }
      }
    }
  },
  "sap.ui": {
    "technology": "UI5",
    "deviceTypes": {
      "desktop": true,
      "tablet": true,
      "phone": true
    }
  },
  "sap.ui5": {
    "dependencies": {
      "minUI5Version": "1.46.7",
      "libs": {
        "sap.ui.core": {},
        "sap.m": {},
        "sap.f": {}
      }
    },
    "contentDensities": {
      "compact": true,
      "cozy": true
    },
    "resources": {
      "js": [

      ],
      "css": [

      ]
    },
    "models": {
      "odata": {
        "dataSource": "MyNodes",
        "settings": {
          "preliminaryContext": true
        },
        "preload": true
      },
      "search": {
        "type": "sap.ui.model.json.JSONModel"
      }
    },
    "rootView": {
      "viewName": "demo.view.App",
      "id": "rootView",
      "type": "XML",
      "async": true,
      "height": "100%"
    },
    "routing": {
      "routes": [{
        "pattern": "",
        "name": "master",
        "target": "master",
        "layout": "OneColumn"
      }],
      "targets": {
        "master": {
          "viewId": "masterView",
          "viewName": "Master",
          "controlAggregation": "beginColumnPages"
        }
      },
      "config": {
        "routerClass": "sap.f.routing.Router",
        "async": true,
        "viewType": "XML",
        "viewPath": "demo.view",
        "controlId": "app"
      }
    }
  }
}
<mvc:View xmlns:mvc="sap.ui.core.mvc"
  xmlns="sap.m"
  xmlns:f="sap.f"
  displayBlock="true"
>
  <App>
    <f:FlexibleColumnLayout id="app" >
      <f:beginColumnPages>
        <!-- will be added by router -->
      </f:beginColumnPages>
      <f:midColumnPages>
        <!-- will be added by router -->
      </f:midColumnPages>
      <f:endColumnPages>
        <!-- will be added by router -->
      </f:endColumnPages>
    </f:FlexibleColumnLayout>
  </App>
</mvc:View>
<mvc:View xmlns:mvc="sap.ui.core.mvc"
  xmlns="sap.m"
  xmlns:f="sap.f"
  controllerName="demo.controller.Master"
>
  <f:DynamicPage showFooter="true">
    <f:title>
      <f:DynamicPageTitle>
        <f:heading>
          <Title text="My Tree"/>
        </f:heading>
        <f:actions>
          <SearchField
            width="auto"
            value="{search>/query}"
            liveChange=".onLiveChange"
          />
        </f:actions>
      </f:DynamicPageTitle>
    </f:title>
    <f:header>
    </f:header>
    <f:content>
      <Tree id="myTree"
        class="sapFDynamicPageAlignContent"
        width="auto"
        items="{
          path: 'odata>/GroupNodes',
          parameters: {
            operationMode: 'Client',
            useServersideApplicationFilters: false
          },
          events: {
            change: '.onTreeChange'
          }
        }"
      >
        <StandardTreeItem title="{odata>Description}" />
      </Tree>
    </f:content>
  </f:DynamicPage>
</mvc:View>
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<edmx:Edmx Version="1.0"
	xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx"
	xmlns="http://schemas.microsoft.com/ado/2008/09/edm"
	xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
	xmlns:sap="http://www.sap.com/Protocols/SAPData"
>
	<edmx:DataServices m:DataServiceVersion="2.0">
		<Schema Namespace="Demo" xml:lang="en" sap:schema-version="1">
 
			<EntityType Name="GroupNode">
				<Key>
					<PropertyRef Name="NodeID" />
				</Key>
				<Property Name="NodeID" Type="Edm.Int32" Nullable="false" sap:hierarchy-node-for="NodeID"/>
				<Property Name="HierarchyLevel" Type="Edm.Int32" Nullable="false" sap:hierarchy-level-for="NodeID"/>
				<Property Name="Description" Type="Edm.String" Nullable="false" />
				<Property Name="ParentNodeID" Type="Edm.Int32" Nullable="true" sap:hierarchy-parent-node-for="NodeID"/>
				<Property Name="DrillState" Type="Edm.String" Nullable="false" sap:hierarchy-drill-state-for="NodeID" />
			</EntityType>

			<EntityContainer Name="DemoEntities" m:IsDefaultEntityContainer="true">
				<EntitySet Name="GroupNodes" EntityType="Demo.GroupNode" />
			</EntityContainer>
 
		</Schema>
	</edmx:DataServices>
</edmx:Edmx>
sap.ui.define([
  "sap/ui/core/util/MockServer",
  "sap/ui/thirdparty/datajs",
], function(MockServer) {
  "use strict";

  return {
    init: function() {
      MockServer.config({
        autoRespond: true,
        autoRespondAfter: 0,
      });
      const mockServer = new MockServer({
        rootUri: "/",
        recordRequests: false,
      });
      const pathPrefix = jQuery.sap.getModulePath("demo/localService");
      mockServer.simulate(pathPrefix + "/metadata.xml", {
        sMockdataBaseUrl: pathPrefix + "/mockdata",
      });
      mockServer.start();
    }
  };
});
[
	{
		"NodeID": 1,
		"HierarchyLevel": 0,
		"Description": "1",
		"ParentNodeID": null,
		"DrillState": "expanded"
	},
	{
		"NodeID": 2,
		"HierarchyLevel": 0,
		"Description": "2",
		"ParentNodeID": null,
		"DrillState": "expanded"
	},
	{
		"NodeID": 3,
		"HierarchyLevel": 0,
		"Description": "3",
		"ParentNodeID": null,
		"DrillState": "expanded"
	},
	{
		"NodeID": 4,
		"HierarchyLevel": 1,
		"Description": "1.1",
		"ParentNodeID": 1,
		"DrillState": "leaf"
	},
	{
		"NodeID": 5,
		"HierarchyLevel": 1,
		"Description": "1.2",
		"ParentNodeID": 1,
		"DrillState": "expanded"
	},
	{
		"NodeID": 6,
		"HierarchyLevel": 2,
		"Description": "1.2.1",
		"ParentNodeID": 5,
		"DrillState": "leaf"
	},
	{
		"NodeID": 7,
		"HierarchyLevel": 2,
		"Description": "1.2.2",
		"ParentNodeID": 5,
		"DrillState": "leaf"
	},
	{
		"NodeID": 8,
		"HierarchyLevel": 1,
		"Description": "2.1",
		"ParentNodeID": 2,
		"DrillState": "leaf"
	},
	{
		"NodeID": 9,
		"HierarchyLevel": 1,
		"Description": "2.2",
		"ParentNodeID": 2,
		"DrillState": "leaf"
	},
	{
		"NodeID": 10,
		"HierarchyLevel": 1,
		"Description": "2.3",
		"ParentNodeID": 2,
		"DrillState": "leaf"
	},
	{
		"NodeID": 11,
		"HierarchyLevel": 1,
		"Description": "3.1",
		"ParentNodeID": 3,
		"DrillState": "expanded"
	},
	{
		"NodeID": 12,
		"HierarchyLevel": 2,
		"Description": "Hello World",
		"ParentNodeID": 11,
		"DrillState": "expanded"
	},
	{
		"NodeID": 13,
		"HierarchyLevel": 3,
		"Description": "3.1.1.1",
		"ParentNodeID": 12,
		"DrillState": "leaf"
	},
	{
		"NodeID": 14,
		"HierarchyLevel": 3,
		"Description": "3.1.1.2",
		"ParentNodeID": 12,
		"DrillState": "leaf"
	},
	{
		"NodeID": 15,
		"HierarchyLevel": 3,
		"Description": "3.1.1.3",
		"ParentNodeID": 12,
		"DrillState": "leaf"
	},
	{
		"NodeID": 16,
		"HierarchyLevel": 3,
		"Description": "3.1.1.4",
		"ParentNodeID": 12,
		"DrillState": "leaf"
	}
]
sap.ui.define([
  "sap/ui/core/mvc/Controller",
  "sap/ui/model/Filter",
], function(Controller, Filter) {
  "use strict";

  return Controller.extend("demo.controller.Master", {
    onLiveChange: function(event) {
      const query = event.getParameter("newValue").trim();
      this.byId("myTree").getBinding("items").filter(query ? new Filter({
        path: "Description",
        operator: "Contains",
        value1: query,
      }) : null);
    },

    onTreeChange: function(event) {
      if (event.getParameter("reason") == "filter") {
        const model = this.getOwnerComponent().getModel("search");
        const query = model.getProperty("/query");
        this.byId("myTree").expandToLevel(query ? 99 : 0);
      }
    },
  });
});
sap.ui.require([
  "demo/localService/mockserver",
  "sap/ui/core/BusyIndicator",
], (mockserver, BusyIndicator) => {
  "use strict";
  
  BusyIndicator.show(1);
  mockserver.init();
  sap.ui.require([ "sap/ui/core/ComponentSupport" ]);
});