【问题标题】:Refresh bindings in parent view when parent value is changed from child through DI当父值通过 DI 从子值更改时刷新父视图中的绑定
【发布时间】:2017-03-17 11:49:08
【问题描述】:

目标是能够更新 SharedParent 和/或 SharedState 视图中的“标题”,无论何时通过 DI 从子级更改它。

我怀疑 Aurelia 路由器自定义元素上的 layout-viewlayout-view-model 存在问题。

我需要这个,因为真实代码中的 SharedParent 将抽象通用计算函数(保存在 SharedParent 中的变量中,当前未在视图中更新)等孩子将调用(以避免每个孩子复制此功能)。理想情况下是引用 SharedParent 的 DI 引用。

理想的解决方案可以直接修改父级。 SharedState 只是一种额外的测试方式,可以忽略,如果你能找到一种让它与选项 1 一起工作的方法)

选项 1 是我开始工作的最高优先级

在此处查看实时运行要点:https://gist.run/?id=66eeff540a4665694a31482b790bf01e

更新

我已经提出了另一个要点,以展示我尝试过的另一种方式以使父/子关系正常工作:https://gist.run/?id=080d4ac3f4d8677d344140a7827aea94 - 在此示例中,当前路线设置不正确只是另一个问题,原因是在路由器中复制“路由”属性。但是在这里,至少我们能够从子级更新父级属性。理想的解决方案是让两者都在一个解决方案中工作。以便正确设置活动路由,并且子级将能够更新依赖注入父级的属性。最后,父视图需要刷新此更改。顺便说一句,这个要点来自另一个问题:How to dynamically build navigation menu from routes linking to parent/child views/controllers - 但稍作修改以帮助说明在这个问题的要点中不起作用的东西确实在这里起作用。

总结一下。

我首先尝试以这种方式解决我的问题:https://gist.run/?id=080d4ac3f4d8677d344140a7827aea94 - 几乎所有事情都按原样工作(从子视图中设置父级标题)并在子视图中反映父级的日期/语言更改 - 获取和设置子级的父级属性。唯一不起作用的是路由。我无法显示活动路线,因为多条路线共享相同的“路线”属性。

所以我查看了 layout-view(-model) 解决方案(我在这个问题中提出了这个解决方案) - 这似乎解决了路由问题,但破坏了父/子之间的绑定。

【问题讨论】:

  • 您是否考虑过使用事件聚合器而不是将您的类注入到子组件中?
  • 因为我需要两者 1) 从父级获取属性 2) 修改父级属性 - 从子级,我认为这样做最不混乱的方法必须是将父级注入子级。我试过使用信号,但问题是当孩子修改父属性时,父视图不会“重新渲染”/更新。至少不适用于“布局视图(-模型方法)。有趣的是,它适用于我在“更新”下给出的另一个示例。我看不出事件聚合器在这方面有何帮助,但感谢你的建议。:-)
  • 你能帮我澄清一件事吗?父母还有什么孩子需要你注射的东西?我的意思是,除了要更新的标题属性之外?子组件是否需要(或将来需要)父组件?
  • 在每个父级中计算了很多统计数据。现在,计算这些统计信息、计算进度和显示进度的函数在父级中定义。孩子通过引用注入的 parent.functionname(params,..,) 来调用这些函数。我曾经为每个子级定义了相同的功能,但我将其移至父级以减少重复代码。我可以从父级读取很好,但似乎 layout-view/layout-view-model 会导致问题,因此您无法从其子级更新 layout-view-model 和视图:/
  • 我刚刚注意到,如果我删除 NewInstance.of,我可以让 2 工作。但它确实是 1) 我希望以某种方式开始工作。

标签: aurelia


【解决方案1】:

我让它在这里工作: https://gist.run/?id=6c112829bb42a5ed86b78b4c8917a72c

  • 我在SharedParent 上设置了@singleton(true) 装饰器=> DI Basics
  • 我使用了来自注入的 Parent 的现有 BindingSignaler

【讨论】:

  • 太棒了...即使在快速浏览了 DI 基础知识链接之后,我也没有头脑去弄清楚 @singleton(true) 绝对可以解决所有问题。现在甚至不需要 BindingSignaler,属性可以放在构造函数之外,也可以放在“SharedParent”中。非常感谢你 - 让这个工作对我来说非常重要,我已经尝试了整整一周。杰出的! gist.run/?id=a1721aa07aa35330138408a28b2a0ce8(看到它现在正在工作 - 即使没有信号器):D
  • 酷。这绝对是相关的,但是我认为 @singleton(true) + router-view、layout-view 和 layout-view-model 方法在这种情况下是更好的方法,因为它允许您直接路由到孩子,并且在同时将布局视图包裹在路由布局子视图周围。 @singleton(true) 真的很重要。 :-)
  • @zedL 好信息!也感谢您显示几个选项。
  • @zedl 它似乎只在 gist 中起作用,但在 esnext/webpack 骨架中不起作用,因为很可能是 babel6 问题。有什么想法吗?
【解决方案2】:

ChildA 由容器构造之前 构造路由器视图上指示的布局视图和布局视图模型。这意味着容器必须创建一个 SharedParent 的新实例(我们称之为“实例 1”)以提供给 ChildA 的构造函数。

稍后,构建路由器视图的布局视图模型(SharedParent)。当容器构建自定义属性、自定义元素和路由视图模型时,模板系统的默认行为是告诉容器“给我一个新实例,不要重用现有实例”。这很有意义,大多数时候您不希望表单上出现的所有 10 个<my-number-input> 都是同一个实例,就像您希望表单上出现 10 个标准 html <input> 元素一样是一样的……你希望他们是独立的。因此构造了SharedParent 的第二个实例,这就是为什么您的标头代码不起作用的原因...ChildASharedParent 实例与路由器视图不同。

SharedParent 上使用@singleton 可以解决此问题,但更好的方法是让SharedParentChildAChildB 依赖于SharedState 类(例如@inject(SharedState))。这将消除覆盖默认行为的需要,更清楚共享依赖项是什么,并保持SharedParentChildA 之间良好的关注点分离。

class SharedState {
  heading = '';
  ... other shared items ...
}

这是一个例子:https://gist.run/?id=dfe291e3da67854d143d264a2edd5ade

【讨论】:

  • 嗨 Jeremy,感谢您的回答,但是我看不出在这种情况下如何使用 SharedState 类,因为父母和孩子都应该能够改变状态(状态只是在父母和孩子之间共享 - 而不是随后的孩子)并反映变化。正如您在此处看到的:gist.run/?id=1abfca51c905d7a9a84a5133aefc55c0 它似乎只能以一种方式工作。标题永远不会从子级更新到父级。
  • 所以我猜想通过使用 sharedState 您指的是另一种实现父/子视图/视图模型关系的方式(stackoverflow.com/questions/40976125/…) - 虽然我相信布局视图会是更清洁的方式,但还有另一种方法的另一个问题最终导致我:stackoverflow.com/questions/42832255/… - 那时我认为我变得非常“hacky”并且必须有更好的方法
  • 我已编辑您的要点并将链接粘贴到我的答案中。请记住 在您的用例中,ChildA 在 SharedParent 之前构造
  • 非常感谢您的示例和解释。我想由于@singleton 装饰器的行为不像 babel 6 那样(将解释为什么它在你的 rjs-bundle 中而不是在当前的骨架中工作),使用你的共享状态方法是目前最好的选择。跨度>
  • 很酷——很高兴它对你有用——你介意更新 github 问题的状态并关闭(或保持打开状态)吗?只是想确保我们让所有参与的人都保持最新状态。
猜你喜欢
  • 2021-04-03
  • 2021-10-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-20
  • 1970-01-01
相关资源
最近更新 更多