Editing Data with View Projection
In my post last week, I have introduced a truly time-saving feature in Crosslight 4 called view projection. As its name implies, this feature supposed to be used only for data listing/viewing purpose. Typically, you will use a much simple (flat) object model that represents the shape of data which can be conveniently bound to the list view. However, the flattened object does no longer represent the actual hierarchy of your data, thus making it non suitable for editing. That said, how can we handle data editing scenario? Is it possible to enable data editing while leveraging view projection? Read on.
The quick answer is yes — data editing can be used together with view projection, but we’ll get there a bit later. When using view projection, we suggest that you load only necessary data that is actually used in the list view. Since the loaded data is not designed to be editable, the best practice for data editing is to reload the data complete with the related entities on demand, typically when user tapped on the cell to navigate. Thanks to the full-fledged app framework and entity services in Crosslight, that can be easily done in the Navigated method of EditorViewModel instance, like so:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
public async override void Navigated(NavigatedParameter parameter) { base.Navigated(parameter); if (parameter.Data != null) { this.ActivityPresenter.Show("Loading"); this.IsDataLoading = true; // reload item along with the specified navigation properties await this.Repository.GetSingleAsync((parameter.Data as SalesOrderHeader).SalesOrderID, new string[] { "Customer", "Address1", "SalesOrderDetails", "SalesOrderDetails.Product" }); // call OnItemChanging so the recently fetched related entities can be tracked after item reloading this.OnItemChanging(this.Item, this.Item); this.IsDataLoading = false; this.ActivityPresenter.Hide(); } } |
The above code is quite self explanatory. It will asynchronously load the entity along with the related entities given its primary key value when the editor view is navigated. The essence of the above code lies in the GetSingleAsync method which now has a new overload that accepts an array of related properties to be reloaded along with the entity in one shot. That’s really intuitive.
To improve performance, it’s wise to load the entity only when it’s navigated the first time. That’s pretty easy to implement, let’s make changes to the code like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
public async override void Navigated(NavigatedParameter parameter) { base.Navigated(parameter); if (parameter.Data != null) { // only load additional data if it hasn't been loaded previously if (this.Item.Customer == null) { this.ActivityPresenter.Show("Loading"); this.IsDataLoading = true; // reload item along with the specified navigation properties await this.Repository.GetSingleAsync((parameter.Data as SalesOrderHeader).SalesOrderID, new string[] { "Customer", "Address1", "SalesOrderDetails", "SalesOrderDetails.Product" }); // call OnItemChanging so the recently fetched related entities can be tracked after item reloading this.OnItemChanging(this.Item, this.Item); this.IsDataLoading = false; this.ActivityPresenter.Hide(); } } } |
Piece of cake. Now, if the properties of the entity has changed, or the related entities have changed during editing, the changes won’t sync back to the list view. That’s actually normal, because the objects in the list view is no longer related to the entities being edited. Remember the code we wrote above? We reloaded the entity specifically for editing purpose during navigation.
There’s where the new entity.UpdateProperties() API comes to rescue. Simply call the API on the edited entity, it will automatically scan the changes and reflect them back to the projected properties. And even better, if you’ve upgraded to Crosslight 4’s Enterprise App Framework, then you have zero line of code to write. That’s made possible because the API is now baked to the DataEditorViewModelBase class, specifically in the OnDataChanged method. Here’s the code snippet for your convenience:
1 2 3 4 5 6 7 8 9 |
/// Called when a data item is changed. protected override void OnDataChanged(TModel item) { IEntity entity = this.Item as IEntity; if (entity != null) entity.UpdateProperties(); base.OnDataChanged(item); } |
And here’s the result as expected using the view projection samples:
You might be wondering how the UpdateProperties API does its magic. How does it know which related entities have changed and which projected properties to sync back? The answer lies in the Crosslight’s powerful data framework which has complete information about the entity’s relationships and its metadata as well as built-in changes management.
If you haven’t familiar with Crosslight data framework — or haven’t used it yet, I strongly recommend you to start using it. Learn more here.
Now, let’s pull the data samples from our Git and see the editing in action with view projection. Run the sample in either iOS and Android platform, tap on a cell, edit some fields, i.e., City, then save it. Go back to the list view, voila, the changes are sync’ed back as expected, just as if it were an entity loaded with navigational properties.
In this post, we’ve looked at how a data-driven Crosslight app is built, covering both data list and editing by combining view projection and entity’s API. Now you also have better understanding on how Crosslight is designed to provide great developer experiences by eliminating much of the boilerplate code, so you can focus on the code that matters to your business apps. If you’ve any questions, we’d be happy to welcome you aboard on our community forum.
Best,
Jimmy