A simple mistake can mess up your ViewModel rendering, making it slow and unlike 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 are the different ViewModels which will show the same thing:
Both SendAndShowSelected
and SendAllShowSelect
are okay, but with different approaches to when data is sent to the client. SendWeirdAndShowSelected
is not advisable but will 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 are 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.
SendAndShowSelected
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.
SendAllShowSelected
All Years, all Months for all Years, and all Days for all Months and 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 you even want this? You want this if you have a custom component you want to process data client-side or it’s OK with a slight delay initially but with a swift experience thereafter.
SendWeirdAndShowSelected
Placing vCurrent* in the ViewModel as in the example above doesn't work out well. This is because 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 the 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 gets all these incorrect branch updates to their data without any good coming from it.
So, why is vCurrent* available in the blue ViewModel classes? It 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 specified 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 the WPF turnkey client.
Conclusion
In most cases, construct your ViewModels with master-detail relationships as shown in SendAndShowSelected.
If you want to increase performance by switching between different things in the view, consider using SendAllShowSelected. That means sending all data right away to the client and then only updating 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/