简体   繁体   中英

Knockout: Bind template bootstrap modal for many data objects

I am relatively new in Javascript and Knockout JS and I am facing the problem below:

I load data from a Ajax request and map it into my object:

function ActivityModel(obj) {
        if (typeof (obj) != 'undefined') {
            this.ShowTable = ko.observable(true);
            this.Name = ko.observable(obj.nomVessel);
            this.NumRecords = ko.observable(obj.data.length);
            this.DataRecords = ko.observableArray([]);
            var aux = [];
            //When add new items, mark they as changed, so the update css style  will be loaded
            $.each(obj.data, function (index, value) {
                aux.push({ hasChanged: ko.observable(true), record: value });
            });
            this.DataRecords.push(aux);

        }
}

I store all objects into an observable Array named DataTables. Then, based on the data, I render a 'gadget', that is composed by a div with some buttons, and a table that loads my data records:

<!-- ko foreach: DataTables -->
<div class="col-sm-6"> 
    <div class="box gadget">
        <div class="box-header clearfix">
            <a  href="#" class="close-btn" title="Delete Gadget"  data-bind="click: function (data, event) { $root.DeleteGadget(data, event) }"><i class="glyphicon glyphicon-remove"></i></a>
            <a href="#" class="minimize-btn" title="Minimize Gadget"><i class="glyphicon glyphicon-chevron-up"></i></a>
            <h1><strong><span data-bind="text: $data.Name"></span></strong> - Activities</h1>
            <div class="icons pull-right">
                <a href="#modal-configure-gadget" title="Configure Gadget" data-toggle="modal"><i class="glyphicon glyphicon-cog"></i></a>
            </div>
        </div>
        <div class="box-body">
            <div class="table-responsive">
                <table class="table table-bordered table-hover text-left density-medium">
                    <thead>
                        <tr>
                            <th>Start Date</th>
                            <th>Start Time</th>
                            <th>End Date</th>
                            <th>End Time</th>
                            <th>Details</th>
                        </tr>
                    </thead>
                    <tbody data-bind="foreach: $data.DataRecords">
                        <tr  class="tooltipstered" data-bind="tooltipster: 'bottom-right'">
                            <td data-bind="text: $data.record.startDate"></td>
                            <td data-bind="text: $data.record.endDate"></td>
                            <td data-bind ="text: $data.record.details"></td>

                        </tr>
                    </tbody>
                </table>
            </div>
          </div>         
    </div>
</div>
<!-- /ko -->

Particularly, I have a button to open a bootstrap modal inside each gadget:

<div class="icons pull-right">
                <a href="#modal-configure-gadget" title="Configure Gadget" data-toggle="modal"><i class="glyphicon glyphicon-cog"></i></a>
</div>

The code of the modal

<div id="modal-configure-gadget" class="modal fade modal-configure-gadget" role="dialog" tabindex="-1">
        <div class="modal-dialog">
            <div class="modal-content">
                <div class="modal-header shadow">
                    <button type="button" class="close" data-dismiss="modal">×</button>
                    <i class="icon-arrow-down-circle"></i><span class="h2">Configure <strong>gadget</strong></span>
                </div>
                <div class="modal-body">
                    <form action="" class="form-horizontal" role="form">
                        <div class="row">
                            <div class="col-sm-6">
                                <span class="h2">Set <strong>size</strong></span>
                                <div class="box box-filter">
                                    <div class="form-group row">
                                        <label for="linhas" class="control-label col-sm-4">Rows:</label>
                                        <div class="add-remove-button col-sm-8">
                                            <span class="btn btn-mini btn-navbar decrease-button">
                                                <i class="glyphicon glyphicon-minus"></i>
                                            </span>
                                            <input id="linhas" type="text" class="form-control" value="1">
                                            <span class="btn btn-mini btn-navbar increase-button">
                                                <i class="glyphicon glyphicon-plus"></i>
                                            </span>
                                        </div>
                                    </div>                              
                                </div>
                            </div>
                        </div>
                    </form>
                </div>
                <div class="modal-footer shadow">
                    <button class="btn btn-success">Ok</button>
                    <button class="btn btn-success" data-dismiss="modal" aria-hidden="true">Cancel</button>
                </div>
            </div>      
        </div>
    </div>

My problem is: For each 'gadget' created, I would like to bind the button I've shown to open the modal. Moreover the input 'linhas' inside the modal should be bound to the observable NumRecords of my object. When I tried to bind using a simple click binding I have an unexpected behaviour that I changed the value of the input for one object (thus updating a single observable NumRecords) and the call was somehow broadcasted to the other gadgets on the screen. I also tried using a custom binding:

ko.bindingHandlers.UpdateActivityCount = {
init:function(element, valueAccessor, allBindings, viewModel, bindingContext) {
    $('#modal-configure-gadget').on('show.bs.modal', function(e) {
        $('#linhasActivity').val(bindingContext.$data.NumActivities());
    });
},
update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {

    $('#modal-configure-gadget .btn-success').on('click', function(e) {

        var confirm_button = $(e.target).is("#btnConfirmActivitiesChange");

        if (confirm_button === true) {
            //Update Value
            self.UpdateObservableValue(data.NumRecords, $('#linhasActivity'), 'int', data, event);
        }

    });
}
};

but the unexpected behaviour remained.

I suspect this behaviour is occurring because the id of the modal and its elements are the same of every gadget created (Instead having one modal for each gadget, I have just one modal for all of them and it is generanting a conflict). However, I do not know how to generate multiple modals with different ids (and different ids for the components such as buttons and inputs). I had a look at the component binding, but could not realise how it works and whether it would be useful to solve my problem.

Anyone has a suggestion?

Thanks.

Some suggestions

at

<tbody data-bind="foreach: $data.DataRecords">
    <tr  class="tooltipstered" data-bind="tooltipster: 'bottom-right'">
        <td data-bind="text: $data.record.startDate"></td>
        <td data-bind="text: $data.record.endDate"></td>
        <td data-bind ="text: $data.record.details"></td>
    </tr>
</tbody>

you dont need to use the $data variable, since you are already inside a foreach context. You can replace it with

<tbody data-bind="foreach: DataRecords">
    <tr  class="tooltipstered" data-bind="tooltipster: 'bottom-right'">
        <td data-bind="text: record.startDate"></td>
        <td data-bind="text: record.endDate"></td>
        <td data-bind ="text: record.details"></td>
    </tr>
</tbody>

Also for modal dialog, you can have one dialog to show details of different objects. Something like

<!-- ko with: currentDialogDetails -->
<input id="linhas" type="text" class="form-control" data-bind="textInput: NumRecords" />
<!-- /ko -->

and the have a click binding for opening up the dialog like

<div class="icons pull-right">
    <a href="#modal-configure-gadget" data-bind="click: $root.setCurrentDialogDetails" title="Configure Gadget" data-toggle="modal"></i></a>
</div>

and in your view model, add an observable and another click handler as

this.currentDialogDetails = ko.observable(null);
this.setCurrentDialogDetails = function(details){
  this.currentDialogDetails(details);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM