public static object HeaderDoc(View <CalculatorViewModel> viewCalculator, Var <string> page, string idParent) => V(viewCalculator.V.SessionStorage).Map(thisStorage => { return(new Template.Header.Main() .IdStorageLink(Id(idParent, StorageLink)) .Storage(V(viewCalculator.V.VSessionStorage)) .StorageLink(async(el, ev) => { // WebSharper compiler doesn't accept switch() here if (page.Value == IndexDoc.Single) { // Single calculator -> Switch to the triptych page page.Set(IndexDoc.Triptych); } else if (page.Value == IndexDoc.Triptych) { // Change storage globally await StorageServer.SetStorage(thisStorage); // Switch back to the single calculator page page.Set(IndexDoc.Single); } else { throw new Exception(string.Format( // JS: no NotImplementedException "Page {0}", page.Value)); } }) .Doc()); });
/// <summary> /// Subpage: The content is built up on the server side, session /// persistence is handled either on the client (ViewState) or on the /// server (Session/Database). /// </summary> /// <returns></returns> public static WebSharper.UI.Doc WithStorageDoc() { var storage = Var.Create(asplib.Model.Storage.ViewState); var contentList = new ListModel <string, string>(s => s); var contentTextBox = Var.Create(""); // Setup the reactive ViewState storage. var viewState = Var.Create(""); return(WebSharper.UI.Doc.ConcatMixed( input(viewState, attr.type("hidden")) , new Template.Withstorage() .ContentTextBox(contentTextBox) .Back((el, ev) => { IndexDoc().RunById("page"); }) // <input ws-var="Storage" value="${ViewState}" type="radio" /> ViewState // in the template yields: // Using ws-var on a <input type="radio"> node is not supported yet, thus programmatic. // Auto-generates the name: <input name="uinref4" type="radio">, manual ids for test.SelectID(). .StorageRadio( label( radio(storage, asplib.Model.Storage.ViewState, attr.id("storageViewState")), "ViewState" ), label( radio(storage, asplib.Model.Storage.Session, attr.id("storageSession")), "Session" ), label( radio(storage, asplib.Model.Storage.Database, attr.id("storageDatabase")), "Database" ) ) .ListContainer( contentList.View.DocSeqCached((string x) => new Template.Withstatic.ListItem().Item(x).Doc() ) ) .ChangeStorage(async(el, ev) => { // Set the static storage override globally for the // instance, as the concept of SessionStorage makes little // sense when it's required to carry it's value along with // the single stored Storage object itself. await StorageServer.SetStorage(storage.Value); // Reload the object from the other storage. var newContent = await StorageRemoting.Reload(viewState.Value); // Write back the changed model object state // to the reactive variable. viewState.Value = newContent.ViewState; // Update the view according to the model. contentList.Set(newContent.Content); }) .Submit(async(el, ev) => { // Retrieve the old stateful object, perform the transition // on it with all new input data passed as method arguments // in one single step, and immediately save the object in // its new state, thus making it effectively immutable from // here on. var newContent = await StorageRemoting.Add(viewState.Value, contentTextBox.Value); // Write back the changed model object state // to the reactive variable. viewState.Value = newContent.ViewState; // Update the view according to the model. contentList.Set(newContent.Content); // Clear entirely on the client side. contentTextBox.Set(""); }) .Doc() )); }