3
votes

I have gone through as many questions on here as I could find and tried all the different suggestions and cannot get this to work. I have a view that is bound with Knockout using the mapping plugin and it works okay but only when I do the "wrong thing". Everything that I have read says that you should only make one call to ko.applyBindings() per view and then everything should update using ko.mapping.fromJS(). I cannot seem to get this to work, the only way I have been able to get my view to refresh is to call ko.applyBindings() again in the success call back from my .ajax() call. Here is the offending code.

<script type="text/javascript">
    var viewModel;

    $(document).ready(function() {
        $("#panelbar").kendoPanelBar({
            expandMode: "multiple"
        });

        $.ajax({
            type: 'GET',
            url: '/Home/IsUserMarketingManager',
            success: function (data) {
                if (data == true) {
                    $('#submitNewCase').hide();
                    $('#approveCase').show();
                    $('#disapproveCase').show();
                }
            }
        });

        // Generate client View Model from Server View Model
        viewModel = new ViewModel();
        ko.mapping.fromJS(@Html.Raw(Json.Encode(Model)),{}, viewModel);
        ko.applyBindings(viewModel);
    });

    function ViewModel () {
        var self = this;

        self.addLocation = function() {
            self.AdditionalLocations.push({ GaNumber: "" });
        };
    }
</script>

And later this to update the form with retrieved data:

<script type="text/javascript">
    $('#btnImport').click(function () {
    $.blockUI({ message: '<h2>Importing Client Information...</h2> <img src="/Images/ajax-loader.gif"><br />' });
    $.ajax({
        type: 'post',
        url: '/Home/ImportClientCrmInfoJson',
        dataType: "json",
        data: ko.mapping.toJS(viewModel),
        success: function (data) {
            $.unblockUI();
            if (!data.AccountNull) {
                ko.mapping.fromJS(data, {}, viewModel);
            } else {
                alert("Could not find account for this GA Number, please try again.");
            }
        }
    });
});
</script>

When submitting the form to my controller, all the data is there and mapped correctly to my server side View Model, but the form in the view isn't updated with the data that comes back from the $.ajax call. I've gotten the form to update if I do the following, but I know it's not the right way and has caused me other issues as well.

 <script type="text/javascript">
    $('#btnImport').click(function () {
    $.blockUI({ message: '<h2>Importing Client Information...</h2> <img src="/Images/ajax-loader.gif"><br />' });
    $.ajax({
        type: 'post',
        url: '/Home/ImportClientCrmInfoJson',
        dataType: "json",
        data: ko.mapping.toJS(viewModel),
        success: function (data) {
            $.unblockUI();
            if (!data.AccountNull) {
                viewModel = ko.mapping.fromJS(data);
                                ko.applyBindings(viewModel); // This works but isn't the right way...
            } else {
                alert("Could not find account for this GA Number, please try again.");
            }
        }
    });
});
</script>

Any help would be much appreciated.

2
Have you confirmed that it's not because !data.AccountNull is evaluating to false which would skip the ko.mapping.fromJS() call?Matthew Cox
Yes, I've tried removing that and it doesn't change the result.Brian Maupin

2 Answers

0
votes

Have you examined that the following line of code appears to create a 'NEW' viewmodel?

viewModel = ko.mapping.fromJS(data);

When you do this the new viewModel the old bindings are destroyed. This is why you have to call ApplyBindings again. Anyway, I think the above line of code is the root of the problem.

Is there a way for you to create an observable property on the viewModel and allow the viewModel to reflect the data in this object? That may be a more practical approach to the update process.

0
votes

In the success callback of the ajax call, use this method ko.applyBindings(viewModel) but pass as a second parameter the DOM portion you want to update as follows

ko.applyBindings(viewModel, $("#mydiv")[0])

Don't use a jquery object but a REAL DOM object.