[Bind(Direction.ServerToClient)] persistence on the client

From what I’ve managed to see in our project, decorating a property with [Bind(Direction.ServerToClient)] makes its value go in one direction from the server to the client. So far so good. But also it is lost on the next fetch from the server.

Is there a way, without complicating things with javascript, to achieve client-side persistence for this kind of properties?

One concrete example: we have a string property with [Bind(Direction.ServerToClient)] that is used in the Html property of a <dot:HtmlLiteral which has the boring purpose of showing a title for a grid view below it. We simply do not need its value on the server-side, we just set it and off with it to the client. But on the client , as soon as we push a button and make interaction with the server through command: binding, the html title disappears although on the server we did not explicitly set or deleted its value.

So, we’re stuck with [Bind(Direction.Both)] (which I know is the default). Somehow I see the need of a binding option that is between [Bind(Direction.ServerToClient)] and [Bind(Direction.Both)], one that does not send the value back to the server but persists it on the client until further explicit update of its value from the server.

Is this even feasible? What do you think?

@tomasherceg
Another example that is a major one:

If we have 3 or more fat grid views on the page (many columns and rows) largely only for viewing purposes, we really do not need the entire dataset pages (Items collection) sent back to the server as we can manage the eventual single rows or cells needed at PostBack by sending them as param to command bindings in hidden buttons inside the grids. The processing we do on the server-side needs lots of properties from the main view model as the business logic is not trivial at all and pages are complex, so the “static command” approach is not suited for this, especially because this would imply writing javascript to map results from server to client view model and we avoid writing javascript as much as possible. This is more of an argument when we consider that switching to static commands approach will result in more custom javascript written than on the WebForms counterpart.

Again, it seems we are stuck with the default [Bind(Direction.Both)] which means a lot of data is send back to server needlessly, when in fact what we want is to send the data set only once when it is needed (a subgrid is shown or changes its page) and then to persist on the client until some later update (after possible many other postbacks that deal with other stuff like downloading/uploading files or editing rows, changing stuff in other grids on the same page etc.)

What was tried, tested:

  • If we put the data set property on [Bind(Direction.ServerToClient)] or [Bind(Direction.ServerToClientPostback)], the grid page is shown but on the next postback (by command binding) page fails with “There is no empty (virtual) nest to be cleared.” and “Could not serialize viewModel of type MgmOperations. Serialization failed at property OperationsInstance.OperationsHistoryDataSet”, of course.
  • If we put it on [Bind(Direction.IfInPostbackPath)] (I’ve read about its usage) it fails again on the next postback with “Could not deserialize viewModel of type MgmOperations. Serialization failed at property viewModel.OperationsInstance.OperationsHistoryDataSet.PagingOptions.” with the dataset containing nulls, which is to be expected.

In WebForms model we had the grid page updated within an UpdatePanel control, the html was changed on the client and the data was stuck there until further update (there was no knockout framework to overwrite it on each client comeback), in the meantime other parts of the page or grid were independently updated without interfering with the dataset of the grid's page while the dataset was in fact not existing on the client, what existed was just that part of the html with the data baked into it.

Is there no other alternative to 1) stick with default [Bind(Direction.Both)] and trafficking all that data at each postback (by command bindings); 2) pushing the grid’s page dataset through a static command and writing custom javascript to cache that page while doing other actions on the grid or page until further grid page update (a case where an entire page dataset push is justified) ?

I think that you are looking for Direction.ServerToClientFirstRequest. The property will not be sent from the server on postback, so it will not reset.

This looks like a glitch with Encrypted view model properties. If you want to use ServerToClientPostback, there is no point in encrypting anything in the collection. However, it should not crash in any of these cases, I’ll look into this. Could you please try it without the encrypted properties?

This was tested also and does not suit the context, as it goes to the client only on the first request. The context is that we have subsequent updates to that property.

Sure

With [Bind(Direction.ServerToClient)] it kabooms on the first postback after the gridview is shown on the page (when for example I click to select a row which triggers a hidden button having a “command:” binding):

With [Bind(Direction.ServerToClientPostback)]:
the same… the exception in both cases making sense of course, the binding direction is only one way. What we need is to be both ways.

Sure, as the property value never gets back from the client.

Ok, that’s expected, unless you reload the same data in Load.

We don’t really have a way to set the property only if some condition is met, you can only transfer it always or never. If your main concern is the transfer size, note that you can use Server-side viewmodel cache | DotVVM Documentation. However, large view models than shift pressure from client network to server memory.

I see.
Well then, thanks!