티스토리 뷰

SAPUI5

Step 19: Reuse Dialogs

선즈반 2018. 12. 19. 18:22

step 설명

이번 스텝에서는 재사용 컨셉을 확장하고 component 레벨에서 dialog를 호출합니다.

스텝 16에서 fragment를 통해 dialog를 생성했고 전체 app 또는 view에서 재사용할 수 있도록 만들었습니다. 그러나 HelloPanel view의 controller에 dialog 인스턴스 검색하고 각각 이것을 열고 닫기 위한 로직을 배치했습니다. 이 접근방식을 고수한다면 dialog가 필요한 각각의 view의 controller에 코드를 복사하고 붙여넣기를 해야 합니다. 이는 우리가 피하고 싶은 원하지 않는 코드 반복을 야기할 수 있습니다.

이번 스텝에서 이 문제에 대해 해결책을 구현합니다.재사용 컨셉을 확장하고 component 레벨에서 dialog를 호출합니다.

Preview

dialog는 component에 의해 열려져 있습니다(이전 스텝과 보이는건 변하지 않았습니다.)

webapp/Component.js

sap.ui.define([
	"sap/ui/core/UIComponent",
	"sap/ui/model/json/JSONModel",
	"sap/ui/demo/walkthrough/controller/HelloDialog"

], function (UIComponent, JSONModel, HelloDialog) {
	"use strict";
	return UIComponent.extend("sap.ui.demo.walkthrough.Component", {
		metadata : {
			manifest : "json"
		},
		init : function () {
			// call the init function of the parent
			UIComponent.prototype.init.apply(this, arguments);
			// set data model
			var oData = {
				recipient : {
					name : "World"
				}
			};
			var oModel = new JSONModel(oData);
			this.setModel(oModel);

			// set dialog
			this._helloDialog = new HelloDialog(this.getRootControl());
		},


		exit : function() {
			this._helloDialog.destroy();
			delete this._helloDialog;
		},

		openHelloDialog : function () {
			this._helloDialog.open();
		}
	});
});

dialog 인스턴스화는 component의 전용 속성에 저장된 새로운 helper 객체로 리팩토링됩니다. helper 객체를 인스턴스화 하려면 dialog가 추가된 view 인스턴스를 전달해야만 합니다.(아래의 helper 객체 HelloDialog.js의 구현에서 addDependent 메소드 호출을 참조하십시오) 

app root view의 라이프사이클에 재사용 dialog를 연결하여 root view의 인스턴스를 생성자에 전달합니다. component의 getRootControl 메소드를 호출함으로써 검색할 수 있습니다.

다른 컨트롤러로부터 dialog를 열 수 있도록 helper 객체의 open 메소드를 호출하는 재사용 함수 openHelloDialog  구현합니다. 그렇게함으로써 application 코딩과 재사용 dialog의 구현 디테일을 분리합니다.

component에 새로운 속성 _helloDialog 을 추가하고 HelloDialog 객체의 인스턴스를 할당했습니다. helper 객체에 할당된 메모리가 component가 소멸될 때 해제되는지 확인하려고 합니다. 그렇지 않으면 application에서 메모리 누수가 발생할 수 있습니다.

그래서  exit hook을 사용합니다. SAPUI5 프레임워크는 component가 소멸될 때 exit에 할당된 함수를 호출합니다. HelloDialog 의 destory 함수를 호출하여 helper 클래스를 정리하고 라이프사이클을 종료합니다. 그럼에도 불구하고 인스턴스는 브라우저 메모리에 존재합니다. 그러므로 delete this._helloDialog를 호출해서 HelloDialog  인스턴스에 대한 참조를 삭제하고 브라우저의 가비지 컬렉션은 메모리를 정리할 수 있습니다.

webapp/controller/HelloDialog.js (New)

sap.ui.define([
	"sap/ui/base/ManagedObject",
	"sap/ui/core/Fragment"
], function (ManagedObject, Fragment) {
	"use strict";

	return ManagedObject.extend("sap.ui.demo.walkthrough.controller.HelloDialog", {

		constructor : function (oView) {
			this._oView = oView;
		},

		exit : function () {
			delete this._oView;
		},

		open : function () {
			var oView = this._oView;

			// create dialog lazily
			if (!oView.byId("helloDialog")) {
				var oFragmentController = {
					onCloseDialog : function () {
						oView.byId("helloDialog").close();
					}
				};
				// load asynchronous XML fragment
				Fragment.load({
					id: oView.getId(),
					name: "sap.ui.demo.walkthrough.view.HelloDialog",
					controller: oFragmentController
				}).then(function (oDialog) {
					// connect dialog to the root view of this component (models, lifecycle)
					oView.addDependent(oDialog);
					oDialog.open();
				});
			} else {
				oView.byId("helloDialog").open();
			}
		}

	});

});

재사용 객체인 HelloDialog 의 구현은 SAPUI5의 코어 기능의 일부를 상속받아 sap.ui.base.ManagedObject 객체를 확장합니다.

open 메소드는 HelloPanel 컨트롤러에서 리팩토링되고 이전 스텝에서와 같이 dialog fragment를 인스턴스화합니다.


open 메소드가 dialog 인스턴스에 포함됩니다. open 메소드가 처음 호출되면 dialog가 인스턴스화됩니다. 이 메소드의 oView 인자는 현재 view를 dialog에 연결하는데 사용됩니다. 나중에 이 객체의  open 메소드를 컨트롤러에서 호출합니다.

이벤트 핸들러 onCloseDialog는 HelloPanel 컨트롤러에서 재사용 객체로 간단하게 옮겨집니다.

component에 했던것처럼 객체가 소멸될 때 자동으로 호출되는 exit 함수를 추가합니다. helper 객체에 할당된 모든 메모리를 비우기 위해 view에 참조를 가지고 있는 프로퍼티를 삭제합니다. view는 component에 의해 소멸되므로 신경쓸 필요가 없습니다.

webapp/controller/HelloPanel.controller.js

sap.ui.define([
	"sap/ui/core/mvc/Controller",
	"sap/m/MessageToast"
], function (Controller, MessageToast) {
	"use strict";
	return Controller.extend("sap.ui.demo.walkthrough.controller.HelloPanel", {
		onShowHello : function () {
			// read msg from i18n model
			var oBundle = this.getView().getModel("i18n").getResourceBundle();
			var sRecipient = this.getView().getModel().getProperty("/recipient/name");
			var sMsg = oBundle.getText("helloMsg", [sRecipient]);
			// show message
			MessageToast.show(sMsg);
		},
		onOpenDialog : function () {
			this.getOwnerComponent().openHelloDialog();
		}
	});
});

onOpenDialog 메소드는 helper 메소드 getOwnerComponent 를 호출해서 component에 연결되어 있습니다. 재사용 객체의 메소드 open을 호출할 때 현재 view에서 전달하여 dialog에 연결합니다.

webapp/view/App.view.xml
<mvc:View
	controllerName="sap.ui.demo.walkthrough.controller.App"
	xmlns="sap.m"
	xmlns:mvc="sap.ui.core.mvc"
	displayBlock="true">
	<App class="myAppDemoWT">
		<pages>
			<Page title="{i18n>homePageTitle}">
				<headerContent>
					<Button
						icon="sap-icon://hello-world"
						press=".onOpenDialog"/>
				</headerContent>
				<content>
					<mvc:XMLView viewName="sap.ui.demo.walkthrough.view.HelloPanel"/>
				</content>
			</Page>
		</pages>
	</App>
</mvc:View>

hello world dialog의 재사용을 보여주기 위해 app view 헤더 영역에 버튼을 추가합니다. 버튼을 누르면 이전에 패널에서 만든 버튼처럼 dialog가 열립니다.

webapp/controller/App.controller.js
sap.ui.define([
	"sap/ui/core/mvc/Controller"
], function (Controller) {
	"use strict";

	return Controller.extend("sap.ui.demo.walkthrough.controller.App", {

		onOpenDialog : function () {
			this.getOwnerComponent().openHelloDialog();
		}
	});

});

app 컨트롤러에 onOpenDialog 메소드를 추가하여 dialog가 현재 view에 참조로 열리도록 합니다.

Conventions
  • 여러 컨트롤러에서 사용되는 모든 assets(자산)을 별도의 모듈에 배치하십시오.


재사용성(모듈화)을 높이기 위해 설정을 하는 시간이었습니다. 번역을 하면서도 완전한 개념을 이해를 못하겠네요 ㅜㅜ 일단은 재사용성을 높이기 위해 이러한 세팅을 한다라고만 알고 넘어가면 될 거 같습니다. 한 싸이클을 돌고나서 좀 더 이해된 상태로 풀이를 적도록 하겠습니다.

댓글