Angular 如何订阅和更新深入嵌套在BehaviorSubject中的各个属性?

Angular 如何订阅和更新深入嵌套在BehaviorSubject中的各个属性?,angular,typescript,rxjs,Angular,Typescript,Rxjs,我需要创建一种方法来动态构建一个可单独订阅的可观测数据存储。我使用的是BehaviorSubject,因为生成的数据的值会发生变化,需要反映出来 我正在创建一个模块,用于从以下界面形状的数据对象生成SVG代码 export interface GraphicElement{ element: string; elementId: string; selfClosing?: boolean; bind?: GraphicBinding; //this propert

我需要创建一种方法来动态构建一个可单独订阅的可观测数据存储。我使用的是
BehaviorSubject
,因为生成的数据的值会发生变化,需要反映出来

我正在创建一个模块,用于从以下界面形状的数据对象生成
SVG
代码

export interface GraphicElement{
    element: string;
    elementId: string;
    selfClosing?: boolean;
    bind?: GraphicBinding; //this property is most relevant to this question
    value?: string;
    properties: GraphicProperties;
    responsiveProperties?: ResponsiveProperties;
}

export interface GraphicBinding{
    library: string;
    property: string;
}
在我的模块中,我有一个封装所有代码的
svg外壳组件
,一个
svg组组件
,它将
graphicalelement
对象迭代到一个
svg元素组件
,该组件生成svg元素并将其注入模板

可选的
bind
属性将让组件知道需要将值绑定到该元素。为了给出一个真实的例子来更好地说明我在做什么,我有一个
产品规格组件
,它显示了一个产品的图表,根据产品的不同尺寸、零件尺寸、开/闭跨度等的测量值。
产品数据
图形数据
是一个单独的存储区,它包含不同维度的所有测量值,这些测量值将用于生成在显示测量值的
svg元素组件
实例中应绑定的数据。用户还可以在英寸和厘米之间切换,这将更新本例中绑定的属性的值

我处理这种情况的方法是使用一个服务文件来动态地生成和设置以下接口形式的属性

export interface GraphicBindingData{ [library: string] : GraphicBindingProperty; }
export interface GraphicBindingProperty{ [property:string] : string; }
因此,在本例中,将在服务文件中生成一个如下所示的对象

BindingData: GraphicBindingData = {
     specMeasurements:{
        width: '2in',
        height: '5in',
        thickness: '.125in',
        depth: '9in'
    },
    someOtherLibrary:{
        somePropA: 'some value',
        somePropB: 'some value'
    }
}
export interface BindingObject{ [library:string] : BindingItem; }
export interface BindingItem{ [property:string] : BehaviorSubject<string>; }

export interface BindingObjectObservable{ [library:string] : BindingItemObservable; }
export interface BindingItemObservable{ [property:string] : Observable<string>; }
回到
graphicselement
界面中
bind
属性的
graphicsbinding
界面,
属性将被设置为
specMeasurements
,而
属性
将被设置为需要绑定到哪个维度的名称

因此,我们将调用的
绑定数据服务
文件将导入
产品规格组件
以设置此数据,而
图形元素组件
将使用
绑定
属性中的值来订阅它需要的任何属性。我添加了另一个虚拟数据对象,因为我想展示如何可能存在其他属性对象,以进一步强调是什么让我很难理解如何将
BehaviorSubject
应用到这种情况中,以便在一个库可能会改变,而其他库则保持不变。在本例中,
产品规范组件
没有太大问题,但在如何使用此模块的其他方面,可能会有更多对象,其中可能包含更深层次的数据

我想做下面的事情

export interface GraphicBindingData{ [library:string] : BehaviorSubject<GraphicBindingProperty>; }
export interface GraphicBindingProperty{ [property:string] : BehaviorSubject<string>; }
导出接口GraphicBindingData{[library:string]:BehaviorSubject;}
导出接口GraphicBindingProperty{[property:string]:BehaviorSubject;}

在考虑了一个
BehaviorSubject
通常是如何被另一个变量观察到的之后,我不确定如何为每个库中的每个属性创建一个观察者。我也不确定在这种情况下如何使用
.next()
来更新数据。我一直在尝试在BehaviorSubjects中查找有关使用BehaviorSubjects的更多信息,如果这是我想要实现的目标所必须做的事情,但却找不到任何东西。有人能帮我弄清楚如何塑造它,这样我就可以订阅和更新单个属性,而不影响其他可观察对象吗?

我不建议嵌套行为主题,它会使您的流消耗更加复杂,最好使用单个状态对象并应用一些过滤逻辑

假设你有一个像

const myObj=new BehaviorSubject({orange:{apple:{cherry:'my cherry'},banana:'my banana'})
您想要更新cherry(在这里重建不可变对象可能会很痛苦)

看看有没有零钱

myObj.pipe(pluck('orange','apple','cherry'), distinctUntilChanged())
因为每当其中一个值发生更改时,您必须.next()调用整个对象,所以要做到这一点,您必须解构并重新构造状态对象

const obj=myObj.value
//add a grape
myObj.next({...obj ,orange:{...obj.orange, grape:'my grape'}})

// or json stringify then json parse
const obj=JSON.parse(JSON.stringify(myObj.value))
obj.orange.grape='my grape'
myObj.next(obj)
或者,如果不需要不变性,可以直接设置属性

let obj=myObj.value
obj.orange.grape='my grape'
myObj.next(obj)

国家管理怎么样


你必须使用NgRx来利用你对这个项目树的所有状态更改

好的,我最后想出了一个方法来实现这一点。我不得不像这样重新塑造我的界面

BindingData: GraphicBindingData = {
     specMeasurements:{
        width: '2in',
        height: '5in',
        thickness: '.125in',
        depth: '9in'
    },
    someOtherLibrary:{
        somePropA: 'some value',
        somePropB: 'some value'
    }
}
export interface BindingObject{ [library:string] : BindingItem; }
export interface BindingItem{ [property:string] : BehaviorSubject<string>; }

export interface BindingObjectObservable{ [library:string] : BindingItemObservable; }
export interface BindingItemObservable{ [property:string] : Observable<string>; }
导出接口BindingObject{[library:string]:BindingItem;}
导出接口绑定项{[property:string]:BehaviorSubject;}
导出接口BindingObjectObservable{[library:string]:BindingItemObservable;}
导出接口BindingItemObservable{[property:string]:Observable;}

因此,我没有将一个实体对象作为
行为主体
和另一个作为
可观察对象
,而是将每个属性设置为
行为主体
,然后单独观察和订阅,并且可以在不影响库中其他属性的情况下进行更新。

平滑解决方案HMMMM。好的,现在如果我有类似于
橙色:{apple:{cherry:'mycherry',grape:'mygrape'}
?我能换樱桃而不影响葡萄吗?我认为在这种情况下,
.next()
可以消除葡萄。但是,我可以将整个对象存储在函数中的一个变量中,然后在那里重新写入cherry,并用相同的grape值重置它。是的,正如你所说,你可以将整个对象存储在一个变量中,而不可观测,但你只是失去了反应性,你已经