상단의 대메뉴를 선택한 후 본문의 왼쪽에 있는 소메뉴를 클릭하면 오른쪽에 본문의 내용이 나온다. 본문을 보기까지의 라우팅(Routing)을 보면 대메뉴 클릭 -> 소메뉴 클릭 -> 본문 으로 이어지는 DOM의 변경이 일어난다. jqGrid, HigChart등의 json 환경 내역을 관리하는 화면을 만들기 위하여 Routing 방식을 고도화 해보자
1. Nest View
- 큰메뉴 -> 작은 메뉴 -> 더 작은 메뉴 -> 본문 식의 View가 내제되어 라우팅 될 경우
- UI-Router 를 이용한 데모, Plunker 데모
- Route-Segment 를 이용한 데모
2. Admin 화면 구성하기
- index.html 메뉴 추가하기
- component에서 jqgrid, highchart와 같은 컴포넌트의 config 값 (json type)을 관리한다
// index.html 메뉴 추가하기
<div class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li data-ng-class="activeWhen(path()=='/')">
<a href="" data-ng-click="setRoute('/')">Home</a>
</li>
.. 중략 ..
<li class="dropdown">
<a href="" class="dropdown-toggle" data-toggle="dropdown">Admin <b class="caret"></b></a>
<ul class="dropdown-menu">
<li class="dropdown-header">Project</li>
<li><a href="">User</a></li>
<li><a href="">Customer</a></li>
<li><a href="">Code</a></li>
<li><a href="">Role</a></li>
<li class="divider"></li>
<li class="dropdown-header">MobiconSoft</li>
<li data-ng-class="activeWhen(path()=='/mc-component')">
<a href="" data-ng-click="setRoute('/mc-component')">Component</a>
</li>
<li><a href="">Dashboard</a></li>
</ul>
</li>
</ul>
</div>
// Component partial 화면과 모듈 생성 및 등록
// 1) MCAdminCtrl.js 모듈을 만들기
// 2) views/mc/component.html 화면 만들기
// 3) DashboardApp.js 에 MCAdminCtrl.js 모듈 명칭 등록하기 : DashboardApp.MCAdminCtrl
// 4) index.html 에 MCAdminCtrl.js 모듈 파일 <script> 태그 추가하기
- 서버 코드로 ComponentController / Component / ComponentService / ComponentMapper(java & xml) 을 만든다
+ compType : grid, chart, option 등 다양하게 존재할 수 있다
// ComponentMapper.xml 에서 : 기존 소스는 typeAlias 사용하였음
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--
id : primary key
$ mysql -u user1 -p DBName
mysql> CREATE TABLE mc_component(
id MEDIUMINT NOT NULL AUTO_INCREMENT,
comp_type VARCHAR(5) NOT NULL,
comp_cfg TEXT NOT NULL,
PRIMARY KEY (id)
);
-->
<mapper namespace="com.mobiconsoft.dashboard.mapper.ComponentMapper">
<resultMap id="component" type="com.mobiconsoft.dashboard.domain.Component" >
<result property="id" column="id"/>
<result property="compType" column="comp_type"/>
<result property="compCfg" column="comp_cfg"/>
</resultMap>
<select id="getComponents" resultType="com.mobiconsoft.dashboard.domain.Component">
SELECT
*
FROM
component
</select>
<select id="getComponent" parameterType="Integer" resultType="com.mobiconsoft.dashboard.domain.Component">
SELECT
*
FROM
component
WHERE
id=#{id}
</select>
<insert id="saveComponent" parameterType="com.mobiconsoft.dashboard.domain.Component"> <!-- useGeneratedKeys="true" keyProperty="id"> -->
INSERT INTO
component(comp_type, comp_cfg)
VALUES
(#{compType}, #{compCfg})
</insert>
<update id="updateComponent" parameterType="com.mobiconsoft.dashboard.domain.Component">
UPDATE
component
SET
comp_type=#{compType},
comp_cfg=#{compCfg}
WHERE
id=#{id}
</update>
<delete id="deleteComponent" parameterType="Integer">
DELETE FROM
component
WHERE
id=#{id}
</delete>
</mapper>
// 서버 전체 파일
3. UI-Router 사용하기
- 관리 메뉴에서 Component를 선택하면 CRUD 할 수있는 메뉴 구조를 본문에서 가져야 한다
- UI-Router를 이용하여 기존의 Routing 환경을 고도화한다
// angular-route 라 반드시 설치되어 있어야 하고, 1.2.* 도 지원함
// bower 설치
$ bower install angular-ui-router --save
bower angular-ui-router#~0.2.0 install angular-ui-router#0.2.0
- index.html에 route-segment 추가하기
<!-- build:js scripts/angular-3.js -->
<script src="bower_components/angular/angular.js"></script>
<script src="bower_components/angular-route/angular-route.js"></script>
<script src="bower_components/angular-ui-router/release/angular-ui-router.js"></script>
.. 중략 ..
<!-- endbuild -->
- DashboardApp.js 메인 소스에 ui-router 모듈을 추가한다 (예제 참조)
var DashboardApp = angular.module('DasbhoardApp', [
'ngRoute',
'ui.router',
.. 중략 ..
'DasbhoardApp.RestfulSvc'
]);
- DashboardApp.js 의 config 에서 $routeProvider를 고도화한다 (소스 참조)
DashboardApp.config(['$stateProvider', '$urlRouterProvider', function ($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise("/main");
$stateProvider
.state('main', {
url: '/main',
templateUrl: 'views/main.html'
})
.state('resttest', {
url: '/resttest',
templateUrl: 'views/restTest.html',
controller: 'RestTestBiz.personCtrl'
})
.state('jqgridtest', {
url: '/jqgridtest',
templateUrl: 'views/jqGridTest.html',
controller: 'JqGridBiz.salesCtrl'
})
.state('mc-component', {
url: '/mc-component',
templateUrl: 'views/mc/component.html',
controller: 'MCAdminCtrl.componentCtrl'
});
}]);
DashboardApp.run(['$rootScope', '$state', '$stateParams',
function ($rootScope, $state, $stateParams) {
// It's very handy to add references to $state and $stateParams to the $rootScope
// so that you can access them from any scope within your applications.For example,
// <li ng-class="{ active: $state.includes('contacts.list') }"> will set the <li>
// to active whenever 'contacts.list' or one of its decendents is active.
$rootScope.$state = $state;
$rootScope.$stateParams = $stateParams;
}]);
- index.html 의 링크 내역 수정 (소스 참조)
+ ui-sref 애프리뷰트 directive 사용으로 routing 되는 정보를 현재 html 페이지의 ui-view 로 연결한다
+ ui-view 애트리뷰트 directive 사용으로 화면이 나타나는 태그 영역
+ 메뉴 active는 $state.includes('<stateName>') 을 이용하여 현재의 state 이면 active로 표현
-즉 한페이지에서 ui-sref와 ui-view를 통해 확장해 가는 방식
<div class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li data-ng-class="{ active: $state.includes('main') }"><a ui-sref="main">Home</a></li>
<li data-ng-class="{ active: $state.includes('resttest') }"><a ui-sref="resttest">RESTTest</a></li>
<li data-ng-class="{ active: $state.includes('jqgridtest') }"><a ui-sref="jqgridtest">jqGridTest</a></li>
<!-- <li data-ng-class="activeWhen(path()=='/')">
<a href="" data-ng-click="setRoute('/')">Home</a>
</li>
<li data-ng-class="activeWhen(path()=='/resttest')">
<a href="" data-ng-click="setRoute('/resttest')">RESTTest</a>
</li>
<li data-ng-class="activeWhen(path()=='/jqgridtest')">
<a href="" data-ng-click="setRoute('/jqgridtest')">jqGridTest</a>
</li> -->
<li class="dropdown">
<a href="" class="dropdown-toggle" data-toggle="dropdown">Admin <b class="caret"></b></a>
<ul class="dropdown-menu">
<li class="dropdown-header">Project</li>
<li><a href="">User</a></li>
<li><a href="">Customer</a></li>
<li><a href="">Code</a></li>
<li><a href="">Role</a></li>
<li class="divider"></li>
<li class="dropdown-header">MobiconSoft</li>
<!-- <li data-ng-class="activeWhen(path()=='/mc-component')">
<a href="" data-ng-click="setRoute('/mc-component')">Component</a>
</li> -->
<li data-ng-class="{ active: $state.includes('mc-component') }"><a ui-sref="mc-component">Component</a></li>
<li><a href="">Dashboard</a></li>
</ul>
</li>
</ul>
</div>
<!-- Add your site or application content here -->
<!-- <div class="container" data-ng-view=""></div> -->
<div ui-view class="container" style="margin-top:30px"></div>
4. Component 관리를 위한 UI-Router 만들기
- component 관리 화면 만들기
+ step-1 : component.html 으로 컴포넌트의 목록을 보여주고 컴포넌트를 선택하면 component.detail.html 이 우측에 표현된다
+ step-2 : component.read.html 로 컴포넌트 상세 정보를 읽거나 업데이트 또는 삭제한다
+ step-3 : component.create.html 로 새로운 컴포넌트 정보를 저장한다
+ step-4 : ComponentMod.js 개발하기 - CRUD Controller와 Service 그리고 index.html에 파일 추가하기
+ step-5 : DashboardApp.js routing 정보 업데이트 및 ComponentMod.js 모듈 추가하기
// index.html 에서 ui-view에 component.html전체가 표현됨
<div ui-view class="container" style="margin-top:30px"></div>
// step-1,2,3) *.html 파일 만들기
// component.html 에서 목록을 받아와서 ng-repeat 하기
<li ng-repeat="component in components"
ng-class="{ active: $state.includes('mc-component.detail') && $stateParams.componentId == component.id }">
<a ui-sref=".detail({componentId:component.id})" style="padding: 2px 2px">{{component.name}}</a>
</li>
.. 중략 ..
// 여기에 component.detail.html 과 component.create.html 내용이 표현됨
<div ui-view></div>
// component.detail.html : value에 값을 표현하기, ng-model을 통하여 controller에서 변경값 처리하기 (create html도 유사함)
<form class="form-horizontal" role="form">
<div class="form-group">
<label class="col-sm-3 control-label"> Name</label>
<div class="col-sm-9">
<input type="text" class="form-control" placeholder="Name" ng-model="component.name" value="{{component.name}}" required>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label"> Type</label>
<div class="col-sm-9">
<input type="text" class="form-control" placeholder="Type" ng-model="component.type" value="{{component.type}}" required>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label"> Config</label>
<div class="col-sm-9">
<textarea class="form-control" id="message" name="message" ng-model="component.cfg" value="{{component.cfg}}"
placeholder="Config" rows="5" required></textarea>
</div>
</div>
<div class="form-group last">
<div class="col-sm-offset-3 col-sm-9">
<button type="submit" class="btn btn-success btn-primary" data-ng-click="update()">Update</button>
<button type="submit" class="btn btn-error btn-primary" data-ng-click="deleteComp()">Delete</button>
</div>
</div>
</form>
- step-4 : CompoonentMod.js 개발
'use strict';
// 모듈 정의
var ComponentMod = angular.module('MobiConSoft.ComponentMod', []);
// ui-router의 서비스 추가
ComponentMod.controller('ComponentMod.componentCtrl', ['$rootScope', '$scope', 'RestfulSvcApi', '$state', '$stateParams', 'componentSvc',
function ($rootScope, $scope, RestfulSvcApi, $state, $stateParams, componentSvc) {
// 서브 화면에서 Create, Delete, Update가 일어나면 목록의 components 를 two-way binding으로 업데이트하기 위함
$scope.$on("updateComponentList", function(event, data){
console.log('--broadcasting data, ', data);
$scope.components = data;
});
var getAll = function() {
console.log('-----all: ', $scope.components);
componentSvc.getAll();
};
var getOne = function() {
console.log('-----one: ', $stateParams.componentId);
RestfulSvcApi.one({ domain: 'component', key: $stateParams.componentId },
function(response) {
console.log('componentCtrl : one data=',response);
$scope.component = response;
},
function(response) {});
};
if($state.current.name === 'mc-component' || (!$stateParams.componentId && !$scope.components)) {
getAll();
};
if($state.current.name === 'mc-component.detail' && $stateParams.componentId) {
getOne();
};
$scope.update = function() {
console.log('componentCtrl : component=', $scope.component);
RestfulSvcApi.update({ domain: 'component'}, $scope.component,
function(response) {
console.log('---update, ', response);
getAll();
},
function(response) {});
};
$scope.deleteComp = function() {
RestfulSvcApi['delete']({ domain: 'component', key: $scope.component.id },
function(response) {
console.log('---delete, ', response);
$scope.component = {};
getAll();
},
function(response) {});
};
$scope.save = function() {
console.log('----> component is ', $scope.component);
RestfulSvcApi.save({ domain: 'component' }, $scope.component,
function(response) {
console.log('---save, ', response);
getAll();
},
function(response) {});
};
}]);
// 전체 목록에 대해서만 Service로 구현함 : Broadcasting에 대한 별도 추가 테스트 필요함
ComponentMod.service('componentSvc', ['$rootScope', 'RestfulSvcApi', function ($rootScope, RestfulSvcApi) {
this.getAll = function() {
RestfulSvcApi.all({ domain: 'component' },
function(response) {
console.log('componentSvc : all data=', response);
$rootScope.$broadcast('updateComponentList', response);
},
function(response) {});
};
}]);
- step-5 : DashboardApp.js routing status 업그레이드
'use strict';
var DashboardApp = angular.module('DasbhoardApp', [
'ngRoute',
'ui.router',
'ngAnimate',
'ngCookies',
'ngResource',
'ngSanitize',
'DasbhoardApp.CommonCtrl',
'MobiConSoft.ComponentMod',
'DashboardApp.JqGridDrtv',
'DasbhoardApp.RestTestBiz',
'DasbhoardApp.JqGridBiz',
'DasbhoardApp.RestfulSvc'
]);
DashboardApp.config(['$stateProvider', '$urlRouterProvider', function ($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise("/main");
$stateProvider
.state('main', {
url: '/main',
templateUrl: 'views/main.html'
})
.state('resttest', {
url: '/resttest',
templateUrl: 'views/restTest.html',
controller: 'RestTestBiz.personCtrl'
})
.state('jqgridtest', {
url: '/jqgridtest',
templateUrl: 'views/jqGridTest.html',
controller: 'JqGridBiz.salesCtrl'
})
.state('mc-component', {
url: '/mc-component',
templateUrl: 'views/mc/component.html',
controller: 'ComponentMod.componentCtrl'
})
.state('mc-component.detail', {
url: '/detail/{componentId:[0-9]{1,4}}',
templateUrl: 'views/mc/component.detail.html',
controller: 'ComponentMod.componentCtrl'
})
.state('mc-component.create', {
url: '/create',
templateUrl: 'views/mc/component.create.html',
controller: 'ComponentMod.componentCtrl'
});
}]);
DashboardApp.run(['$rootScope', '$state', '$stateParams',
function ($rootScope, $state, $stateParams) {
$rootScope.$state = $state;
$rootScope.$stateParams = $stateParams;
}]);
- 결과화면
* 소스 : https://github.com/ysyun/SPA_Angular_SpringFramework_Eclipse_ENV/tree/feature_admin_routing
<참조>
'My Projects > BI Dashboard' 카테고리의 다른 글
[BI Dashboard] jqGrid 와 Angular.js 연동하기 (0) | 2013.11.28 |
---|---|
[BI Dashboard] Angular.js $resource 이용하여 Service 만들기 (0) | 2013.11.27 |
[BI Dashboard] Angular.js 엔터프라이즈 애플리케이션 구조 만들기 (0) | 2013.11.22 |
[BI Dashboard] Angular+Bootstrap을 Windows와 IE8 이상에 적응시키기 (0) | 2013.11.21 |
[BI Dashboard] myBatis에서 Mapper Interface로 고도화하기 (0) | 2013.11.20 |