【发布时间】:2017-11-17 12:35:40
【问题描述】:
我在 Web IDE 中创建了一个主从模板应用程序。 (见图)
我有一个包含许多实体集的 OData 服务 (ZSV_SURVEY_SRV)。
Master(左侧)调用我的 EntitySet SurveySet 并加载找到的所有调查。
Detail(右侧)调用我的 EntitySet QuestionSet,而我目前刚刚得到它,因此它会加载找到的所有问题。我真正需要做的是只带回在主部分中选择的特定于调查的问题。
这是我第一次使用 Master Detail 应用程序模板,我有点不知所措,无法从一个 EntitySet 中提取与另一个 EntitySet 中的数据相关的数据。
尝试了不同的绑定变体,但现在只需将其设置为从 QuestionSet 中读取所有内容。
详细视图:
<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>
细节控制器:
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) { “使用严格”;
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
});
}
});
});
【问题讨论】:
-
如果您不熟悉整个 Master Detail 概念,只需在网络上搜索教程和示例即可。有很多,这个网站不是教程。例如。本教程:blogs.sap.com/2016/11/28/… 另外我认为您没有多个 odata 服务。你只有两个实体集?您的具体问题可能是由错误的数据绑定引起的。如果您发布截取详细视图的代码,人们也可以更好地帮助您
-
嗨,Thomas,是的,我的意思是两个实体集,我急于在午餐前发布此内容:) 我也会用一些示例代码对其进行更新。
-
主屏幕和详细屏幕应该只有一个模型:SurveySet?$expand=QuestionSet。正如 Thomas 所说,网上有很多教程可以做到这一点。
-
$expand 会从所有调查中获取所有问题,这代表不必要的超载