在生产中将类型保存到本地存储和从本地存储恢复类型 [英] Saving and restoring types to and from localStorage in production
问题描述
我构建了一个可停靠的面板解决方案,其中要将布局存储到localStorage
,因此当我重新加载页面时可以再次使用它.在我的本地主机上,这实际上就像是一种魅力.这些是最重要的模型,以及我如何使用它们:
I built a dockable panels solution in which I want to store the layout to localStorage
, so I can use it again when I reload the page. This is actually working like a charm on my localhost. These are the most important models and how I use them:
export class DockTreeNode {
parent: DockTreeContainer;
// methods..
}
export class DockTreePanel extends DockTreeNode {
type: Type<DockablePanel>;
args: DockArguments;
movable: boolean;
}
export class DockTreeContainer extends DockTreeNode {
private orientation: Orientation;
private left: DockTreeNode;
private right: DockTreeNode;
}
dockTree: DockTreeNode = new DockTreeContainer(
new DockTreePanel(
TestPanelComponent,
null,
false
),
new DockTreePanel(
BovenbouwingComponent,
null,
true
),
Orientation.horizontal
);
用于保存和还原布局的代码如下:
The code for saving and restoring my layout is as follows:
private typeMap: Map<string, Type<DockablePanel>> = new Map();
/**
* Saving is pretty damn simple
*/
public saveDockTree(): void {
const saveString = JSON.stringify(this.dockTree, (key, value) => {
if (key === 'parent') {
return null;
} else if (key === 'type') {
return value.name;
} else {
return value;
}
});
localStorage.setItem(this.localStorageKey, saveString);
}
/**
* This method will check local storage for our stored tree and parse everything
* and be all kinds of cool on local storage.
*/
public setDefaultDockTree(dockTree: DockTreeNode): void {
this.defaultDockTree = dockTree;
try {
// Retrieve the stored item
const storageItem = localStorage.getItem(this.localStorageKey);
if (storageItem) {
const stored = JSON.parse(storageItem, (key, value) => {
if (key === 'type') {
if (!this.typeMap.has(value)) {
throw new Error('Layout types don\t match.');
}
return this.typeMap.get(value);
} else {
return value;
}
});
// Convert to real dockTree
const tree: DockTreeNode = this.JSONtoDockTree(stored);
this.dockTree = tree;
} else {
throw new Error('Could not find layout');
}
} catch (e) {
// Anything wrong? Reset the dockTree layout to default
this.dockTree = this.defaultDockTree;
this.saveDockTree();
console.log('Could not parse stored layout. Resetting local storage');
}
}
/**
* I think this can be done better, but that's not the problem here.
*/
private JSONtoDockTree(tree: any): DockTreeNode {
let node: DockTreeNode;
if (tree.left && tree.right) {
const left = this.JSONtoDockTree(tree.left);
const right = this.JSONtoDockTree(tree.right);
node = new DockTreeContainer(left, right, tree.orientation);
} else if (tree.type) {
node = new DockTreePanel(tree.type, tree.args, tree.movable);
} else {
throw new Error('Node is not a DockTreePanel or DockTreeContainer.');
}
return node;
}
现在在本地存储中,我保存的dockTree看起来像这样:
Now in local storage my saved dockTree looks like this:
{
"left": {
"type": "TestPanelComponent",
},
"right": {
"type": "SomePanelComponent",
},
// More
}
但是当我将其提交到svn存储库并且Jenkins使用ng build --prod
进行构建并启动运行该构建的Docker容器时,保存的type值将是毫无意义的:
But when I commit it to the svn repository and Jenkins builds with ng build --prod
and starts a Docker container running the build, the saved value for type will be complete nonsense:
{
"left": {
"type": "",
},
"right": {
"type": "n",
}
// More stuff
}
我认为这与TypeScript将所有内容都编译为JavaScript AOT有关,因此在运行代码时这些类型实际上并不存在.但是,我不了解仅通过使用typeMap<string, Type<DockablePanel>
来存储我的类型,它就可以在我的本地主机上正常工作.
I figured this would have to do with TypeScript compiling everything to JavaScript AOT, so the types don't actually exist when running the code. However, I don't understand that it does work on my localhost by simply using the typeMap<string, Type<DockablePanel>
to store my types.
为什么这有什么不同?是否有另一种方法可以从我忽略的字符串中获取类型?
Why is this any different? Is there another way to get a type from a string that I am overlooking?
推荐答案
我解决了.我在问题中遗漏了一个关键部分:
I solved it. I left out a critical part in my question:
private typeMap: Map<string, Type<DockablePanel>> = new Map();
constructor(@Inject('panelTypes') private panelTypes: Type<DockablePanel>[]) {
for (let i = 0; i < panelTypes.length; i++) {
this.typeMap.set(panelTypes[i].name, panelTypes[i]);
}
}
在这里,我使用类型名称作为键将面板的类型放入Map中.解决方案是删除它,仅使用panelTypes本身:
Here I put the types of the panels into a Map using the name of the type as the key. The solution was to drop this and just use panelTypes itself:
constructor(@Inject('panelTypes') private panelTypes: Type<DockablePanel>[]) { }
public setDefaultDockTree(dockTree: DockTreeNode): void {
// more code
const stored = JSON.parse(storageItem, (key, value) => {
if (key === 'type') {
// The changed part:
const panel: Type<DockablePanel> = this.panelTypes.find((panelType: Type<DockablePanel>) => {
return panelType.name === value;
});
if (!panel) {
console.log('Couldn\'t find paneltype ' + value);
} else {
return panel;
}
} else {
return value;
}
});
// More code
}
在没有地图的情况下,我只是使用Type<>.name属性来找到正确的Type.
With the Map out of the picture, I just use the Type<>.name property to find the correct Type.
这篇关于在生产中将类型保存到本地存储和从本地存储恢复类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!