0

I'm trying to implement master-slave web page where on the left side is a control on which you can choose an element. On the right side chosen element's details are shown. I'm using asp.net mvc and I've already implemented master control which downloads (using ajax) element's details.

EDIT
Thanks to photo_tom's response and my further research I managed to reload sub-viewmodel and details sub-page. Unfortunately it doesn't work :( If I do something similar to this it works fine. But it fails if I only try to place the inner html dynamically and change the viewmodel afterwards. How to make the bindings work with dynamically replaced element's innerHtml?

@{
    ViewBag.Title = "Products";
}

<h2>Products</h2>

<div class="ms-master">
    <select size="15" data-bind="
        options: Products,
        optionsText: 'Name',
        value: CurrentProduct
        ">
    </select>
</div>

<div class="ms-slave" data-bind="
    with: CurrentProductVM">
  <div data-bind="html: $parent.CurrentProductHtml" />
</div>

<script type="text/javascript" language="javascript">
    function Product(data) {
        var self = this;
        ko.mapping.fromJS(data, {}, this);
    };

    function ViewModel(data) {
        var self = this;
        if (data != undefined) {
            ko.mapping.fromJS(data, {
                'Products': {
                    'create': function(d) {
                        return new Product(d.data);
                    }
                }
            }, this);
        }

        self.CurrentProductHtml = ko.observable();
        self.CurrentProductVM = ko.observable();
        self.CurrentProduct = ko.observable();
        self.OnCurrentProduct = function(value) {
            $.getJSON(
                self.DetailsUrl(),
                { id: value.Id() },
                function (result) {
                    self.CurrentProductVM(result.Model);
                    self.CurrentProductHtml(result.View);
                }
            );
        };
        self.CurrentProduct.subscribe(self.OnCurrentProduct);
    };

    $(function () {
        var model = @Html.Raw(Json.Encode(Model.Data));
        var vm = new ViewModel(model);
        ko.applyBindings(vm);
    });
</script>

OLD POST

The Details action on the controller returns PartialView on which I want to have a separate KO's viewmodel which controlls the partial view. How to do it? Maybe there's better solutions for my problem?

Here's similar problem but using this solution I'll have to query controller twice: once to get VM, second time to get view, wouldn't I?

JS

function Product(data) {
    var self = this;
    ko.mapping.fromJS(data, {}, this);

    self.AsyncDetails = ko.observable();
    self.OnSelect = function() {
        $.get(
            '@Url.Action("Details", "ProductsMgm")',
            { id: self.Id() },
            function (e) {
                self.AsyncDetails(e);
            }
        );
    };
};

function ViewModel(data) {
    var self = this;
    if (data != undefined) {
        ko.mapping.fromJS(data, {
            'Products': {
                'create': function(d) {
                    return new Product(d.data);
                }
            }
        }, this);
    }

    self.CurrentProduct = ko.observable();
    self.OnCurrentProduct = function(value) {
        value.OnSelect();
    };
    self.CurrentProduct.subscribe(self.OnCurrentProduct);
};

** HTML **

<div class="ms-master">
    <select size="15" data-bind="
        options: Products,
        optionsText: 'Name',
        value: CurrentProduct
        ">
    </select>
</div>

<div class="ms-slave" data-bind="
    with: CurrentProduct">
    <div data-bind="html: AsyncDetails" ></div>
</div>
Community
  • 1
  • 1
SOReader
  • 5,697
  • 5
  • 31
  • 53

1 Answers1

0

I've done this with list and edit views on the same page. In general, do the following if editing the detail.

  1. Retrieve all the data for both sides of screen in initial ajax call.
  2. When user clicks on "EDIT" button (for example), pass the right side object to an "Edit" function.
  3. The "Edit" function the following:

    • Makes a deep copy of the Edit object passed into it. This keeps any edits from be immediately reflected in the original object.
    • Copies the contents of the new Edit object to the observables on the right side.
    • When the user is done and has changed the data, send updated data to server via ajax and then update contents of the original Edit object

EDIT - in response to first comment First read https://stackoverflow.com/a/10590386/136717 on how to retrieve a partial view via ajax.

Basic Procedure will be - 1. When you render your left side, on the control that is clicked to retrieve the data, add a Click binding. Look at http://knockoutjs.com/documentation/click-binding.html for full details. 2. Your current data item will be passed as a parameter. In your "click" function, build a url to retrieve your partial view. 3. Call your new library function that will do the ajax call and then load the html into area that you want.

Community
  • 1
  • 1
photo_tom
  • 7,292
  • 14
  • 68
  • 116
  • I can't really do so. I want to have the right-side controlled by a separate viewmodel which will be retrieved from server with a partial view, so I can create a general solution, reusable in many places in my project. Any other ideas how to achieve this functionality? – SOReader Dec 24 '12 at 19:04
  • Thanks for the hint how to send back view and model in one response. But the bindings still do not work :( – SOReader Dec 26 '12 at 02:50
  • Can you build a fiddle to show what it happening? One question, do your bindings work once or never? – photo_tom Dec 26 '12 at 12:24
  • I'd like to but I don't know how to simulate ajax calls. It would be more simple if I give you link to SVN: https://aspmvc-knockoutjs.googlecode.com/svn/trunk – SOReader Dec 26 '12 at 17:25
  • Lets continue this in chat room I've created at http://chat.stackoverflow.com/rooms/info/21760/question-14022384-discussion?tab=general – photo_tom Dec 27 '12 at 11:00