Я пытаюсь сериализовать объект модели в локальное хранилище (или IndexedDB), однако он содержит сигналы.
// An example of the model I'm dealing with
export class ExampleModel {
canSerialise = "";
cantSerialise = signal("");
}
// What I'd like to be able to do
let exampleModel = new ExampleModel();
localStorage.setItem("example", JSON.stringify(exampleModel));
Однако это не будет сериализоваться cantSerialise
, поскольку сигналы технически являются функциями. Я бы хотел избежать ручного написания функций сериализации для всех моделей, в которых есть только сигнал.
JSON.stringify()
:
'{"canSerialise":"","cantSerialise":X}'
где X
может быть чем угодно, при условии, что оно сериализуется обратно в исходное значение в качестве сигнала (в данном случае signal("")
)'{"canSerialise":""}'
Обновлено:
Я должен уточнить, что цель состоит в том, чтобы модель была сериализована, и в этой модели есть сигналы, мне дана модель, и я не могу ее изменить. В то же время я хотел бы подчеркнуть, что десериализация действительно должна приводить к появлению сигналов в тех же местах, что и до сериализации (например, cantSerialise
должен быть обернут в сигнал во время десериализации, а canSerialise
не должен), поскольку код, работающий с моделью (который опять же, я не могу контролировать) ожидает этих сигналов. Сигналы не обязательно должны быть одними и теми же сигналами сами по себе, т.е. допустимо просто сохранить их значение во время сериализации и обернуть их в новый сигнал во время десериализации.
Вы используете TS, но не указали соответствующий тег в своем вопросе, с другой стороны, вы используете теги signals
и angular-signals
. Также обратите внимание на комментарий @Chellappanவ, чтобы устранить проблему XY.
@Chellappan வ Я добавил некоторые пояснения выше.
Это не идеальный код, но вы можете написать собственный метод toString
, который выполняет сигнал перед записью в объект. Затем мы можем вызвать JSON.stringify
, чтобы преобразовать объект, содержащий только значения, в строку.
Пожалуйста, игнорируйте мои ошибки TypeScript, поскольку это лучшее, что я могу сделать; это может выглядеть некрасиво, но свою работу выполняет.
export class ToStringConverter {
toString() {
let output: any = {};
const that: ToStringConverter = this as never as ToStringConverter;
for (let key in that) {
if (that!.hasOwnProperty(key)) {
const lookupKey: keyof ToStringConverter =
key as keyof ToStringConverter;
if ((that[lookupKey] as any) instanceof Function) {
output[lookupKey] = (that[lookupKey] as Function)() as any;
} else {
output[lookupKey] = that[lookupKey];
}
}
}
return JSON.stringify(output);
}
}
Полный код:
import { Component, signal } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import 'zone.js';
export class ToStringConverter {
toString() {
let output: any = {};
const that: ToStringConverter = this as never as ToStringConverter;
for (let key in that) {
if (that!.hasOwnProperty(key)) {
const lookupKey: keyof ToStringConverter =
key as keyof ToStringConverter;
if ((that[lookupKey] as any) instanceof Function) {
output[lookupKey] = (that[lookupKey] as Function)() as any;
} else {
output[lookupKey] = that[lookupKey];
}
}
}
return JSON.stringify(output);
}
}
// An example of the model I'm dealing with
export class ExampleModel extends ToStringConverter {
canSerialise = '';
cantSerialise = signal('');
constructor(canSerialize = '', cantSerialize = '') {
super();
this.canSerialise = canSerialize;
this.cantSerialise = signal(cantSerialize);
}
}
@Component({
selector: 'app-root',
standalone: true,
template: `
<h1>Hello from {{ name }}!</h1>
<a target = "_blank" href = "https://angular.dev/overview">
Learn more about Angular
</a>
`,
})
export class App {
name = 'Angular';
ngOnInit() {
// What I'd like to be able to do
let exampleModel = new ExampleModel('working', 'also working');
localStorage.setItem('example', exampleModel.toString());
}
}
bootstrapApplication(App);
Это решение частично удается тем, что оно сериализует сигналы, но нет различия между значением, которое было заключено в сигнал, и значением, которое не было заключено в сигнал, что означает, что десериализация не может обернуть сигналы вокруг значений там, где это необходимо. Как я писал в моем вопросе, его необходимо десериализовать как сигнал. Я использовал модифицированную версию вашего решения, в которой я добавляю к ключам/свойствам префикс func_
или other_
, чтобы при десериализации я мог просто удалить префикс и при необходимости включить новый сигнал.
astebin.com/H8VyspgA
Можете ли вы объяснить свой вариант использования, почему вы хотите сохранить сигнал в localStorage?