Sending messages to subordinate components

I’m using DoneJS.

I want to have a button on a parent component that tells the subordinate detail components to go to a summary state. I can think of ways to make this happen but do not see how DoneJS supports this seemingly common need.

Here, two are already summary and one is in the editing state. Can you suggest the DoneJS mechanism for having the thing at top tell the things at bottom to change state (but only for the things at bottom that belong to this, exact thing at top)?

Thanks.

From a logical point of view I would suggest thinking in terms of the model and how to wire things up there. The ‘parent’ component can set the state on the model of the relevant items. The subordinate component would be updated based on that state. This is something one would do with most “presentation model” type of implementations such as canjs.

I hope that makes sense…

What other options were you considering?

A lot depends on who should be managing the state.

I’ll do this sorta thing in the parent component’s template:

<button ($click)="doSomething()"/>

<child-component ($inserted)="addChild(%viewModel))"/>

And then in the parent’s view model:

VM = DefineMap.extend({
  children: DefineList
  addChild: function(childVM){
    this.children.push(childVM);
  },
  doSomething: function(){
    this.children.forEach(function(child){
      child.someMethodOnChild()
    })
  }
})

The trick for me is that the children can be in any state and I want them forced to be ‘summary’. Also, they need to be able to be changed to ‘edit’ independently thereafter.

Eben, my goal is to do it the ay you suggest. However, I have not found good ways to do inter-component communication. Generally, I use properties on a parent view model and that works.

I this case, however, each child has a property in its view model that says what it’s supposed to be and a control that toggles it. I can’t use a parent’s property because each has its own state. As you suggest, the goal is to reach into each child view model and set the state to ‘summary’.

If Justin hadn’t revealed ($insert) to me and highlighted that the %viewModel refers to that of the child, ie, solved the problem, I would probably have used a jquery trigger with a common class-ID to activate an event. That would not make me happy but would work.

But, as I say, the details Justin highlighted for me will solve the problem.

There will always be more than one way to skin a cat I’m sure :slight_smile:

I’m just wondering where the %viewModel comes from?

I guess if it works that is first prize. This type of solution would make sense if the children are somehow disconnected from the parent and can only be linked via the DOM, which is somewhat odd :neutral_face:

It’s one of the special keys available to an event binding: http://canjs.github.io/canjs/doc/can-stache/keys/special.html

First, it works. I have successfully made a ‘close all’ function that does just what I wanted.

The %viewModel does, in fact, refer to the view model of the new inserted child element. Just as Justin suggested, I iterated over it and told each of them that their state is ‘summary’. This new knowledge is going to be very helpful to me going forward.

As an aside…

I have had a lot of difficulty figuring out how to communicate among parts of the DoneJS universe.

For example, I have taken to sending in the controlling view model (the one that receives the info from the selecting widget and supplies it to the editing widget(s)) explicitly into nested components. Not only have I found the “…/” syntax to be brittle (turns out that later wrapping a {{#each} in a {#showList}} breaks things), but I have not found a way to refer to view models up the hierarchy inside of view model functions (usually for event handlers).

So, a child component that edits a part of the main data element has to be able to talk to the controlling view model to, say, insert a new item into a list. I end up using

this.attr(‘planRootVm’).attr(‘workingPlan’).attr(‘diagnoses’).push(newThing);

It seems cumbersome but, I haven’t been able to figure out anything better.

However, I don’t want to seem too negative. I am a huge fan of the view model approach and am often astonished at the things that DoneJS does for me automatically. But, some things are very difficult.

I have seen that page many times. I always thought that the viewModel referred to the one driving the stach.

Let me suggest that you slightly revise the definition of the %viewModel. Something like,

In an event binding, %viewModel references the view model of the current element, or the new view model if a component is being created.

If, of course, what that is correct.

I have come across the %viewModel and actually referenced that page in another thread :slight_smile:

My statement related to where the actual view model would come from. It is fine referencing it but it has be instantiated somewhere

So now we know that it is the view model instantiated along with the new component.

Eg,

<user-nurse-plan-editor ($insert)=’%viewModel’ />

References the view model in the file user/nurse/plan/editor.js that is instantiated at the time that the stach file is interpreted. Not the view model that drives the stach file that contains it (in this case, the one in user-nurse-plan.js).

I didn’t see that earlier for the same reason you question it now (I think), because it doesn’t exist until after that tag is operated. Since it looks a lot like, say, %index, which comes from the enclosing stach and does exist before that tag is evaluated, I was confused.

Sounds like you were, too.

It’s added to the scope here: https://github.com/canjs/can-stache-bindings/blob/master/can-stache-bindings.js#L288

I’m not sure what you mean here. Could you try to explain this a bit better. Is there a bug somewhere with ../?

It sounds like what you want is a “bi directional” tree-like structure. Where children know about parents and parents know about children. This is like the DOM where you can go from parentNode.childNodes to childNode.parentNode.

We just experienced this within the Bitcentive app we are building. We’re adding an added and removed callback to List types so they can make sure all children have easy access to their parent.

You can see an example here that makes it so MonthlyOSProjects always know about their ContributionMonth:

For example:

contributionMonth = new ContributionMonth();

var monthlyOSProject = new MonthlyOSProject({name: "CanJS"})

contributionMonth.monthlyOSProjects.push( monthlyOSProject );

monthlyOSProject.contributionMonth //-> contributionMonth

contributionMonth.monthlyOSProjects.pop();

monthlyOSProject.contributionMonth //-> null

Perhaps in the future we can make this pattern a bit easier to accomplish. It would be helpful to better understand what you said above.

I don’t think anything is broken with “…/”. I have had need to refer to details from above and have found counting the levels difficult. Also, I’m still new to DoneJS and have had occasions where I moved things around requiring different relative references.

I’ll read the other parts more carefully later and see what I can make of them.

So last night, just before I went to bed, this whole situation became more clear (I hope).

Now you may actually know this so please ignore (and take no offence while you’re at it) if you already have this thinking :slight_smile:

I tend to approach this from a point of view that widgets represent my state, as opposed to containing my state. This may seem trivial, silly, or subtle but it all relates to MVVM. There are a million opinions on these things I know. Your state (model, the first M in MVVM) should simply contain your data. The view model (VM) contains the presentation model that is used to perform your behaviour/interaction. The view (first V) interacts with the VM to get things done. At this point you may be rolling your eyes with the accompanying “boring…”. However, there certainly is a difference in approach and I think this is where the “ViewModel” on a component level seems odd i.t.o. naming — since it is related to only the components state and behaviour (so it is proabably aptly named).

The view model for your entire view that contains all your components (even if the view itself is a component) should contain the structure and the various components should bind to those bits. In this way the components are always attached to the overall structure. This is why the relative finding of data should not relying on your component structure but rather on the structure of your larger view model. Component relative links should always be predictable.

I have the following JSBin that demonstrates my take on this: http://jsbin.com/pafeqiy/14/edit?html,js,output. Is this what you had in mind or am I still missing something? Anyway, so all that is driven from the model and the components don’t need to be aware of each other.

You and I are on the same page.

When I used the phrase, “controlling view model”, I was referring to your “first M”. When I was asking for a way to “send messages to subordinate components”, I was asking to set properties in your “VM” as you do in the summarize() loop.

My situation differs your jsbin in that, I have to have a complicated selection tool to choose which of those parents to play with that has to reach out to the controlling view model and designate the item that is active in the “first V”. Also, there is a second data source that must be accessed in concert with the loading of that parent, sort of a Javascript join. Also, I do not separate the parent and child data into separate models since they arrive from the data as a JS object that includes a list property for the children.

The closest thing we have to a difference is, I think, a mere language thing. I don’t actually have any interest in the components being aware of each other specifically. Previous to Justin telling us about %viewModel (and me, ($insert) which I had not previously known about), I could not find a way to loop over the children in a way that would allow me to set the property on my ‘subordinate’ (your “VM”) to change the state. That’s my interest and that’s what you do in the jsbin.

As an aside… I am the opposite of offended or bored. I work alone and generally have no one to talk to about these things. (Honestly, I had hoped that this forum would offer more opportunity for more general interaction about experiences and techniques.) I very much appreciate your thinking about this and posting your observations. It helps me to think it through just to read your words. Thanks.

Another aside… I am starting to wish that I had done this project based on CanJS instead of DoneJS. DoneJS, I’m starting to feel, does too much stuff too automatically. Had I been doing this in the CanJS mode you show in your jsbin, I would have been able to locate the subordinate view model. No point to be made but it’s something I’m thinking about.

As best I can intuit, I would like a bi-directional tree-like structure. Here is an aspect of my app that might clarify my need.

The app I am working on is a tool to help school nurses manage individual health plans for students. Nurses have many students. Students have many plans. Plans have many conditions. Conditions have many details. Student data has to be stored separately for privacy reasons.

Adding a condition to a plan actually means 1) choosing a boilerplate item from a separate database, 2) making that available to the view model that has the data model received from the server, and 3) creating a new plan item based on that boilerplate and 4) pushing it into that plan.

There are a lot of conditions (asthma, stomach ulcers, etc) and a normal menu selector won’t work for choosing the boilerplate item. Instead, I have a tool that (eventually) allows typing a partial string and other methods of shortening the list so a nurse can find the right thing. This tool needs to know what conditions have already been selected so that the nurse doesn’t add them twice.

I have constructed the selector to allow the addition of widgets (mainly for filtering). One widget (component) is the one that presents the list of boilerplate items. It needs to know, for each item, whether there is already an element in the plan derived from that boilerplate.

The connection of the plan item source id and the boilerplate item is something that might have been done with a join in a SQL based implementation. For Javascript, I obviously have to loop over the plans conditions to match with boilerplates. To do that, I need to gain access to the plan view model which is some arbitrary distance above the listing component in the hierarchy.

Importantly, the plan view model is not %root. This application does other things (eg, enter and edit boilerplate), the plan view model is held by a component named ‘nurse’. While the component makes %root available to everyone, I have had to adopt the practice of explicitly sending a ‘planRootVm’ to the subordinate components.

At first, I did plan-root-vm=’{.}’ or plan-root-vm=’{…/…/}’, etc, depending on where in the hierarchy the component in question is. This is where the brittleness I spoke of comes in. Now, all subordinate components get plan-root-vm=’{planRootVm}’. (This makes it essentially a global so I feel dirty.)

So, the bottom line of this probably too long story, is that I have had to do things that feel to me like hackery to get access to intermediate (ie, non %root) plan data model (there are other examples, too). I think that it is probably something that you are trying to address with your bi-directional tree-like structures though the analogy to childNode.parentNode seems like the english expression of “…/”, and thus potentially brittle. The phrase “make sure all children have easy access to their parent”, however, exactly expresses the problem that needs solving.

To be honest, I have started shaving off bits of the DoneJS generated code from my own application also. CanJS is great… and focuses on a library approach. DoneJS is more opinionated. It’s probably OK for most folks but I don’t need all those moving bits quite yet.

As to your problem space: it does seem as though you may have quite a challenging UI going and it certainly can be tricky getting to a simple UI. Sometimes it may be useful to rethink the design though. Of course, I’m not in any way trying to say that you have an incorrect design but at times it may take a couple of attempts to get it just right. From a domain-driven design perspective modelling requires quite a bit of input from domain experts so if you have someone like that to talk to it may help.

Another approach that I haven’t really seen in the CanJS / DoneJS space is using a pub/sub approach to disconnect components. I don’t know if that will work for you in this particular case but I have used it with success my previous ember project. For instance, once a customer was selected that event would be published and all interested parties would update their models or fetch data (or whatever it is they needed to do).

The reason this is complex is that the task is a complicated one. Mostly, I feel like I have got it decently right both visible to the user and in the internal model. Things are nicely encapsulated and the state models well isolated to their local widgets. (If you want to be friends and play online demo sometime, let me know. I’d be really interested in your opinion.)

I’m no fan of pub/sub as a primary way of organizing things. In my first big app (here), I used JavascriptMVC with a lot of eventing. It eventually drove me crazy. It still makes me think of the GOTO/spaghetti code of my childhood. It soon becomes impossible to figure out who is talking to whom. I ended up using a callback strategy that in some ways, imitated a live binding scenario.

I chose Can/Done after watching a video last year by Justin. He said, “Never listen to a click, then do a bunch of stuff. Listen to a click, then change state. If you have a good view layer, live binding takes care of everything.” I wrote a small CanJS app and never looked back.

With the problem that started this thread, I would have used events if Justin hadn’t suggested a live binding solution.

1 Like

One has to use the right tool for the job :slight_smile:

Although events are not a cure-all they do have their place; whereas an all-encompassing state class would probably be the antithesis to this. But there surely could be middle ground somewhere. But agreed… one could quite easily get away with some decent binding. These are all just variations on the observer pattern anyway.

I’ll PM you with my details as I am quite keen to see what you’ve done. :+1:

1 Like

Sorry I can’t digest and respond to all of this … I’m deep in some compute craziness for 3.0. But I just wanted to thank you both for having an awesome discussion.

1 Like