Can I make knockout generate bindings from the val

2019-08-10 21:49发布

问题:

After asking this question and getting an answer I have a modal form which has its contents data bound to a knockout model. this is great and makes it generic and reusable, so long as the form follows the same pattern as template, ie a couple of buttons and a fixed body.

What I would like is to make the body dynamic and contain input fields bound to other values on my view model.

So I have this:

<script id="myModal" type="text/html">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-bind="click:close" aria-hidden="true">&times;</button>
                <h3 data-bind="html:header"></h3>
            </div>
            <div class="modal-body">
                Name:<input type="text" data-bind="value: paramName" /><br/>
                Type:<input type="text" data-bind="value: paramType" /><br />
            </div>
            <div class="modal-footer">
                <a href="#" class="btn" data-bind="click:close,html:closeLabel"></a>
                <a href="#" class="btn btn-primary" data-bind="click:action,html:primaryLabel"></a>
            </div>
        </div>
    </div>
</script>

which extends the form to include a couple of text input fields. Can I make this body content so that it is still populated from my view model, but still has the data-bindings. So have a vierw model that looks like this:

modal = {
    header: ko.observable("This is a modal"),
    body: ko.observable("Name:<input type='text' data-bind='value: paramName' /><br/>Type:<input type='text' data-bind='value: paramType' /><br />"),
    paramName: ko.observable(),
    paramType: ko.observable(),
    closeLabel: "Cancel",
    primaryLabel: "Ok",
    show: ko.observable(false), /* Set to true to show initially */
    onClose: function () {
        self.onModalClose();
    },
    onAction: function () {
        if (self.modal.paramName() && self.modal.paramType()) {
            self.nextParameter.name(self.modal.paramName());
            self.nextParameter.type(self.modal.paramType());
            self.addInputParameter();
            self.modal.show(false);
        }            
    }

and have the template go back to being generic like this

<script id="myModal" type="text/html">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-bind="click:close" aria-hidden="true">&times;</button>
                <h3 data-bind="html:header"></h3>
            </div>
            <div class="modal-body" data-bind"html: body">
            </div>
            <div class="modal-footer">
                <a href="#" class="btn" data-bind="click:close,html:closeLabel"></a>
                <a href="#" class="btn btn-primary" data-bind="click:action,html:primaryLabel"></a>
            </div>
        </div>
    </div>
</script>

but still have knockout bind changes to the first input to paramName and changes to the second input to paramType

回答1:

I would handle this with a dynamic template, as described in note 5 here. So it would look something like this:

modal = {
    header: ko.observable("This is a modal"),
    //this is now just the name of the template
    body: ko.observable('bodyTemplateA'),
    // ...
};

And then in your binding, do

<div class="modal-body" data-bind="template: { name: body }">
</div>

and then of course define all of your needed templates separately:

<script id="bodyTemplateA" type="text/html">
     Name:<input type="text" data-bind="value: paramName" /><br/>
     Type:<input type="text" data-bind="value: paramType" /><br />
</script>

Not quite what you were looking for, but I think that'll be a lot easier and maintainable than trying to keep all your various ko-bound html in strings throughout your code.