0
votes

I have a page with a table, bound with Knockout inside an UpdatePanel. My goal is to get the binding successfully applied after a postback. Everything works as expected on initial page load, so the model is working.

I'm using pageLoad() to call a function that gets the model's JSON data from a HiddenField that was set server side. In the view I have each RadioButton's click data-bind set to a JS function outside the ViewModel that sets a hidden input field's value to the ID specified by the button, and then causes a server postback by clicking a hidden button client-side.

Inside pageLoad() I'm using Sys.WebForms.PageRequestManager.getInstance().add_endRequest to specify that the binding helper function should be called after the server-side of the postback is complete.

My problems:

After being set server-side, the HiddenField with the JSON data still has the same string as it did client-side when it returns to the client, even though when the server-side scriptlet is executed, I can see that the value updated correctly. Not sure what is going on here.

Even if the values don't update, BindingHelper() is called, although for some reason clicking on the RadioButtons no longer causes the event after one postback has already occurred.

Any insight into this would be greatly appreciated!

Code:

<script type="text/javascript">

     Sys.WebForms.PageRequestManager.getInstance().add_endRequest(BindingHelper)

     function pageLoad() {
        if (!isPostBack()){
            BindingHelper();
        }
    }

    function BindingHelper() {
        var data = <%= hfData.Value%>;
        var model = new DataViewModel();

        model.load(data);
        ko.applyBindings(model);
    }

     function Select(id) {
        document.getElementById('<%=hfSelectedID.ClientID%>').value = id;
        document.getElementById('<%=rbSelect.ClientID%>').click();
    }

    function isPostBack() {
        return document.getElementById('hfPostback').value == 'True';
    }
</script>

HTML:

<table id="tblData">
    <thead>
        <tr>
            <th></th>
            <!-- ko foreach: subViewModel -->
                <th><input type="radio" name="rbGroup" data-bind="value: id, checked: $root.selectedID, click: function() {Select(id);}" /><span data-bind="text: name"></span></th>
            <!-- /ko -->
         </tr>
    </thead>
</table>

<asp:HiddenField ID="hfData" runat="server" />

<asp:HiddenField ID="hfSelectedID" runat="server" />
<input id="hfPostback" type="hidden" value="<%=Page.IsPostBack.ToString()%>" />

<div style="display:none">
    <asp:RadioButton ID="rbSelect" runat ="server" AutoPostBack="true" />
</div>

Edit: I've since determined that this works if the binding is not inside an UpdatePanel, just by registering BindingHelper() as a startup script in Page_Load.

Oddly enough, even if I register the startup script by specifying the UpdatePanel, the results are the same. There are other controls in the UpdatePanel so I know the UpdatePanel is in fact, updating, and it isn't set to conditionally update.

1
I've also tried calling BindingHelper when it is a postback as well, but this causes the binding to be messed up and shows too many rows in the table. With a (!ko.dataFor(document.getElementById('tblBenefits')) check, I can see that on postback, the bindings are still there, and yet if I include that as a condition it is never bound on postback. - barthooper

1 Answers

0
votes

I solved this. I ended up needing to find the HiddenField in the DOM and then parsing the JSON from that to get the data for the model. It seems weird to me that even after the value had been set server-side, it was keeping the old value, but the UpdatePanel complicates the lifecycle.

Also I changed the RadioButton that is clicked client-side to a LinkButton to get it to always force a postback to the server.