Skip to Content
0

SAPUI5 Master Detail Template App - Multiple EntitySets, data binding

Nov 17, 2017 at 12:37 PM

384

avatar image

I have created a Master Detail template app in Web IDE. (See image)

I have an OData service (ZSV_SURVEY_SRV) with many EntitySets.

Master (left side) calls my EntitySet SurveySet and loads all Surveys found.

Detail (right side) calls my EntitySet QuestionSet and I've just currently got it so it loads all Questions found. What I really need to do is bring back only the Questions specific to the Survey selected in the Master section.

It's the first time I've used the Master Detail app template and I'm a little lost with to pull data from one EntitySet that is related to data in another EntitySet.

Tried different variations of binding, but just have it set back to read all from the QuestionSet for now.


Detail View:

<mvc:View xmlns="sap.m" xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc" xmlns:l="sap.ui.layout" xmlns:f="sap.ui.layout.form"
	xmlns:semantic="sap.m.semantic" xmlns:footerbar="sap.ushell.ui.footerbar" controllerName="managesurveys.controller.Detail">
	<semantic:DetailPage id="page" navButtonPress="onNavBack" showNavButton="{device>/system/phone}" title="{Name}" busy="{detailView>/busy}"
		busyIndicatorDelay="{detailView>/delay}">
		<semantic:content>
			<!-- Start of Survey Details Form -->
			<f:Form editable="true" class="sapUiSmallMarginTop">
				<f:formContainers>
					<!-- Survey Details -->
					<f:FormContainer>
						<f:formElements>
							<!-- Survey Name -->
							<f:FormElement label="{i18n>surveyName}">
								<f:fields>
									<Input value="{Name}" width="100%" id="__inputSurveyName" liveChange="validateForm"/>
								</f:fields>
							</f:FormElement>
							<!-- Description -->
							<f:FormElement label="{i18n>description}">
								<f:fields>
									<TextArea value="{SurveyDesc}" id="__areaSurveyDescription"/>
								</f:fields>
							</f:FormElement>
						</f:formElements>
					</f:FormContainer>
					<f:FormContainer>
						<f:formElements>
							<f:FormElement label="{i18n>reporting}">
								<f:fields>
									<RadioButtonGroup width="100%" selectedIndex="-1" id="__group0" columns="3">
										<buttons>
											<RadioButton selected="true" text="{i18n>onSubmission}" id="__reportingOnSubmission" select="onReportingSelected"/>
											<RadioButton text="{i18n>onDate}" id="__reportingOnDate" select="onReportingDateSelected"/>
											<RadioButton text="{i18n>none}" id="__reportingNo" select="onNoReportingSelected"/>
										</buttons>
									</RadioButtonGroup>
								</f:fields>
							</f:FormElement>
							<f:FormElement label="" id="__reportDateElement" visible="false">
								<f:fields>
									<DatePicker id="__reportDate" placeholder="{i18n>enterDate}" change="onReportingDateChange"/>
								</f:fields>
							</f:FormElement>
						</f:formElements>
					</f:FormContainer>
				</f:formContainers>
				<f:layout>
					<f:ResponsiveGridLayout/>
				</f:layout>
			</f:Form>
			<!-- Categories -->
			<!--<IconTabBar items="{/CategorySet}" id="iconTabBar" enableTabReordering="true" class="sapUiResponsiveContentPadding" expandable="false">-->
				<!--<items>-->
					<!--<IconTabFilter text="{CategoryDesc}">-->
						<List  id="list" mode="SingleSelectMaster" delete="handleDelete" items="{path:'/QuestionSet', templateShareable:true}"
							includeItemInSelection="true" selectionChange="onQuestionSelect" headerText="{i18n>questions}">
							<CustomListItem>
								<l:Grid>
									<Text text="ID ({SurveyId}) - Question ({QuestionDesc})"
										class="sapUiTinyMarginTop sapUiLargeMarginBegin">
										<layoutData>
											<l:GridData span="XL9 L9 M9 S9"/>
										</layoutData>
									</Text>
									<Button icon="sap-icon://navigation-up-arrow">
										<layoutData>
											<l:GridData span="XL1 L1 M1 S1"/>
										</layoutData>
									</Button>
									<Button icon="sap-icon://navigation-down-arrow">
										<layoutData>
											<l:GridData span="XL1 L1 M1 S1"/>
										</layoutData>
									</Button>
									<Button icon="sap-icon://delete" type="Reject">
										<layoutData>
											<l:GridData span="XL1 L1 M1 S1"/>
										</layoutData>
									</Button>
								</l:Grid>
							</CustomListItem>
						</List>
					<!--</IconTabFilter>-->
				<!--</items>-->
			<!--</IconTabBar>-->
		</semantic:content>
		<!-- Footer -->
		<semantic:positiveAction>
			<semantic:PositiveAction text="{i18n>btnSaveSurvey}" id="btnSurveySave" press="onSaveSurvey" enabled="false"/>
		</semantic:positiveAction>
	</semantic:DetailPage>
</mvc:View>

Detail Controller:

/*global location */
/* gLobal underscore: true */
sap.ui.define([
	"managesurveys/controller/BaseController",
	"sap/ui/model/json/JSONModel",
	"managesurveys/model/formatter",
	"sap/m/MessageBox",
	"sap/m/MessageToast",
	"managesurveys/libs/underscore"
], function(BaseController, JSONModel, formatter, MessageBox, MessageToast, UnderScoreJS) {
	"use strict";


	return BaseController.extend("managesurveys.controller.Detail", {


		formatter: formatter,


		/* =========================================================== */
		/* lifecycle methods                                           */
		/* =========================================================== */


		onInit: function() {
			// Model used to manipulate control states. The chosen values make sure,
			// detail page is busy indication immediately so there is no break in
			// between the busy indication for loading the view's meta data
			var oViewModel = new JSONModel({
				busy: false,
				delay: 0,
				questions: [{
					order: 1,
					title: "",
					criteria: "",
					category: "",
					competency: "",
					showScore: false,
					addImage: false,
					questionType: 0,
					minimumCommentsLength: 10,
					additionalQuestionTitle: "1",
					additionalQuestionDesc: "2",
					additionalQuestionType: 1,
					numberOfAnswers: 3,
					answers: [{
						sequence: 1,
						label: "Yes",
						points: 2,
						imageFlag: false,
						image: "/images/happy-1.svg",
						mandatoryComments: false,
						additionalQuestion: false
					}, {
						sequence: 2,
						label: "No",
						points: 0,
						imageFlag: false,
						image: "/images/sceptic.svg",
						mandatoryComments: false,
						additionalQuestion: false
					}, {
						sequence: 3,
						label: "N/A",
						points: -2,
						imageFlag: false,
						image: "/images/angry-2.svg",
						mandatoryComments: false,
						additionalQuestion: false
					}]
				}]
			});
			


			this.getRouter().getRoute("object").attachPatternMatched(this._onObjectMatched, this);


			this.setModel(oViewModel, "detailView");


			this.getOwnerComponent().getModel().metadataLoaded().then(this._onMetadataLoaded.bind(this));
		},


		/* =========================================================== */
		/* begin: internal methods                                     */
		/* =========================================================== */


		/**
		 * Binds the view to the object path and expands the aggregated line items.
		 * @function
		 * @param {sap.ui.base.Event} oEvent pattern match event in route 'object'
		 * @private
		 */
		_onObjectMatched: function(oEvent) {
			var sObjectId = oEvent.getParameter("arguments").objectId;
			this.getModel().metadataLoaded().then(function() {
				var sObjectPath = this.getModel().createKey("SurveySet", {
					SurveyId: sObjectId
				});
				this._bindView("/" + sObjectPath);
			}.bind(this));
		},


		/**
		 * Binds the view to the object path. Makes sure that detail view displays
		 * a busy indicator while data for the corresponding element binding is loaded.
		 * @function
		 * @param {string} sObjectPath path to the object to be bound to the view.
		 * @private
		 */
		_bindView: function(sObjectPath) {
			// Set busy indicator during view binding
			var oViewModel = this.getModel("detailView");


			// If the view was not bound yet its not busy, only if the binding requests data it is set to busy again
			oViewModel.setProperty("/busy", false);


			this.getView().bindElement({
				path: sObjectPath,
				events: {
					change: this._onBindingChange.bind(this),
					dataRequested: function() {
						oViewModel.setProperty("/busy", true);
					},
					dataReceived: function() {
						oViewModel.setProperty("/busy", false);
					}
				}
			});
		},


		_onBindingChange: function() {
			var oView = this.getView(),
				oElementBinding = oView.getElementBinding();


			// No data for the binding
			if (!oElementBinding.getBoundContext()) {
				this.getRouter().getTargets().display("detailObjectNotFound");
				// if object could not be found, the selection in the master list
				// does not make sense anymore.
				this.getOwnerComponent().oListSelector.clearMasterListSelection();
				return;
			}


			var sPath = oElementBinding.getPath(),
				oResourceBundle = this.getResourceBundle(),
				oObject = oView.getModel().getObject(sPath),
				sObjectId = oObject.SurveyId,
				sObjectName = oObject.SurveyDesc,
				oViewModel = this.getModel("detailView");


			this.getOwnerComponent().oListSelector.selectAListItem(sPath);


			oViewModel.setProperty("/saveAsTileTitle", oResourceBundle.getText("shareSaveTileAppTitle", [sObjectName]));
			oViewModel.setProperty("/shareOnJamTitle", sObjectName);
			oViewModel.setProperty("/shareSendEmailSubject",
				oResourceBundle.getText("shareSendEmailObjectSubject", [sObjectId]));
			oViewModel.setProperty("/shareSendEmailMessage",
				oResourceBundle.getText("shareSendEmailObjectMessage", [sObjectName, sObjectId, location.href]));
		},


		_onMetadataLoaded: function() {
			// Store original busy indicator delay for the detail view
			var iOriginalViewBusyDelay = this.getView().getBusyIndicatorDelay(),
				oViewModel = this.getModel("detailView");


			// Make sure busy indicator is displayed immediately when
			// detail view is displayed for the first time
			oViewModel.setProperty("/delay", 0);


			// Binding the view will set it to not busy - so the view is always busy if it is not bound
			oViewModel.setProperty("/busy", true);
			// Restore original busy indicator delay for the detail view
			oViewModel.setProperty("/delay", iOriginalViewBusyDelay);
		},


		// Question radio button selected, ready for delete question 
		onQuestionSelect: function(oEvent) {
			console.log("Question Selected");
			this.getView().byId("btnSurveySave").setEnabled(true);
			
			var oRouter = sap.ui.core.UIComponent.getRouterFor(this);
			oRouter.navTo("questiondetails");
			
			
            //var oContext = oEvent.getParameters().listItem.getBindingContext(this.MODEL_SITE);
            //var oData = oContext.getModel().getProperty(oContext.getPath());
            //this.getRouter().navTo("QuestionDetails", {QuestionId: oData.QuestionId});
		},


		// Delete Question Message Box	
		onDeleteQuestion: function() {
			var that = this;
			var oViewModel = this.getModel("masterView");
			MessageBox.show("Are you sure you want to delete this Question?", {
				icon: MessageBox.Icon.ERROR,
				title: "Delete Question",
				actions: [MessageBox.Action.YES, MessageBox.Action.NO],
				onClose: function(oAction) {
					if (oAction === MessageBox.Action.YES) {
						that.getModel().remove("/SurveySet", {
							SurveyId: oViewModel.SurveyId
						}, {
							success: function() {
								MessageToast.show("Survey successfully deleted", {
									duration: 2000
								});
							},
							error: function() {
								MessageToast.show("Error deleting Survey", {
									duration: 2000
								});
							}
						});
					}
				}
			});
		},


		// Save Survey
		onSaveSurvey: function() {
			MessageToast.show("Survey successfully saved", {
				duration: 2000
			});
		}


	});


});
rsa-app.jpeg (160.3 kB)
10 |10000 characters needed characters left characters exceeded
* Please Login or Register to Answer, Follow or Comment.

1 Answer

Irfan Gokak Nov 20, 2017 at 10:19 AM
0

Hi,

In below code you're getting SurveyId and passing it also. Then what error you're getting?

_onObjectMatched: function(oEvent) {
			var sObjectId = oEvent.getParameter("arguments").objectId;
			this.getModel().metadataLoaded().then(function() {
				var sObjectPath = this.getModel().createKey("SurveySet", {
					SurveyId: sObjectId
				});
				this._bindView("/" + sObjectPath);
			}.bind(this));
		},
Share
10 |10000 characters needed characters left characters exceeded