Domanda

I have a model in MVC called Entity that contains Properties and the value of these said properties can be one of 3 things. A Unit, DropDownSelection, or native type (int, string, datetime, etc.). Unit and DropDownSelection are pretty simple but they're displayed differently than the native types (DropDownSelection -> DropDown, Native -> Input, Unit -> Input + DropDown).

I personally know based on the Property[0].DataType but how do I go about conveying that information appropriately to Knockout so that it displays DropDownSelections in a Select Control, Native Types in Inputs, etc.

Current View

@model List<NMBS.EntityModels.Entity>

@* Page Content *@
<h1><span class="entity-type" data-bind="text: $data[0].EntityType"></span></h1>
<a data-bind="attr: { href: '/Entity/Create?EntityType=' + $data[0].EntityType() }" class="ignore">New</a>
<form>
    <table>
        <thead>
            <tr data-bind="template: { name: 'HeaderRowTemplate', foreach: $data[0].Properties }">
                <td data-bind="text: Name, visible: SummaryProperty"></td>
            </tr>
        </thead>
        <tbody data-bind="template: { name: 'DataRowTemplate', foreach: $data }">

        </tbody>
    </table>
</form>

@* Templates *@
<script id="HeaderRowTemplate" type="text/html">
    <td data-bind="text: Name, visible: SummaryProperty"></td>
</script>

<script id="DataRowTemplate" type="text/html">
    <tr data-bind="template: { name: 'DataItemTemplate', foreach: Properties }"></tr>
</script>

<script id="DataItemTemplate" type="text/html">
    <td data-bind="text: Value.ValueAsString, visible: SummaryProperty"></td>
</script>

@* Scripts *@
<script type="text/javascript">
    function ApplyBindings() {
        var data = @Html.Raw(new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(Model)),
            viewModel = ko.mapping.fromJS(data);
        ko.applyBindings(viewModel);
    }
    ApplyBindings();
</script>

Entity Properties

public Int32 ID { get; set; }
public String EntityType { get; set; }
public Int32? ParentID { get; set; }
public Int32? PropertyValueID { get; set; }
public List<Property> Properties { get; set; }
public Entities Children { get; set; }
public Boolean IsValueEntity { get; set; }

Property Properties

public Int32 ID { get; set; }
public String Name { get; set; }
public String DataType { get; set; }
public Boolean Required { get; set; }
public Boolean OnlyOne { get; set; }
public Boolean ForceNew { get; set; }
public dynamic Value { get; set; }
public String ValueAsString { get; set; }
public Boolean SummaryProperty { get; set; }

Question: How would I go about databinding values (i.e. Entity[i].Property[i].Value) to the correct Html Control? Is there a way to tell it explicitly or implicitly to use a specific template for certain values of DataType (Entity[i].Properties[i].DataType)?

È stato utile?

Soluzione

I'd say you need to look into writing your own custom binding handler. http://knockoutjs.com/documentation/custom-bindings.html

Note that even data-bind="text: fooVar" is just a pre-defined binding handler and you can always extend knockout with your own custom ones.

In your case, I would take the following route:

First, redefine your mark-up to accommodate the handler we'll be writing:

<script id="DataItemTemplate" type="text/html">
    <td data-bind="visible: SummaryProperty">
        <label data-bind="text: Value.ValueAsString" />
        <input data-bind="customFormControl: Value" />
    </td>
</script>

Secondly, we define our handler. In this case, I chose to test against your DataType property and then add the child element to your table cell.

ko.bindingHandlers.customFormControl = {
    init: function ( element, valueAccessor, allBindings, viewModel, bindingContext ) {
        var val = valueAccessor(),
            dataType = bindingContext.$data.DataType;
        if ( dataType == 'Unit' ) {
            // define and replace 'element'
        } else if ( dataType == 'DropDownSelection') {
            // define and replace 'element'
        } else { 
            // control is already an input, so this shouldn't need any work
        }
    }, update: function ( element, valueAccessor, allBindings, viewModel, bindingContext ) {
        // do as you wish when the values are updated.
    }
}

The key is to learn more about these parameters that knockout is tossing back to you. Once you understand bindingHandlers, you realize that just about anything you need to do via Knockout can be accomplished and the context is always available.

Best of luck.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top