<!DOCTYPE html>
<html>
<head>
<title>Angular 2 Material Plunker</title>
<link rel="stylesheet" href="https://npmcdn.com/codemirror@latest/lib/codemirror.css" />
<!-- Load common libraries -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/typescript/2.1.1/typescript.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/core-js/2.4.1/core.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/zone.js/0.7.2/zone.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.41/system.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.8/hammer.min.js"></script>
<!-- Configure SystemJS -->
<script src="systemjs.config.js"></script>
<script>
System
.import('main.ts')
.catch(console.error.bind(console));
</script>
<!-- Load the Angular Material 2 stylesheet -->
<link href="https://rawgit.com/angular/material2-builds/master/core/theming/prebuilt/deeppurple-amber.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link href="app.css" rel='stylesheet' type='text/css'>
<style>body { font-family: Roboto, Arial, sans-serif; }</style>
</head>
<body>
<material-app>Loading the Angular 2 JSON Flatten Tool</material-app>
</body>
</html>
<!--
Copyright 2016 Google Inc. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://angular.io/license
-->
import {Component} from '@angular/core';
import {Http} from '@angular/http'
import {bootstrap} from '@angular/platform-browser-dynamic';
import { flatten } from './utils/flatten.util';
import { unflatten } from './utils/unflatten.util';
import { unflatSample, flatSample } from './samples/demos';
import prettyJson from 'json-stringify-pretty-compact';
const PlaceholderMessages = {
FLAT: 'Paste a json to flatten it',
UNFLAT: 'Paste a json to unflatten it'
}
@Component({
selector: 'material-app',
templateUrl: 'app.component.html'
})
export class AppComponent {
isFlat: boolean = false;
jsonData: string = '';
editorConfig = {
lineNumbers: true,
mode: { name: "javascript", json: true }
};
data = '';
codeMessagePlaceholder = PlaceholderMessages.FLAT;
constructor(http: Http) {
this.jsonData = prettyJson(unflatSample, { indent: 2});
}
updateJson(jsonData: string) {
this.jsonData = jsonData;
}
flatten() {
const json = JSON.parse(this.jsonData.trim());
if (json) {
this.jsonData = this.formatJson(flatten(json));
this.changeMode();
}
}
unflatten() {
const json = JSON.parse(this.jsonData.trim());
if (json) {
this.jsonData = this.formatJson(unflatten(json));
this.changeMode();
}
}
loadUnflatSample() {
this.jsonData = this.formatJson(unflatSample);
}
loadFlatSample() {
this.jsonData = this.formatJson(flatSample);
}
formatJson(_json) {
return prettyJson(_json, { indent: 2 });
}
handleChangeMode() {
this.changeMode();
this.clearJson();
}
changeMode() {
this.isFlat = !this.isFlat;
this.codeMessagePlaceholder = this.isFlat
? PlaceholderMessages.UNFLAT
: PlaceholderMessages.FLAT;
}
clearJson() {
this.jsonData = '';
}
}
/*
Copyright 2016 Google Inc. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://angular.io/license
*/
<md-toolbar color="primary">
JSON Flatten Tool
</md-toolbar>
<div>
<md-toolbar>
<md-slide-toggle
[checked]="!isFlat"
(change)="handleChangeMode()">
To Flat Mode
</md-slide-toggle>
<md-toolbar-row>
<button color="secondary" md-raised-button
[disabled]="isFlat"
(click)="loadUnflatSample()">
Sample unflattened JSON
</button>
<button color="secondary" md-raised-button
[disabled]="!isFlat"
(click)="loadFlatSample()">
Sample flattened JSON
</button>
</md-toolbar-row>
<md-toolbar-row>
<button color="primary" md-raised-button
*ngIf="isFlat"
(click)="unflatten()">
Unflatten
</button>
<button color="primary" md-raised-button
*ngIf="!isFlat"
(click)="flatten()">
Flatten
</button>
<span class="spacer"></span>
<button color="warn" md-raised-button
mdTooltip="clears the json code..."
(click)="clearJson()">
<md-icon>delete sweep</md-icon>
</button>
</md-toolbar-row>
</md-toolbar>
<p>
<md-input-container class="full-width">
<textarea mdTextareaAutosize mdInput
[placeholder]="codeMessagePlaceholder"
minRows="30"
#jsonArea
[value]="jsonData"
(input)="updateJson(jsonArea.value)"></textarea>
</md-input-container>
</p>
</div>
<!--
Copyright 2016 Google Inc. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://angular.io/license
-->
/** Add Transpiler for Typescript */
System.config({
transpiler: 'typescript',
typescriptOptions: {
emitDecoratorMetadata: true
},
packages: {
'.': {
defaultExtension: 'ts'
},
'vendor': {
defaultExtension: 'js'
}
}
});
System.config({
map: {
'main': 'main.js',
// Angular specific mappings.
'@angular/core': 'https://unpkg.com/@angular/core/bundles/core.umd.js',
'@angular/common': 'https://unpkg.com/@angular/common/bundles/common.umd.js',
'@angular/compiler': 'https://unpkg.com/@angular/compiler/bundles/compiler.umd.js',
'@angular/http': 'https://unpkg.com/@angular/http/bundles/http.umd.js',
'@angular/forms': 'https://unpkg.com/@angular/forms/bundles/forms.umd.js',
'@angular/router': 'https://unpkg.com/@angular/router/bundles/router.umd.js',
'@angular/platform-browser': 'https://unpkg.com/@angular/platform-browser/bundles/platform-browser.umd.js',
'@angular/platform-browser-dynamic': 'https://unpkg.com/@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
'@angular/material': 'https://rawgit.com/angular/material2-builds/master/bundles/material.umd.js',
// Rxjs mapping
'rxjs': 'https://unpkg.com/rxjs',
'json-stringify-pretty-compact': 'https://unpkg.com/json-stringify-pretty-compact@1.0.2'
},
packages: {
// Thirdparty barrels.
'rxjs': { main: 'index' }
}
});
/*
Copyright 2016 Google Inc. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://angular.io/license
*/
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
import {BrowserModule} from '@angular/platform-browser';
import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {AppComponent} from './app.component';
import {MaterialModule} from '@angular/material';
@NgModule({
imports: [
BrowserModule,
CommonModule,
MaterialModule.forRoot()
],
declarations: [AppComponent],
bootstrap: [AppComponent],
providers: []
})
export class PlunkerAppModule {}
platformBrowserDynamic().bootstrapModule(PlunkerAppModule);
/*
Copyright 2016 Google Inc. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://angular.io/license
*/
.full-width {
width: 100%;
}
.spacer {
flex: 1 1 auto;
}
export function flatten(_json: any) {
function objToJson (key, obj) {
return Object.keys(obj).reduce((acc, current, index) => {
const _key = '' !== key ? `${key}.${current}` : `${current}`;
const currentValue = obj[current];
if (Array.isArray(currentValue) || Object(currentValue) === currentValue) {
Object.assign(acc, objToJson(_key, currentValue));
} else {
acc[_key] = currentValue;
}
return acc;
}, {});
};
return objToJson('', _json);
};
export function unflatten(_json: any) {
function jsonToObj(data: any, result) {
return Object.keys(data).reduce((acc, current, index) => {
const inlineKeys = current.split('.');
let firstProp = inlineKeys.shift();
const hasProps = inlineKeys.length >= 1;
if (hasProps) {
const parsedKey = parseInt(inlineKeys[0], 10);
const isNextKeyNumber = !isNaN(parsedKey);
let _nextData = {};
if (!acc[firstProp]) {
acc[firstProp] = isNextKeyNumber ? [] : {};
}
if (isNextKeyNumber) {
const _index = parseInt(inlineKeys.shift(), 10);
const isValueInArray = acc[firstProp].length - 1 >= _index;
const currentValueObj = acc[firstProp][_index];
_nextData[inlineKeys.join('.')] = data[current];
acc[firstProp][_index] = isValueInArray
? Object.assign(currentValueObj, jsonToObj(_nextData, currentValueObj))
: jsonToObj(_nextData, {});
} else {
_nextData[inlineKeys.join('.')] = data[current];
Object.assign(acc[firstProp], jsonToObj(_nextData, acc[firstProp]));
}
} else {
acc[firstProp] = data[current];
}
return acc;
}, result);
}
return jsonToObj(_json, {});
};
export let unflatSample = {
"firstName": "John",
"lastName": "Green",
"car": {
"make": "Honda",
"model": "Civic",
"revisions": [
{
"miles": 10150,
"code": "REV01"
},
{
"miles": 20021,
"code": "REV02",
"changes": [
{
"type": "asthetic",
"desc": "Left tire cap"
},
{
"type": "mechanic",
"desc": "Engine pressure regulator"
}
]
}
]
},
"visits": [
{
"date": "2015-01-01",
"dealer": "DEAL-001"
},
{
"date": "2015-03-01",
"dealer": "DEAL-002"
}
]
};
export let flatSample = {
"firstName": "John",
"lastName": "Green",
"car.make": "Honda",
"car.model": "Civic",
"car.revisions.0.miles": 10150,
"car.revisions.0.code": "REV01",
"car.revisions.1.miles": 20021,
"car.revisions.1.code": "REV02",
"car.revisions.1.changes.0.type": "asthetic",
"car.revisions.1.changes.0.desc": "Left tire cap",
"car.revisions.1.changes.1.type": "mechanic",
"car.revisions.1.changes.1.desc": "Engine pressure regulator",
"visits.0.date": "2015-01-01",
"visits.0.dealer": "DEAL-001",
"visits.1.date": "2015-03-01",
"visits.1.dealer": "DEAL-002"
};