A simple mistake can mess up your viewmodel rendering and make it slow and not what you expected.
This is our example model, which lends itself to a simple master-detail view.
The view we want is a list of Years, click a Year, and that Year’s months will show. Then, click a Month and that month’s Days will show.
Below is the different viewmodels which will show the same thing.
Both SendAndShowSelected and SendAllShowSelect is ok, but with different approaches to when data is sent to the client. SendWeirdAndShowSelected is not really good at all but will actually show the same thing as the previous two.
So, what’s happening in these situations?
In a viewmodel you have access to built in variables called vCurrent_<name of viewmodelclass> and self. self is what you would expect, the object rendered when the server iterates over the list for the viewmodel class you access self in. vCurrent_<name of viewmodelclass> are variables that is global to the entire viewmodel. Whenever you access vCurrent, you get the user selected current object for the list of objects of the named class.
All Years, the current Month for the current Year and all Days for the selected Months and Years will be fetched serverside and sent to the client. This is a minimum of fetched and sent data. This is probably the thing you want most of the time.
All Years, all Months for all Years and all Days for all Months and for all Years will be fetched serverside and ALL of them will be sent to the client. This is the maximum expanded tree that the viewmodel expresses. Why would I even want this? You want this if you have an custom component that you want to process data client-side or it’s OK with a slight delay initially and then a really swift experience after that.
Placing vCurrent* in the viewmodel like the example above don’t work out well at all. This is because when the server, for example, with the Years, for every Year in the object list, vCurrent_AllYear evaluates to the same – what the user has clicked on.
Let’s say Years are a list of 2014, 2015 and 2016. If the user has clicked on 2015, the Months will be the months for 2015, even for 2014 and 2016. This means that client is updated again and again with an incorrect list of months when the user clicks. But it still shows a correct view to the user, why? The user only sees the correct branch, but the client get’s all these incorrect branch updates to it’s data, without any good coming from it.
So, why is vCurrent* at all available in the blue viewmodel classes? Because is usable for example in filtering a list on user selection in another list. If it’s not a master-detail relationship, it can be an easy way to add a sublist of objects to another viewmodel class.
Two ways viewmodels are built
When the server renders/fills in a viewmodel it does one of these;
- Expands the whole “tree” with every object that the expressions specify in each branch making a “full” tree.
- Expands only the “”vCurrent” on each level, making a “sparse” tree.
Different clients – different trees
For a WCF client with an ECO-space in memory, sparse trees are built. This is because the client has access to the full object space anyway and can quickly rebuild the viewmodel tree upon user selection.
For Turnkey, i.e. streaming viewmodel clients, the server builds full trees and streams to the client. This is true for both Angular web UI and for the WPF turnkey client.
In most cases, construct your viewmodels with master-detail relationships as shown in SendAndShowSelected.
If you want to increase performance switching between different things in the view, consider using SendAllShowSelected. That means sending all data right away to the client and then only update vCurrent-variables to switch between different data on the client.
The model used in this example: YearMonthDayExampleModel
You can also read about it here: https://blog.mdriven.net/cursored-or-full-tree/