Master.controller.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. sap.ui.define([
  2. "./BaseController",
  3. "sap/ui/model/json/JSONModel",
  4. "sap/ui/model/Filter",
  5. "sap/ui/model/FilterOperator",
  6. "sap/ui/model/Sorter",
  7. "sap/m/GroupHeaderListItem",
  8. "sap/ui/Device",
  9. "sap/ui/core/Fragment",
  10. "../model/formatter",
  11. "sap/ui/core/format/DateFormat"
  12. ], function (BaseController, JSONModel, Filter, FilterOperator, Sorter, GroupHeaderListItem, Device, Fragment, formatter, DateFormat) {
  13. "use strict";
  14. return BaseController.extend("sap.ui.demo.orderbrowser.controller.Master", {
  15. formatter: formatter,
  16. /* =========================================================== */
  17. /* lifecycle methods */
  18. /* =========================================================== */
  19. /**
  20. * Called when the master list controller is instantiated. It sets up the event handling for the master/detail communication and other lifecycle tasks.
  21. * @public
  22. */
  23. onInit : function () {
  24. // Control state model
  25. var oList = this.byId("list"),
  26. oViewModel = this._createViewModel(),
  27. // Put down master list's original value for busy indicator delay,
  28. // so it can be restored later on. Busy handling on the master list is
  29. // taken care of by the master list itself.
  30. iOriginalBusyDelay = oList.getBusyIndicatorDelay();
  31. this._oGroupFunctions = {
  32. CompanyName: function (oContext) {
  33. var sCompanyName = oContext.getProperty("Customer/CompanyName");
  34. return {
  35. key: sCompanyName,
  36. text: sCompanyName
  37. };
  38. },
  39. OrderDate: function (oContext) {
  40. var oDate = oContext.getProperty("OrderDate"),
  41. iYear = oDate.getFullYear(),
  42. iMonth = oDate.getMonth() + 1,
  43. sMonthName = this._oMonthNameFormat.format(oDate);
  44. return {
  45. key: iYear + "-" + iMonth,
  46. text: this.getResourceBundle().getText("masterGroupTitleOrderedInPeriod", [sMonthName, iYear])
  47. };
  48. }.bind(this),
  49. ShippedDate: function (oContext) {
  50. var oDate = oContext.getProperty("ShippedDate");
  51. // Special handling needed because shipping date may be empty (=> not yet shipped).
  52. if (oDate != null) {
  53. var iYear = oDate.getFullYear(),
  54. iMonth = oDate.getMonth() + 1,
  55. sMonthName = this._oMonthNameFormat.format(oDate);
  56. return {
  57. key: iYear + "-" + iMonth,
  58. text: this.getResourceBundle().getText("masterGroupTitleShippedInPeriod", [sMonthName, iYear])
  59. };
  60. } else {
  61. return {
  62. key: 0,
  63. text: this.getResourceBundle().getText("masterGroupTitleNotShippedYet")
  64. };
  65. }
  66. }.bind(this)
  67. };
  68. this._oMonthNameFormat = DateFormat.getInstance({ pattern: "MMMM"});
  69. this._oList = oList;
  70. // keeps the filter and search state
  71. this._oListFilterState = {
  72. aFilter : [],
  73. aSearch : []
  74. };
  75. this.setModel(oViewModel, "masterView");
  76. // Make sure, busy indication is showing immediately so there is no
  77. // break after the busy indication for loading the view's meta data is
  78. // ended (see promise 'oWhenMetadataIsLoaded' in AppController)
  79. oList.attachEventOnce("updateFinished", function(){
  80. // Restore original busy indicator delay for the list
  81. oViewModel.setProperty("/delay", iOriginalBusyDelay);
  82. });
  83. this.getView().addEventDelegate({
  84. onBeforeFirstShow: function () {
  85. this.getOwnerComponent().oListSelector.setBoundMasterList(oList);
  86. }.bind(this)
  87. });
  88. this.getRouter().getRoute("master").attachPatternMatched(this._onMasterMatched, this);
  89. this.getRouter().attachBypassed(this.onBypassed, this);
  90. },
  91. /* =========================================================== */
  92. /* event handlers */
  93. /* =========================================================== */
  94. /**
  95. * After list data is available, this handler method updates the
  96. * master list counter
  97. * @param {sap.ui.base.Event} oEvent the update finished event
  98. * @public
  99. */
  100. onUpdateFinished : function (oEvent) {
  101. // update the master list object counter after new data is loaded
  102. this._updateListItemCount(oEvent.getParameter("total"));
  103. },
  104. /**
  105. * Event handler for the master search field. Applies current
  106. * filter value and triggers a new search. If the search field's
  107. * 'refresh' button has been pressed, no new search is triggered
  108. * and the list binding is refresh instead.
  109. * @param {sap.ui.base.Event} oEvent the search event
  110. * @public
  111. */
  112. onSearch : function (oEvent) {
  113. if (oEvent.getParameters().refreshButtonPressed) {
  114. // Search field's 'refresh' button has been pressed.
  115. // This is visible if you select any master list item.
  116. // In this case no new search is triggered, we only
  117. // refresh the list binding.
  118. this.onRefresh();
  119. return;
  120. }
  121. var sQuery = oEvent.getParameter("query");
  122. if (sQuery) {
  123. this._oListFilterState.aSearch = [new Filter("CustomerName", FilterOperator.Contains, sQuery)];
  124. } else {
  125. this._oListFilterState.aSearch = [];
  126. }
  127. this._applyFilterSearch();
  128. },
  129. /**
  130. * Event handler for refresh event. Keeps filter, sort
  131. * and group settings and refreshes the list binding.
  132. * @public
  133. */
  134. onRefresh : function () {
  135. this._oList.getBinding("items").refresh();
  136. },
  137. /**
  138. * Event handler for the filter, sort and group buttons to open the ViewSettingsDialog.
  139. * @param {sap.ui.base.Event} oEvent the button press event
  140. * @public
  141. */
  142. onOpenViewSettings : function (oEvent) {
  143. var sDialogTab = "filter";
  144. if (oEvent.getSource().isA("sap.m.Button")) {
  145. var sButtonId = oEvent.getSource().getId();
  146. if (sButtonId.match("sort")) {
  147. sDialogTab = "sort";
  148. } else if (sButtonId.match("group")) {
  149. sDialogTab = "group";
  150. }
  151. }
  152. // load asynchronous XML fragment
  153. if (!this._pViewSettingsDialog) {
  154. this._pViewSettingsDialog = Fragment.load({
  155. id: this.getView().getId(),
  156. name: "sap.ui.demo.orderbrowser.view.ViewSettingsDialog",
  157. controller: this
  158. }).then(function(oDialog){
  159. // connect dialog to the root view of this component (models, lifecycle)
  160. this.getView().addDependent(oDialog);
  161. oDialog.addStyleClass(this.getOwnerComponent().getContentDensityClass());
  162. return oDialog;
  163. }.bind(this));
  164. }
  165. this._pViewSettingsDialog.then(function(oDialog) {
  166. oDialog.open(sDialogTab);
  167. });
  168. },
  169. /**
  170. * Event handler called when ViewSettingsDialog has been confirmed, i.e.
  171. * has been closed with 'OK'. In the case, the currently chosen filters or groupers
  172. * are applied to the master list, which can also mean that they
  173. * are removed from the master list, in case they are
  174. * removed in the ViewSettingsDialog.
  175. * @param {sap.ui.base.Event} oEvent the confirm event
  176. * @public
  177. */
  178. onConfirmViewSettingsDialog : function (oEvent) {
  179. var aFilterItems = oEvent.getParameter("filterItems"),
  180. aFilters = [],
  181. aCaptions = [];
  182. aFilterItems.forEach(function (oItem) {
  183. switch (oItem.getKey()) {
  184. case "Shipped":
  185. aFilters.push(new Filter("ShippedDate", FilterOperator.NE, null));
  186. break;
  187. case "NotShipped":
  188. aFilters.push(new Filter("ShippedDate", FilterOperator.EQ, null));
  189. break;
  190. default:
  191. break;
  192. }
  193. aCaptions.push(oItem.getText());
  194. });
  195. this._oListFilterState.aFilter = aFilters;
  196. this._updateFilterBar(aCaptions.join(", "));
  197. this._applyFilterSearch();
  198. this._applyGrouper(oEvent);
  199. },
  200. /**
  201. * Apply the chosen grouper to the master list
  202. * @param {sap.ui.base.Event} oEvent the confirm event
  203. * @private
  204. */
  205. _applyGrouper: function (oEvent) {
  206. var mParams = oEvent.getParameters(),
  207. sPath,
  208. bDescending,
  209. aSorters = [];
  210. // apply sorter to binding
  211. if (mParams.groupItem) {
  212. mParams.groupItem.getKey() === "CompanyName" ?
  213. sPath = "Customer/" + mParams.groupItem.getKey() : sPath = mParams.groupItem.getKey();
  214. bDescending = mParams.groupDescending;
  215. var vGroup = this._oGroupFunctions[mParams.groupItem.getKey()];
  216. aSorters.push(new Sorter(sPath, bDescending, vGroup));
  217. }
  218. this._oList.getBinding("items").sort(aSorters);
  219. },
  220. /**
  221. * Event handler for the list selection event
  222. * @param {sap.ui.base.Event} oEvent the list selectionChange event
  223. * @public
  224. */
  225. onSelectionChange : function (oEvent) {
  226. var oList = oEvent.getSource(),
  227. bSelected = oEvent.getParameter("selected");
  228. // skip navigation when deselecting an item in multi selection mode
  229. if (!(oList.getMode() === "MultiSelect" && !bSelected)) {
  230. // get the list item, either from the listItem parameter or from the event's source itself (will depend on the device-dependent mode).
  231. this._showDetail(oEvent.getParameter("listItem") || oEvent.getSource());
  232. }
  233. },
  234. /**
  235. * Event handler for the bypassed event, which is fired when no routing pattern matched.
  236. * If there was an object selected in the master list, that selection is removed.
  237. * @public
  238. */
  239. onBypassed : function () {
  240. this._oList.removeSelections(true);
  241. },
  242. /**
  243. * Used to create GroupHeaders with non-capitalized caption.
  244. * These headers are inserted into the master list to
  245. * group the master list's items.
  246. * @param {Object} oGroup group whose text is to be displayed
  247. * @public
  248. * @returns {sap.m.GroupHeaderListItem} group header with non-capitalized caption.
  249. */
  250. createGroupHeader : function (oGroup) {
  251. return new GroupHeaderListItem({
  252. title : oGroup.text
  253. });
  254. },
  255. /* =========================================================== */
  256. /* begin: internal methods */
  257. /* =========================================================== */
  258. _createViewModel : function() {
  259. return new JSONModel({
  260. isFilterBarVisible: false,
  261. filterBarLabel: "",
  262. delay: 0,
  263. titleCount: 0,
  264. noDataText: this.getResourceBundle().getText("masterListNoDataText")
  265. });
  266. },
  267. _onMasterMatched : function() {
  268. //Set the layout property of the FCL control to 'OneColumn'
  269. this.getModel("appView").setProperty("/layout", "OneColumn");
  270. },
  271. /**
  272. * Shows the selected item on the detail page
  273. * On phones a additional history entry is created
  274. * @param {sap.m.ObjectListItem} oItem selected Item
  275. * @private
  276. */
  277. _showDetail : function (oItem) {
  278. var bReplace = !Device.system.phone;
  279. // set the layout property of FCL control to show two columns
  280. this.getModel("appView").setProperty("/layout", "TwoColumnsMidExpanded");
  281. this.getRouter().navTo("object", {
  282. objectId : oItem.getBindingContext().getProperty("OrderID")
  283. }, bReplace);
  284. },
  285. /**
  286. * Sets the item count on the master list header
  287. * @param {int} iTotalItems the total number of items in the list
  288. * @private
  289. */
  290. _updateListItemCount : function (iTotalItems) {
  291. // only update the counter if the length is final
  292. if (this._oList.getBinding("items").isLengthFinal()) {
  293. this.getModel("masterView").setProperty("/titleCount", iTotalItems);
  294. }
  295. },
  296. /**
  297. * Internal helper method to apply both filter and search state together on the list binding
  298. * @private
  299. */
  300. _applyFilterSearch : function () {
  301. var aFilters = this._oListFilterState.aSearch.concat(this._oListFilterState.aFilter),
  302. oViewModel = this.getModel("masterView");
  303. this._oList.getBinding("items").filter(aFilters, "Application");
  304. // changes the noDataText of the list in case there are no filter results
  305. if (aFilters.length !== 0) {
  306. oViewModel.setProperty("/noDataText", this.getResourceBundle().getText("masterListNoDataWithFilterOrSearchText"));
  307. } else if (this._oListFilterState.aSearch.length > 0) {
  308. // only reset the no data text to default when no new search was triggered
  309. oViewModel.setProperty("/noDataText", this.getResourceBundle().getText("masterListNoDataText"));
  310. }
  311. },
  312. /**
  313. * Internal helper method that sets the filter bar visibility property and the label's caption to be shown
  314. * @param {string} sFilterBarText the selected filter value
  315. * @private
  316. */
  317. _updateFilterBar : function (sFilterBarText) {
  318. var oViewModel = this.getModel("masterView");
  319. oViewModel.setProperty("/isFilterBarVisible", (this._oListFilterState.aFilter.length > 0));
  320. oViewModel.setProperty("/filterBarLabel", this.getResourceBundle().getText("masterFilterBarText", [sFilterBarText]));
  321. }
  322. });
  323. });