0
votes

I am new to SAPUI5, and more or less new to programming as well. I am currently working on my first practical SAPUI5 project. The application is going to be a splitApp where the master view will have a list of employees which work under the logged on manager and the detail view will have a list of recent absences for a particular employee selected from the list based on their employee number. I was able to add my own Component.js file to include this application in our Fiori launchpad. I set up and registered the gateway service this app will be using. The service has two entity sets, EmployeeListSet and EmployeeLeaveDetailSet. When I set up up oData model in my UI5 code I can bind the EmployeeListSet to my list in the master view. I can see the list of subordinate employees. When I click on a list item I am successfully retrieving the associated employee number in my master controller.

From here I am struggling. I need to use the employee number as a filter parameter when trying to get data for the EmployeeleaveDetailSet and use that data as the model for my table in my detail view. I have researched routing as an option to accomplish this, by looking at the following links like, http://scn.sap.com/community/developer-center/front-end/blog/2015/01/03/splitapp-with-routing-mechanism, and https://www.youtube.com/watch?v=Iz1itB7uDio. (I have read several other tutorials and forum posts and watched several other videos, but I can't share the links in this post because I don't have enough reputation to post more than 2 links. That seems a bit silly to me since the "How to Ask" page for the site stated I should share my research with the community.) Anyhow, I am able to get all of these routing tutorials running, and can understand the concepts being demonstrated, but when I try to apply routing to my own app I get an error "Uncaught TypeError: t.createContent is not a function". I am wondering if I have a flaw in my splitApp set up, because some of the routing tutorials I have looked at started out with just an app, and when I try to change it to be splitApp I get the same error.

So my hope is that there might be members of this programming community who would be able to guide me in the right direction regarding how to pass the employee number from the master controller to the detail so I can use it in a filter for my odata call to the EmployeeLeaveDetail entity set.

Your help is greatly appreciated, thanks in advance to those how are able to help. The following will be the code I have done so far. I commented out the parts of the routing that weren't working.

In WebContent folder

index.html

<!DOCTYPE HTML>
<html>
	<head>
		<meta http-equiv="X-UA-Compatible" content="IE=edge">
		<meta http-equiv='Content-Type' content='text/html;charset=UTF-8'/>
	       <script src="resources/sap-ui-core.js"
				id="sap-ui-bootstrap"
				data-sap-ui-libs="sap.ui.commons, sap.ui.table, sap.m"
				data-sap-ui-theme="sap_bluecrystal"
				data-sap-ui-resourceroots='{
				"zhcm_leave_check": "./"
			}'>
		</script>
		
		<script src="/sap/public/bc/ui2/services/sap/ui2/srvc/error.js"></script>
		<script src="/sap/public/bc/ui2/services/sap/ui2/srvc/utils.js"></script>
		<script src="/sap/public/bc/ui2/shell-api/sap/ui2/shell/startup.js"></script>
		<script src="/sap/public/bc/ui2/shell-api/sap/ui2/shell/shell.js"></script>
		<!-- add sap.ui.table,sap.ui.ux3 and/or other libraries to 'data-sap-ui-libs' if required -->

		<script>
		sap.ui.localResources("view");
// 		jQuery.sap.require("sap.ui.core.routing.Router");
// 		jQuery.sap.require("sap.ui.core.routing.HashChanger");
	
	new sap.m.Shell("shellId", {
			app: new sap.ui.core.ComponentContainer({
				name : "zhcm_leave_check",
				height: "100%"
		})
		}).placeAt("content");
	
// 	var oRouter = new sap.ui.core.routing.Router(  
// 			  {  
// // 			      master: {  
// // 			          pattern: "",  
// // 			          view: "employeelist",
// // 			          targetAggregation: "masterPages"
// // 			  	  },  
// 			  	  detail: {    
// 			  		  pattern: ["EmployeeLeaveHistory", "detail"], 
// 			 		  view: "detail",
// 			 		 targetAggregation: "detailPages"
// 			  	  }  
// 			  },  
// 			  {  
// 			  targetControl: "splitapp",                                    
// 			  viewType: "JS",  
// 			  viewPath: "view",                        
// 			  clearTarget: false                    
// 			  });  
// 	var oRouteHandler = new sap.m.routing.RouteMatchedHandler(oRouter);  
// 	  oRouter.register("router");  // Assign a name to Router, so that we can access it in all controllers by using this name  
// 	  oRouter.initialize();  // Initialise the Router  

		</script>
		<script type = "text/javascript">var EmpID = ""</script>
	</head>
	<body class="sapUiBody" role="application">
		<div id="content"></div>
	</body>
</html>

Component.js

jQuery.sap.declare("zhcm_leave_check.Component");

sap.ui.core.UIComponent.extend("zhcm_leave_check.Component", {
	
//	metadata : {  
//		  routing : {  
//		  config : {  
//		  viewType : "JS",  
//		  viewPath : "view",  
//		  targetControl : "appId",  
//		  clearTarget : false,  
//		  },  
//		  routes : [  
//		  {  
//		  pattern : "", // which appears in URL, while you navigate  
//		  name : "Master",     // Name that is used in navTo method  
//		  view : "employeelist",   // this is the target view that you are navigating to  
//		  viewType : sap.ui.core.mvc.ViewType.JS,
//		  targetControl: "appId",
//		  targetAggregation : "masterPages"	  // this defines whether the target view is a [pages/content/masterpages/detailpages]  
//
//		  },  
//		 {  
//		  pattern : ["EmployeeLeaveHisotry", "detail"],  
//		  name : "detail",  
//		  view : "detail",  
//		  viewType : sap.ui.core.mvc.ViewType.JS,
//		  targetControl: "appId",
//		  targetAggregation : "detailPages"  
//		  },  
//		 ]  
//		  }  
//		  },    
		  
//		  init : function () {  
//			  // 1. some very generic requires  
//			   jQuery.sap.require("sap.m.routing.RouteMatchedHandler");  
//			   jQuery.sap.require("zhcm_leave_check.MyRouter");  
//			   // 2. call overridden init (calls createContent)  
//			   sap.ui.core.UIComponent.prototype.init.apply(this, arguments);  
//			 // 3a. monkey patch the router  
//			   var router = this.getRouter();  
//			   router.myNavBack = zhcm_leave_check.MyRouter.myNavBack;  
//			   // 4. initialize the router  
//			   this.routeHandler = new sap.m.routing.RouteMatchedHandler(router);  
//			   router.register("router");
//			   router.initialize();  
//			   },  
//			   
//			   destroy : function () {  
//			   if (this.routeHandler) {  
//			   this.routeHandler.destroy();  
//			   }  
//			   // call overridden destroy  
//			   sap.ui.core.UIComponent.prototype.destroy.apply(this, arguments);  
//			   },  
			
	createContent : function() {
		var oView = sap.ui.view({
			id : "app",
			viewName : "zhcm_leave_check.view.main",
			type : "JS",
			viewData : { component : this }
		});
		
		var sUrl1 = "/sap/opu/odata/sap/zhcm_leave_check_srv/";
		var oModel = new sap.ui.model.odata.ODataModel(sUrl1, false);
//		sap.ui.getCore().setModel(oModel);
//    sap.ui.getCore().byId("EmployeeList").setModel(oModel,"data");
		oView.setModel(oModel, "data")
		return oView;
	}
	
});

MyRouter.js

jQuery.sap.declare("zhcm_leave_check.MyRouter");  
zhcm_leave_check.MyRouter = {  
  /*  * to monkey patch the router with the mobile nav back handling 
  */  
  myNavBack : function (route, data) {  
  var history = sap.ui.core.routing.History.getInstance();  
  var url = this.getURL(route, data);  
  var direction = history.getDirection(url);  
  if ("Backwards" === direction) {  
  window.history.go(-1);  
  } else {  
  var replace = true; // otherwise we go backwards with a forward history  
  this.navTo(route, data, replace);  
  }  
  },  
};  

In view folder which is under WebContent:

main.view.js

sap.ui.jsview("zhcm_leave_check.view.main", {
	getControllerName : function() {
		return "zhcm_leave_check.view.main";
	},

	createContent : function(oController) {
		
		this.setDisplayBlock(true);
		this.app = new sap.m.SplitApp("splitapp"
//				, {
//			afterDetailNavigate: function(){
//				this.hideMaster();
//			}
//		}
		);
		
		var oPage = new sap.m.Page("mainPage", {
			title : "Department Leave History",
			showNavButton : true,
			navButtonPress : function(e){
				window.history.go(-1);
			},
		});
		
		this.app.addDetailPage(sap.ui.jsview(
				"zhcm_leave_check.view.detail", 
				"zhcm_leave_check.view.detail"));
		
		// Inbox-View as Master
		this.app.addMasterPage(sap.ui.jsview(
				"zhcm_leave_check.view.employeelist", 
				"zhcm_leave_check.view.employeelist"));
		
		// Add Views to Master
		this.app.toDetail("zhcm_leave_check.view.detail");
		this.app.toMaster("zhcm_leave_check.view.employeelist");
	
		oPage.addContent(this.app);
      	return oPage;
	}
});

main.controller.js is empty

Master View employeelist.view.js

sap.ui.jsview("zhcm_leave_check.view.employeelist", { 
	getControllerName : function() {
		return "zhcm_leave_check.view.employeelist";
	},

	createContent : function(oController) {
		var oList = new sap.m.List("EmployeeList",{
//			mode: jQuery.device.is.phone ? 
//			 sap.m.ListMode.None : sap.m.ListMode.SingleSelectMaster,
//			select : function(){oController.itemSelected(); },
			includeItemInSelection: true,
			inset: true,
			itemPress : function(oEvent){
				oController.onSelect(oEvent);}
		});
		
		oTemplate = new sap.m.StandardListItem("idItems", {
			title : "{data>EmployeeName}",
			description: "{data>EmployeeNumber}",
			type : sap.m.ListType.Navigation
		});
		
		oList.bindAggregation( "items", { 
			 path : "data>/EmployeeListSet",
			 template: oTemplate	 
		});
		
		this.page =  new sap.m.Page("master", {
			title: "Employee List",	
			content: [oList]
		});
 		return this.page;
	}
});

employeelist.controller.js

sap.ui.controller("zhcm_leave_check.view.employeelist", {

	onInit: function() {
//		var sUrl1 = "/sap/opu/odata/sap/zhcm_leave_check_srv";
//		var oModel = new sap.ui.model.odata.ODataModel(sUrl1, false);
		var oModel = sap.ui.getCore().getModel("data");
//		console.log(oModel);
		sap.ui.getCore().byId("EmployeeList").setModel(oModel,"data");
	//	this.router = sap.ui.core.UIComponent.getRouterFor(this);  

	},
	
	onSelect: function(oEvent){
		
		var oItemSelect = oEvent.getParameter("listItem");
		console.log(oItemSelect);
		var Context = oItemSelect.getBindingContext("data");
		console.log(Context);
		var EmpID = Context.getProperty("EmployeeNumber");
		console.log(EmpID);
 		
//		var sUrl2 = "/sap/opu/odata/sap/zhcm_leave_check_srv";
//		var oModel2 = new sap.ui.model.odata.ODataModel(sUrl2, false);
		var oModel = sap.ui.getCore().getModel("data");
		oTable = sap.ui.getCore().byId("EmployeeLeave");
		oTable.setModel(oModel);
		
//		this.oRouter = sap.ui.core.routing.Router.getRouter("router");  
//		this.oRouter.navTo("detail", {EmployeeNumber: EmpID});	

			
//		var oFilter = new sap.ui.model.Filter("/EmployeeLeaveDetailSet", sap.ui.model.FilterOperator.EQ, "EmployeeNumber", EmpID);
//		console.log(oFilter);
//		var colItems = sap.ui.getCore().byId("colItems");
//		oTable.bindAggregation("items","/EmployeeLeaveDetailSet",colItems, [oFilter]);
//		
	},

//	onBeforeRendering: function() {
//
//	},

//	onAfterRendering: function() {
//
//	},
 
//	onExit: function() {
//
//	}   	
});

Detail View detail.view.js

sap.ui.jsview("zhcm_leave_check.view.detail", {

	/** Specifies the Controller belonging to this View. 
	* In the case that it is not implemented, or that "null" is returned, this View does not have a Controller.
	* @memberOf view.detail
	*/ 
	getControllerName : function() {
		return "zhcm_leave_check.view.detail";
	},

	/** Is initially called once after the Controller has been instantiated. It is the place where the UI is constructed. 
	* Since the Controller is given to this method, its event handlers can be attached right away. 
	* @memberOf view.detail
	*/ 
	createContent : function(oController) {
		
		var oTable = new sap.m.Table("EmployeeLeave",  {		
			inset : true,
			headerText : "List of Absences",
			headerDesign : sap.m.ListHeaderDesign.Standard, 
			mode : sap.m.ListMode.None, 		
			includeItemInSelection : false, 		
			});
		
		oTable.addColumn(new sap.m.Column({
	           header: new sap.ui.commons.Label({text: "Employee Number"}),
//	            template: new sap.ui.commons.TextField().bindProperty("value", "EmployeeNumber"),
	            sortProperty: "EmployeeNumber",
	            filterProperty: "EmployeeNumber"
	        }));
		
		oTable.addColumn(new sap.m.Column({
	           header: new sap.ui.commons.Label({text: "Leave ID"}),
//	            template: new sap.ui.commons.TextField().bindProperty("value", "LeaveID"),
	            sortProperty: "LeaveID"
	        }));
		
		
		oTable.addColumn(new sap.m.Column({
	           header: new sap.ui.commons.Label({text: "Leave Type"}),
//	            template: new sap.ui.commons.TextField().bindProperty("value", "LeaveText"),
	            sortProperty: "LeaveText"
	        }));
		
		oTable.addColumn(new sap.m.Column({
				header: new sap.m.Label({text: "Start Date"}),
//           template: new sap.ui.commons.TextField().bindProperty("value", "StartDate"),
            sortProperty: "StartDate"
        }));
		
		oTable.addColumn(new sap.m.Column({
            header: new sap.m.Label({text: "End Date"}),
//           template: new sap.ui.commons.TextField().bindProperty("value", "EndDate"),
            sortProperty: "EndDate"
        }));
		
		oTable.addColumn(new sap.m.Column({
            header: new sap.m.Label({text: "Start Time"}),
//          template: new sap.ui.commons.TextField().bindProperty("value", "StartTime"),
            sortProperty: "StartTime"
        }));
		
		oTable.addColumn(new sap.m.Column({
            header: new sap.ui.commons.Label({text: "End Time"}),
 //          template: new sap.ui.commons.TextField().bindProperty("value", "EndTime"),
            sortProperty: "EndTime"
        }));
		
		oTable.addColumn(new sap.m.Column({
           header: new sap.ui.commons.Label({text: "Absent Days"}),
 //           template: new sap.ui.commons.TextField().bindProperty("value", "AbsentDays"),
            sortProperty: "AbsentDays"
        }));
		
		oTable.addColumn(new sap.m.Column({
            header: new sap.m.Label({text: "Absent Hours"}),
 //           template: new sap.ui.commons.TextField().bindProperty("value", "AbsentHours"),
            sortProperty: "AbsentHours"
        }));
		
//		 Table Column Items
		var colItems = new sap.m.ColumnListItem("colItems",{type:"Active"});
		
		var txtNAME = new sap.m.Text("txtNAME",{text:"{EmployeeNumber}"});
		colItems.addCell(txtNAME);
		
		var txtNAME1 = new sap.m.Text("txtNAME1",{text:"{LeaveID}"});
		colItems.addCell(txtNAME1); 
		
		var txtNAME2 = new sap.m.Text("txtNAME2",{text:"{LeaveText}"});
		colItems.addCell(txtNAME2); 
				
		var txtNAME3 = new sap.m.Text("txtNAME3",{text:"{StartDate}"});
		colItems.addCell(txtNAME3); 
				
		var txtNAME4 = new sap.m.Text("txtNAME4",{text:"{EndDate}"});
		colItems.addCell(txtNAME4); 
		
		var txtNAME5 = new sap.m.Text("txtNAME5",{text:"{StartTime}"});
		colItems.addCell(txtNAME5); 
		
		var txtNAME6 = new sap.m.Text("txtNAME6",{text:"{EndTime}"});
		colItems.addCell(txtNAME6); 
		
		var txtNAME7 = new sap.m.Text("txtNAME7",{text:"{AbsentDays}"});
		colItems.addCell(txtNAME7);
		
		var txtNAME8 = new sap.m.Text("txtNAME8",{text:"{AbsentHours}"});
		colItems.addCell(txtNAME8);
		
////		oFilter = sap.ui.getCore().byId("Filter");
//		var oFilter = new sap.ui.model.Filter("/EmployeeLeaveDetailSet", sap.ui.model.FilterOperator.EQ, "EmployeeNumber", EmpID);
//		oTable.bindAggregation("items","/EmployeeLeaveDetailSet",colItems, [oFilter]);
//		
		
 		return new sap.m.Page("detail", {
			title: "Employee Leave History",
			content: [oTable]
		});
	}

});

detail.controller.js is empty.

2
Too much text, too little useful information. To get help, you should tell what result are you trying to achieve, how you have tried to achieve the desired result (share the relevant code), what is the error you face and what action you did when you got the error. Otherwise, people would have to guess.keshet
I will reiterate the result I am trying to achieve. I am building a splitApp where a list of employees and ID numbers will be populated in my master view from an oData service created in our SAP ERP system. (I successfully pull this info with my data binding). When a list item is selected, I want a table to be populated with recent absences of the employee in the detail view from the same service but different entity set. I edited the original post to have code.Kristen
I will also reiterate what issues I am facing now. I am struggling with passing the ID to the detail view and setting up the oData service with the ID as a filter. I read routing can achieve this value pass, but when I try to incorporate routing in my code I get an error "Uncaught TypeError: t.createContent is not a function". I thought I wasn't getting the concept so I went back to all the tutorials and I get the same error when I modify tutorial code to be a splitApp versues an App.Kristen

2 Answers

0
votes

I want a Badge for reading this MUCH Information!!! As far as I can see you are missing to bind the aggregation "items" to your detail-page. These few steps are necessary for lists/tables:

  1. Columns

            var oColumns = [
                new sap.m.Column({
                    hAlign: "Left",
                    header: new sap.m.Label({
                        text: "Pernr"   
                }),
                    minScreenWidth: "Tablet"
                }), new sap.m.Column({
                    hAlign: "Left",
                    header: new sap.m.Label({
                        text: "Name"    
                }),
                    minScreenWidth: "Tablet"
                })
            ];
    
  2. Table

            var oTable = new sap.m.Table({
                columns: oColumns,
                growing: true,
                growingThreshold: 5,
                mode: sap.m.ListMode.MultiSelect
            });
    
  3. Templates

            var oTemplate = new sap.m.ColumnListItem({
                vAlign: "Middle",
                cells: [
                    new sap.m.Text({
                        text: "{Pernr}"
            }), new sap.m.Text({
                        text: "{Name}"
                    })
                ]
            });
    
  4. Item Aggregation Binding (Missing in your Detail view)

            oTable.bindAggregation("items", {
                path: "/d/results", // <-- may differ in your Scenario, if SAP-Service, /d/results might be fine!
                template: oTemplate
            });
    

Another hint is to use the SAP WEB IDE, there also exists a Trial Version if you don't have HCP in place, where you can simply build your example out of a preset template by only selecting the odata fields and the IDE is writing the code for you. This might help to see how to develop the way sap meant it to be.

0
votes

I was able to get this project to work with routing. So I successfully passed a variable from the detail view to the master view. I had trouble sending the filter parameter to the back end with oTable.bindAggregation. The table IT_FILTER_SELECT_OPTIONS in the SAP back end was empty. But using a filter parameter with oTable.bindItems worked to send the filter to the back end table IT_FILTER_SELECT_OPTIONS.

Though I got the program to work, I can not put this in my fiori launch pad because still get the error "Uncaught TypeError: t.createContent is not a function" when I try to incorporate a Component.js file. I am also working with the demo from the blog http://scn.sap.com/community/developer-center/front-end/blog/2015/02/16/navigation-between-views-using-routing-and-parameter-passing-between-views This demo uses routing and a Component.js file. But when I try to modify this demo to be splitApp rather than App, I still get the same error "Uncaught TypeError: t.createContent is not a function". So I suppose I must be missing something when it comes to using a splitApp, routing and Component.js together.