Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Refresh bindings in parent view when parent value is changed from child through DI

Tags:

aurelia

The goal is to be able to update "heading" on the SharedParent and/or in the SharedState view, whenever it is changed from the child through DI.

I suspect there's a problem with the layout-view and layout-view-model on the Aurelia router custom element.

I need this since the SharedParent in the real code, will be abstractung general calculation functions (saved in variables in the SharedParent, which currently is not updated in the view) etc which the children will be calling (to avoid every child to duplicate this functionality). Ideally referencing the DI reference of the SharedParent.

The ideal solution enables direct modification on the parent. The SharedState was just an extra way of testing, and can be ignored, if you can see a way to get it working with option 1)

Option 1 is my highest priority to get working

See the live running gist here: https://gist.run/?id=66eeff540a4665694a31482b790bf01e

Update

I've made yet another gist to show another way I've tried in order to get the parent/child relationship working: https://gist.run/?id=080d4ac3f4d8677d344140a7827aea94 - in this example there's just another issue with the current route not being set correctly, due to duplicate "route" attributes in the router. But here, at least we're able to update the parent property from the children. The ideal solution is to get both working in 1 solution. So that the active route is set correctly, and children will be able to update the dependency injected parent's properties. And lastly the parent view needs to refresh on this change. This gist is by the way from another question: How to dynamically build navigation menu from routes linking to parent/child views/controllers - but slightly modified to help illustrate that what isn't working in this questions' gist, is indeed working here.

To sum it up.

I first tried to solve my problem this way: https://gist.run/?id=080d4ac3f4d8677d344140a7827aea94 - almost everything worked as it should (set heading in parent from child) and reflect change of dates/language from parent in child-view - both getting and setting of parent properties from the children. The only thing not working was the routing. I couldn't get the active route displayed, since multiple routes shared the same "route" attribute.

So I looked towards the layout-view(-model) solution (whick I proposed in this question) - which seemed to fix the routing issue, but broke the bindings between parent / child.

like image 822
Dac0d3r Avatar asked Mar 17 '17 11:03

Dac0d3r


2 Answers

I got it to work here: https://gist.run/?id=6c112829bb42a5ed86b78b4c8917a72c

  • I set @singleton(true) decorator on SharedParent => DI Basics
  • I used the existing BindingSignaler from the injected Parent
like image 107
zedL Avatar answered Nov 18 '22 17:11

zedL


ChildA is constructed by the container before the layout-view and layout-view-model indicated on the router-view are constructed. That means the container has to create a new instance of SharedParent (lets call it "instance 1") to give to ChildA's constructor.

Later, the router-view's layout view-model is constructed (SharedParent). When custom attributes, custom elements and router view models are constructed by the container, the templating system's default behavior is to tell the container "give me a fresh instance, don't reuse an existing one". This makes a lot of sense, most of the time you don't want all the the 10 <my-number-input> that appear on your form to all be the same instance no more than you would want 10 standard html <input> elements on your form to be the same... you want them to be independent. So a second instance of SharedParent is constructed, which is why your header code doesn't work... ChildA has a different instance of SharedParent than the router view.

Using @singleton on SharedParent will resolve this, but a better approach is to have SharedParent, ChildA and ChildB take a dependency on a SharedState class (eg @inject(SharedState)). This will negate the need to override the default behavior, make it more clear what the shared dependencies are, and preserve the nice separation of concerns between SharedParent and ChildA.

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

here's an example: https://gist.run/?id=dfe291e3da67854d143d264a2edd5ade

like image 28
Jeremy Danyow Avatar answered Nov 18 '22 18:11

Jeremy Danyow