guide Data Model

RealGrid-Touch 컨트롤은 (대량의) 업무 데이터를 표시하는 UI 컨트롤이므로, 명확한 화면을 구성하는 것 외에 데이터 관리가 중요한 요소이다. 가능한 데이터에 집중해서 앱을 개발 및 관리할 수 있도록 데이터 소스는 화면을 구현하는 리스트 컨트롤과 별도 계층으로 분리된다.
RealGrid-Touch 라이브러리는 전형적인 UI 구현 방식인 MVC 패턴으로서, Model(데이터소스), View(컨트롤 내부에 구현된 리스트뷰), Controller(리스트 컨트롤)가 각각 다른 레이어로 구현된다. 컨트롤러가 데이터와 뷰를 연결하고 관리한다.
데이터는 추가/삭제/수정할 수 있는데, 데이터의 변경은 바로 화면 view에 반영된다. 또, 화면에서 사용자 등을 통해 값이 변경되면 데이터 레이어에 바로 저장된다.

데이터소스는 실제 데이터행들을 보관하고 행들을 추가/수정/삭제 할 수 있는 RtListData, 정렬/필터링을 통해 RtListData 데이터행들을 다르게 배치하는 RtDataView, 둘 이상의 RtListDataRtDataView를 마스터/디테일로 연결해서 데이터행들을 배치하는 RtDataLinkView가 있다.

RtListData

데이터필드 목록이 생성되고, 필드 값들이 저장된 실제 데이터행들을 보관하는 기본 데이터소스이다. 다양한 method들을 통해 데이터를 검색하고 수정/추가/삭제할 수 있다.

const data = RealTouch.createListData('data');

// 리스트 컨트롤에 연결
realtouch.data = data;

Data Field

데이터행은 데이터소스 생성 시 지정된 데이터필드 개수와 동일한 값 목록을 갖게 되고, 각 필드의 값은 데이터필드의 자료형에 맞게 저장된다. RtDataType 열겨형으로 설정할 수 있는 자료형은 아래와 같다. 모든 자료형의 기본값은 undefined이다. 또, 필드 생성 지 자료형이 지정되지 않으면 RtDataType.TEXT로 설정된다.

Type RtDataType 설명
'text' TEXT 문자열
'number' NUMBER 숫자
'bigint' BIGINT 큰 숫자 2^53 - 1보다 큰 정수가 필요할 때 사용한다.
'bool' BOOL Boolean
'date' DATE Date 객체 Date 객체가 아닌경우 new Date()의 매개변수로 가능한 숫자나 문자열이어야한다. 데이터로 읽어들일 때 Date 객체로 변환한다.
'any' ANY Json object 여러 속성을 포함한 객체. view에 개별 속성에 접근할 수 있다.

필드 생성 시 [IRtDataField]에 선언된 필드 속성들을 지정할 수 있는데, 자료형외에 표시 label, 기본값, 필수 여부 등을 지정할 수 있다.

Any 필드

RtDataType.ANY 자료형 필드에는 JSON 객체를 저장할 수 있고, 데이터를 표시할 때 객체의 속성별로 접근할 수 있다.

const data = RealTouch.createListData('main', {
    fields: [
        { name: 'NAME', label: '이름' },
        { name: 'JOB', label: '직장', type: 'any' }
    ]
});
const values = [{
    NAME: 'hong',
    JOB: { company: 'samsung', dept: 'r&d' }
},
...]
const template = {
    template: {
        layout: 'vlinear',
        children: [{
            field: 'NAME'
        }, {
            field: 'JOB.dept'
        }]
    }
}

파생 필드(Derived Field)

기본 필드들의 조합 연산으로 값이 결정되는 필드이다.

const data = RealTouch.createListData('main', {
    title: '판매 정보',
    fields: [
        { name: 'QTY', label: '수량', type: 'number' },
        { name: 'LAT', label: '위도', type: 'number' },
        { name: 'LOGT', label: '경도', type: 'number' }
    ],
    derivedFields: [
        { name: 'SUM', label: '합', extractor: values => values.LAT + values.LOGT },
    ]
});

Data Load

데이터소스 생성 시 외부 데이터로 부터 데이터행을 생성하는 몇가지 방법을 제공한다. RealTouch.createListData 호출로 데이터를 생성하는 시점이나 RtListData.loadData 호출로 읽어 들이며, IRtDataValueSource 설정 모델에 저장 방식을 지정할 수 있다.

JSON Array

Json 객체 배열로 변환될 수 있는 텍스트, 혹은 Json 배열 자체로부터 데이터행들을 구성한다.

const options = {
    fields: [...],
    ...
}
const source = '[{}, {}, ...]';
const info = {
    type: 'json',       // 기본이 'json'이므로 생략 가능
    values: source,     // csv lines
    reader: (prop, value) => {
        if (prop === '매출액' || prop === '관객수' || prop === '스크린수') {
            return +value;
        }
        return value;
    }
};
const data = RealTouch.createListData('main', options, info);

CSV

콤마(',')로 분리된 행들로 구성된 텍스트로부터 데이터행들을 구성한다.

const options = {
    fields: [...],
    ...
}
const source = '...';
const info = {
    type: 'csv',        // csv text
    values: source,     // csv lines
    quited: true,       // 따옴표로 둘러쌓인 경우 따옴표를 제거하고 저장한다.
    skipBlank: true,    // true면 빈 줄은 무시한다.
    fieldHeader: 1,
    startRow: 2,
    reader: (prop, value) => {
        if (prop === '매출액' || prop === '관객수' || prop === '스크린수') {
            return +value;
        }
        return value;
    }
};
const data = RealTouch.createListData('main', options, info);

TSV

탭 문자로 ('\t')으로 분리된 행들로 구성된 텍스트로부터 데이터행들을 구성한다.

const options = {
    fields: [...],
    ...
}
const source = '...';
const info = {
    type: 'tsv',        // tsv text
    values: source,     // tsv lines
    multiTabs: true,    // true면 연결된 중복 tab을 하나로 간주한다.
    skipBlank: true,    // true면 빈 줄은 무시한다.
    fieldHeader: 1,
    startRow: 2,
    reader: (prop, value) => {
        if (prop === '매출액' || prop === '관객수' || prop === '스크린수') {
            return +value;
        }
        return value;
    }
};
const data = RealTouch.createListData('main', options, info);

RtDataView

RtListData로부터 정렬 혹은 필터링된 데이터행 목록을 새로 구축(build)해서 보관한다.
하나 이상의 필드를 기준으로 필드 값이나 정렬 콜백을 지정해서 정렬할 수 있다. 데이터뷰 생성 후에도 정렬 조건을 개별적으로 추가하거나 제거할 수 있고, 완전히 새로 설정할 수도 있다.
필터링은 정렬을 기준으로 적용된 순서에 따라 pre/post(정렬 이전/이후) 필터로 지정할 수 있다. 필터는 개별 필터이거나 둘 이상의 필터를 and/or로 묶은 필터 set으로 지정할 수 있디.
데이터뷰는 전역 함수로 생성하거나,

const list = RealTouch.craeteListControl(document, 'realtouch');
// 원본 데이터
const options = {
    fields: [...]
};
const data = RealTouch.createListData('data', options);
// 데이터뷰 생성
const dv = RealTouch.createDataView('dv', data, {});

// 리스트 컨트롤에 연결
list.data = dv;

원본 데이터로 부터 직접 생성할 수 있다.

const dv = RealTouch.createListData('', options).createView('dv', data, {});
list.data = dv;

Sorting

데이터뷰 생성 시 초기 정렬 상태를 지정할 수 있다.

const dv = RealTouch.createListData(...).createView('', {
    { sort: 'NAME' }
});
    { sort: ['DEPT', 'NAME'] } // 두 필드
    { sort: { field: 'NAME', dir: 'descending' } } // 정렬 방향 지정

Filtering

데이터뷰 생성 시 필터를 지정할 수 있다.

const dv = RealTouch.createListData(...).createView('', {
    {
        filter: {
            name: 'f1',     // 이름을 지정해야 나중에 enable/disable 시킬 수 있다.
            enabled: true,  // 지정하지 않으면 true
            filter: (row, values) => values['판매량'] >= 100
        }
    }
});

정렬 후 적용되는 post filter는 별도로 지정한다.

    {
        postFilter: {
            name: 'f2',
            enabled: false,
            filter: (row, values) => values['매출액'] >= 10000000
        }
    }

데이터뷰에 설정된 필터들은 개별적으로 활성 혹은 비활성 시킬수 있다. 비활성된 필터는 데이터행을 구축할 때 적용되지 않는다. 또, 위와 같이 필터 함수로 지정하는 방식 외에 지정할 수 있는 간략화딘 필터가 존재한다.

Dedupe

지정한 필드들을 기준으로 중복된 행들을 제외시킨다.

const dv = RealTouch.createListData(...).createView('', {})
           .dedupe('d1', ['NAME', 'DEPT'], true, true);

Slicing

지정한 범위 밖의 행들을 제외시킨다.

const dv = RealTouch.createListData(...).createView('', {})
           .slice('s1', [10, 100], true, true);
const dv = RealTouch.createListData(...).createView('', {})
           .slice('s1', 100, true, true); // 배열이 아니면 0부터 시작하는 범위가 된다.

Filter Set

둘 이상의 필터들을 AND 혹으 OR 로 묶어서 필터링한다.

const dv = RealTouch.createListData(...).createView('', {})
           .addFilterSet({
                name: 'fs1',
                filters: [...],
                op: 'and'   // 기본값 'or'
           }, true);

RtDataLinkView

둘 이상의 단순 데이터소스 즉, RtListDataRtDataView를 master/detail 관계로 연결하고 거기에 포함된 행들을 자신의 데이터행들로 배치한다. 연결 계층은 깊어질 수 있다. 즉, 디테일 데이터가 다른 것들의 마스터가 될 수 있다.

const list = RealTouch.craeteListControl(document, 'realtouch');
const master = RealTouch.createListData('master');
const detail = RealTouch.createListData('detail');
const data = RealTouch.createDataLink('dsLink', master, {});

// 리스트 컨트롤에 연결
list.data = data;

See Also

RtListControl
RtDataSource
RtListData
RtDataView
RtDataLinkView
createListData