Question

I am attempting to utilise KnockoutJS and MVC 4 in order to display a table with ActionLink definitions in the first column of the table. Displaying the data itself is extremely straight-forward and I'm not having any problem there. The problem I have is in the generation of the ActionLink's.

I have taken a look at Use MVC helpers inside jquery.tmpl templates, but the solution there does not utilise knockout templates and inserting the Url into the model object is not feasible (the app domain model objects used to create the view model will be used extensively through out the application).

The table definition:

<table>
    <tbody data-bind="template: { name: 'dmuTableDetail', foreach: tables() }"></tbody>
</table>

(tables is an observable array, hence the parens).

The knockout template definition:

<script id="dmuTableDetail" type="text/html">
    <tr>
        <td>@Html.ActionLink("Details", "Details", "DMUTableCategory", new { @Id = ??? } )</td>
        <td data-bind="text:TableId"></td>
        <td data-bind="text:TableName"></td>
    </tr>
</script>​

The View Model definition:

var PageViewModel = function () {
    self = this;

    self.tables = ko.observableArray([]);

    self.readItems = function () {
        self.tables(jQuery.parseJSON('[{"TableId":1001, "TableName":"Table#1"},{"TableId":1002, "TableName":"Table#2"}]'));
    }
}

$(document).ready(function () {
    vm = new PageViewModel();
    self.readItems('');
    ko.applyBindings(vm);
});

(the actual code performs an Ajax call to retrieve the data, but the code above also demonstrates the issue).

Regardless of what I replace the ??? with, I am unable to get the value of the TableId field to be inserted into the href.

Any help would be greatly appreciated.

Thankyou.

Était-ce utile?

La solution

Thankyou Eric, you got me thinking about an anchor element and binding the href attribute.

It seems the answer is a little easier than expected (it usually is!).

The table definition: (same as original question)

<table>
    <tbody data-bind="template: { name: 'dmuTableDetail', foreach: tables() }"></tbody>
</table>

The knockout template definition: (change to the binding of the href attribute).

<script id="dmuTableDetail" type="text/html">
    <tr>
        <td><a data-bind="attr: { 'href': '@Url.Action("Details", new RouteValueDictionary() { { "Controller", "DMUTableCategory" } } )/' + TableId }">Details</a></td>
        <td data-bind="text:TableId"></td>
        <td data-bind="text:TableName"></td>
    </tr>
</script>?

The View Model definition: (same as original question)

var PageViewModel = function () {
    self = this;

    self.tables = ko.observableArray([]);

    self.readItems = function () {
        self.tables(jQuery.parseJSON('[{"TableId":1001, "TableName":"Table#1"},{"TableId":1002, "TableName":"Table#2"}]'));
    }
}

$(document).ready(function () {
    vm = new PageViewModel();
    self.readItems('');
    ko.applyBindings(vm);
});

You dont actually need to RootValueDictionary but I've included it so people can see how to change the controller the request is sent to.

Autres conseils

Knockout binds completely on the client side, which is after MVC has rendered the HTML for your page and sent it back to the original browser.

If you want your Knockout template to be able to use a URL that is generated on the server, then you'll have to employ some clever strategy similar to the following:

CSHTML:

@{
    // create a dummy URL that you can use as a template
    string hrefFormat = Url.Action("Details", "DMUTableCategory", new { id = "{ID}" });
}

<script type="javascript">
    // a global string (but you can put it where ever you need to)
    var _hrefFormat = @Html.Raw(hrefFormat)
<script>

JS:

self.readItems = function () {
    self.tables(jQuery.parseJSON('[{"TableId":1001, "TableName":"Table#1"},{"TableId":1002, "TableName":"Table#2"}]'));


    // loop through the 'tables' and add a new 'href' property to each for binding
    ko.utils.arrayForEach(self.tables(), function(table){
         table.href = _hrefFormat.replace("{ID}", table.TableId);
    });
}

Your KO Tmpl where you bind the 'href' property of each table object to the a tag's href attribute:

<script id="dmuTableDetail" type="text/html">
    <tr>
        <td><a data-bind="attr: { 'href': href }">Details</a></td>
        <td data-bind="text:TableId"></td>
        <td data-bind="text:TableName"></td>
    </tr>
</script>​
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top