InputManJSのコントロールは、Wijmoのデータレイヤー機能であるCollectionViewと連携して、様々なデータ連携機能を提供することができます。
データ連結
CollectionViewはJavaScript配列オブジェクトから生成されます。サーバーから取得したJSONデータや、クライアントで生成したデータ配列とのデータ連結に対応します。
InputManJSのコントロールをCollectionViewと連結するには、現在のレコードが変更されたときにコントロールのsetValue(テキストコントロールはsetText)メソッドを実行して、コントロールの値を更新します。
また、InputManJSのコントロールで変更した値をCollectionViewに反映するには、コントロールのgetValue(テキストコントロールはgetText)メソッドで値を取得して、現在のレコードに設定します。
変更データの追跡
CollectionViewは、編集/追加/削除された項目を自動的に追跡して管理します。変更された項目は配列オブジェクトとして取得され、変更データを簡単にサーバーに送信することができます。
現在の項目
CollectionViewでは、配列のインデックスを指定して項目を参照するのではなく、currentItemプロパティで現在の項目を参照します。現在の項目を前/後/先頭/最後に移動するためのメソッドも提供されます。
後述のソートやフィルタリングを適用した場合でも、特別な処理を実装することなく、簡単に現在の項目を移動することができます。
また、CollectionViewを複数のコントロールと連結した場合に、すべてのコントロールで現在の項目の位置が同期されます。このサンプルでは、右上のグリッドコントロールでセルを選択すると、InputManJSのコントロールに選択された行のデータが表示されます。
データビュー
グループ化、並べ替え、フィルター、ページングされたデータを取得するためのビューを作成することができます。
これらのビューを作成すると、表示上のデータの順番やデータの有無が変更されますが、連結した元のデータは変更されません。
このサンプルでは、右上のグリッドコントロールで次の操作を行うことができます。
並べ替え:列ヘッダをクリックします。
フィルター:列ヘッダの右側のアイコンをクリックして、リストから表示する値を選択したり、表示する値の条件を指定します。
Wijmoコントロールとの連携
ドロップダウンプラグインを使用すると、Wijmoのコントロールをドロップダウン表示することができます。詳細は「ドロップダウンプラグイン」を参照してください。
import '@mescius/inputman/CSS/gc.inputman-js.css';
import '@mescius/wijmo.styles/wijmo.css';
import './styles.css';
import './license';
import { InputMan } from '@mescius/inputman';
import { FlexGrid } from '@mescius/wijmo.grid';
import { CollectionView } from '@mescius/wijmo';
import { getProducts, categoryNames } from './data';
InputMan.appearanceStyle = InputMan.AppearanceStyle.Modern;
const cv = new CollectionView(getProducts(), {
trackChanges: true,
currentChanged: () => update()
});
const grid = new FlexGrid('#grid', {
itemsSource: cv,
isReadOnly: true,
columns: [
{ header: '商品コード', binding: '商品コード', width: 100 },
{ header: '商品名', binding: '商品名', width: 200 },
{ header: '分類', binding: '分類', width: 120 },
{ header: '価格', binding: '価格', format: 'c', width: 80 },
{ header: '発売日', binding: '発売日', width: 120 }
]
});
const gridEdited = new FlexGrid('#gridEdited', {
itemsSource: cv.itemsEdited,
isReadOnly: true
});
const gridAdded = new FlexGrid('#gridAdded', {
itemsSource: cv.itemsAdded,
isReadOnly: true
});
const gridRemoved = new FlexGrid('#gridRemoved', {
itemsSource: cv.itemsRemoved,
isReadOnly: true
});
const controls = {
商品コード: new InputMan.GcMask(document.getElementById('商品コード'), {
formatPattern: '\\A\\D{3}'
}),
商品名: new InputMan.GcTextBox(document.getElementById('商品名')),
分類: new InputMan.GcComboBox(document.getElementById('分類'), {
items: categoryNames
}),
価格: new InputMan.GcNumber(document.getElementById('価格'), {
displayPositivePrefix: '$',
displayNegativePrefix: '-$',
displayFormatDigit: '##,##0',
showNumericPad: true
}),
発売日: new InputMan.GcDateTime(document.getElementById('発売日'), {
formatPattern: 'yyy/M/d',
displayFormatPattern: '',
showDropDownButton: true,
dropDownConfig: {
dropDownType: InputMan.DateDropDownType.Calendar
}
})
};
const update = () => {
for (var fieldName in controls) {
if (fieldName == '商品名') {
controls[fieldName].setText(cv.currentItem[fieldName]);
} else if (fieldName == '分類') {
controls[fieldName].setSelectedIndex(categoryNames.indexOf(cv.currentItem[fieldName]));
} else {
controls[fieldName].setValue(cv.currentItem[fieldName]);
}
}
}
const setEnabled = (isEnabled) => {
for (var fieldName in controls) {
controls[fieldName].setEnabled(isEnabled);
}
}
const switchForms = () => {
const editForm = document.getElementById('editForm');
const commitForm = document.getElementById('commitForm');
editForm.style.display = editForm.style.display == 'block' ? 'none' : 'block';
commitForm.style.display = commitForm.style.display == 'block' ? 'none' : 'block';
}
const btn_contanier = document.getElementById('btn_container');
btn_contanier.addEventListener('click', (e) => {
let name = e.target.getAttribute('name');
if (!name) {
return;
}
handler[name]();
});
const handler = {
edit: () => {
cv.editItem(cv.currentItem);
setEnabled(true);
switchForms();
},
add: () => {
cv.addNew();
setEnabled(true);
switchForms();
},
remove: () => {
cv.remove(cv.currentItem);
},
commit: () => {
for (var fieldName in controls) {
cv.currentItem[fieldName] = fieldName == '分類' ? categoryNames[controls[fieldName].getSelectedIndex()] : controls[fieldName].getValue();
}
cv.commitEdit();
cv.commitNew();
setEnabled(false);
switchForms();
},
cancel: () => {
cv.cancelEdit();
cv.cancelNew();
setEnabled(false);
switchForms();
},
moveCurrentToFirst: () => cv.moveCurrentToFirst(),
moveCurrentToPrevious: () => cv.moveCurrentToPrevious(),
moveCurrentToNext: () => cv.moveCurrentToNext(),
moveCurrentToLast: () => cv.moveCurrentToLast(),
}
update();
setEnabled(false);
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>基本機能 - Wijmoとのデータ連携</title>
<!-- SystemJS -->
<script src="node_modules/systemjs/dist/system.src.js"></script>
<script src="systemjs.config.js"></script>
<script>
window.onload = function() {
System.import('./src/app');
}
</script>
</head>
<body>
<table id="btn_container">
<tr>
<td style="min-width: 300px;">
<table>
<tr>
<td>商品コード</td>
<td><input id="商品コード"></td>
</tr>
<tr>
<td>商品名</td>
<td><input id="商品名"></td>
</tr>
<tr>
<td>分類</td>
<td><select id="分類"></select></td>
</tr>
<tr>
<td>価格</td>
<td><input id="価格"></td>
</tr>
<tr>
<td>発売日</td>
<td><input id="発売日"></td>
</tr>
</table><br>
<div id="editForm" style="display: block;">
<button name="edit">編集</button>
<button name="add">追加</button>
<button name="remove">削除</button>
</div>
<div id="commitForm" style="display: none;">
<button name="commit">確定</button>
<button name="cancel">キャンセル</button>
</div>
<div>
<button name="moveCurrentToFirst"><<</button>
<button name="moveCurrentToPrevious"><</button>
<button name="moveCurrentToNext">></button>
<button name="moveCurrentToLast">>></button>
</div>
</td>
<td>
<div id="grid" style="height: 15rem;"></div>
</td>
</tr>
</table><br>
<table style="table-layout: fixed; width: 100%;">
<tr>
<td>
<label>編集された項目:<div id="gridEdited" style="height: 6.5rem;"></div></label>
</td>
<td>
<label>追加された項目:<div id="gridAdded" style="height: 6.5rem;"></div></label>
</td>
</tr>
<tr>
<td>
<label>削除された項目:<div id="gridRemoved" style="height: 6.5rem;"></div></label>
</td>
<td>
</td>
</tr>
</table>
</body>
</html>
.gcim, .gcim-calendar {
width: 200px;
}
import { Globalize } from '@mescius/wijmo';
export const getProducts = () => {
let products = [];
let id = 1;
let date = new Date(2014, 0, 1);
for (let i = 0; i < productNames.length; i++) {
for (let j = 0; j < productNames[i].length; j++) {
products.push({
商品コード: 'P' + Globalize.format(id++, 'd3'),
商品名: productNames[i][j],
分類: categoryNames[i],
価格: random(40, 10) * 100,
発売日: addDays(date, random(365 * 4))
});
}
}
return products;
}
const random = (max, min) => {
if (!min) min = 0;
return Math.floor(Math.random() * (max - min)) + min;
}
const addDays = (value, days) => {
return new Date(value.getFullYear(), value.getMonth(), value.getDate() + days);
}
const productNames = [
['果汁100%オレンジ', '果汁100%グレープ', '果汁100%レモン', '果汁100%ピーチ', 'コーヒーマイルド', 'コーヒービター', 'コーヒーミルク', 'ピリピリビール', 'オタル白ラベル', 'バードワイン'],
['ホワイトソルト', 'ブラックペッパー', 'ピュアシュガー', 'うまい素', 'ピュアデミグラスソース', 'だしかつお', 'だしこんぶ', 'ピリカラタバスコ', 'のり山椒', '特製和風醤油'],
['バニラクリームアイス', 'チョコクリームアイス', '紅茶バー', 'じゃがチップス', 'アメリカンクラッカー', 'バナナキャンディー', 'メロンミルクキャンディー', '小倉あんぱん', 'インドカレーパン', 'チーズあんぱん'],
['ロッキーチーズ', 'パルメザンチーズ', 'フレッシュバター', 'ライフマーガリン', 'ローカロリー牛乳', '牛乳マイルド', 'ストロベリーヨーグルト', 'ブルーベリーヨーグルト', 'ラズベリーヨーグルト', 'ココナッツミルク'],
['モーニングブレッド', 'バタートースト', 'バケットフランス', '極上パスタ', '極上マカロニ', '伝統スパゲッティ', 'ヘルシークラッカー', 'コーンフレークプレーン', 'コーンフレークチョコ', 'コーンフレークシュガー'],
['アメリカンポーク', 'うす味ウインナー', 'ベターローストハム', 'ベタープレスハム', 'ベター生ハム', '特製サラミ', '和風ハンバーグレトルト', '照焼きミートボール', 'ミックスハム', 'ミートバー'],
['もめんどうふ特上', 'きぬごしどうふ特上', '冷凍ミックスベジタブル', '冷凍クリームコロッケ', '冷凍コーンクリームコロッケ', '冷凍ポテトコロッケ', '冷凍枝豆', '冷凍やきおにぎり', '乾燥バナナ', '乾燥アップル'],
['特選味のり', '北海道昆布', 'やきいかするめくん', '食卓わかめ', 'ふりかけかつお風味', 'ふりかけ鮭風味', '大陸サーモン', '特選にぼし', '本がつお特上', 'ころもはんぺん']
];
export const categoryNames = ['飲料', '調味料', '菓子類', '乳製品', '穀類、シリアル', '肉類', '加工食品', '魚介類'];
[gcim-control-appearance="modern"] .gcim,
[gcim-control-appearance="modern"] .gcim-calendar {
width: 200px;
}
System.config({
transpiler: 'plugin-babel',
babelOptions: {
es2015: true
},
meta: {
'*.css': { loader: 'css' }
},
paths: {
// paths serve as alias
'npm:': 'node_modules/'
},
// map tells the System loader where to look for things
map: {
'@mescius/inputman': 'npm:@mescius/inputman/index.js',
'@mescius/inputman/CSS': 'npm:@mescius/inputman/CSS',
'@mescius/wijmo': 'npm:@mescius/wijmo/index.js',
'@mescius/wijmo.styles': 'npm:@mescius/wijmo.styles',
'@mescius/wijmo.cultures': 'npm:@mescius/wijmo.cultures',
'@mescius/wijmo.input': 'npm:@mescius/wijmo.input/index.js',
'@mescius/wijmo.grid': 'npm:@mescius/wijmo.grid/index.js',
'css': 'npm:systemjs-plugin-css/css.js',
'plugin-babel': 'npm:systemjs-plugin-babel/plugin-babel.js',
'systemjs-babel-build': 'npm:systemjs-plugin-babel/systemjs-babel-browser.js'
},
// packages tells the System loader how to load when no filename and/or no extension
packages: {
src: {
defaultExtension: 'js'
},
"node_modules": {
defaultExtension: 'js'
},
}
});