StrugglingCoder
StrugglingCoder

Reputation: 5021

Selected Dropdown ids in Knockout JS

I have an array doorsForSitewhere each item will have a Doors Array and each door will have a Schedules array.

It looks like :

            var scheduleList = new[] 
            {
                new { ScheduleId = "Schedule1",ScheduleName = "Always On" },
                new { ScheduleId = "Schedule2",ScheduleName = "Never On"}
            };

            var doorsForSite = new[]
                {
                new { ControllerId ="controller1",ControllerName="Eagle",IsChecked = "false",
                        Doors = new[]
                        {
                            new { DoorId="Door1",DoorName="DoorOne",Schedules = scheduleList},
                            new { DoorId = "Door2", DoorName = "DoorTwo",Schedules = scheduleList}
                        }

                    },
                new { ControllerId ="controller2",ControllerName="NetAxis",IsChecked = "false",
                        Doors = new[]
                        {
                            new { DoorId=  "Door3",DoorName="DoorThree",Schedules = scheduleList},
                            new { DoorId = "Door4", DoorName = "DoorFour",Schedules = scheduleList},
                            new { DoorId = "Door5", DoorName = "DoorFive",Schedules = scheduleList}
                        }

                    }
            };

Now in UI ..

<ul class="accgrouptableaccordian scroll-x scroll-y">
    <!-- ko foreach: $data.AddModel.ControllerDoors -->
    <li>
        <div class="panel-group">
            <div class="panel panel-default">
                <div class="panel-heading">
                    <h4 class="panel-title">
                        <span>
                            <span>
                                <span class="ispicon ispicon_accordian_droparrow">
                                </span>
                                <span class="title" style="line-height:20px;" data-bind="text: ControllerName() + ' - ' + Doors().length + ' Doors'">
                                </span>
                            </span>
                            <span>

                            </span>
                        </span>
                    </h4>
                </div>
                <div class="panel-collapse">
                    <div class="panel-body">
                        <div class="table-responsive panel-body">
                            <table class="table">
                                <tbody data-bind="foreach:Doors">
                                    <tr>
                                        <td>
                                            <div>
                                                <span data-bind="text:DoorId"></span>
                                            </div>
                                        </td>
                                        <td class="col-md-4">

                                            <select name="drpSchedulesAccess" class="form-control drpSchedulesAccess" data-bind="options:$data.Schedules,
                                                optionsText: 'ScheduleName',
                                                optionsValue: 'ScheduleId',
                                                value: $data.ScheduleId"></select>
                                        </td>
                                    </tr>
                                </tbody>
                            </table>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </li>
    <!-- /ko -->
</ul>

But in Viewmodel I only want to get the values of the checked Door's selected Schedule in the dropdown.

But that's not happening.

I did

            ko.utils.arrayForEach(this.AddModel.ControllerDoors(), function (item) {
                ko.utils.arrayForEach(item.Doors(), function (item) {
                    doorsSelected.push(item);
                });

            });
            var doors = ko.utils.arrayFilter(doorsSelected, function (item) {
                return item.IsChecked == true;
            });

            var doorIds = ko.utils.arrayMap(doors, function (door) {
                if (jQuery.inArray(door.DoorId, doorIds) == -1) {
                    return door.DoorId;
                }
            });

            ko.utils.arrayForEach(doors, function (item) {
                debugger;
                ko.utils.arrayForEach(item.Schedules, function (item) {

                    $('.drpSchedulesAccess option:selected').each(function (i) {
                        schedulesSelected.push($(this).val());
                    });
                });

            });

and I checked 3 doors with 3 selected Schedule from dropdown.

But I am getting a schedule array length of 30.

Why is it so ?

enter image description here

Upvotes: 0

Views: 43

Answers (2)

super cool
super cool

Reputation: 6045

you might need to slightly tweek your code & most importantly do everthing is knockout-ish way .

viewModel:

var ViewModel = function() {
  var self = this;
  self.ControllerDoors = ko.observableArray(ko.mapping.fromJS(doorsForSite)()); // mapping to convert everything to observable
  self.check = function() {
    var doorsSelected = [];
    ko.utils.arrayForEach(self.ControllerDoors(), function(item) {
      //you can add condition here based on controllerName IsChecked & reduce looping
      ko.utils.arrayForEach(item.Doors(), function(item) {
        if (item.IsChecked())
          doorsSelected.push(item);
      });
    });
    console.log(doorsSelected);
  }
};

catch the working demo here and check console window to find Results .

Things to note :

() : used to read observable (you can find it's usage on current view)

Upvotes: 1

user3297291
user3297291

Reputation: 23397

The way you look up the selected options in your view is not "the knockout way". In these lines:

$('.drpSchedulesAccess option:selected').each(function (i) {
  schedulesSelected.push($(this).val());
});

you're using the DOM to store your ViewModel state, which isn't bad per se, but not how knockout works.

When using knockout, your ViewModel should contain all data and communicate with the DOM through data-binds.

You haven't shown us a snippet of working code, so I'll try to recreate parts of your UI to show how it should work.

var DoorViewModel = function(schedules, door) {
    return Object.assign({
      checked: ko.observable(true),
      selectedSchedule: ko.observable(),
      schedules: schedules
    }, door);
};

var ViewModel = function(doors, schedules) {
   this.doors = ko.observableArray(doors.map(DoorViewModel.bind(null, schedules)));
  
   this.selectedScheduleIds = ko.computed(function() {
       return this.doors()
         .filter(function(door) { return door.checked(); })
         .map(function(door) {
           return door.selectedSchedule() 
             ? door.selectedSchedule().ScheduleId
             : null;
         });
   }, this);
};

var schedules = [{
  'ScheduleId': "Schedule1",
  'ScheduleName': "Always On"
}, {
  'ScheduleId': "Schedule2",
  'ScheduleName': "Never On"
}];

var doors = [{
  'DoorId': "Door1",
  'DoorName': "DoorOne"
  }, {
  'DoorId': "Door2",
  'DoorName': "DoorTwo"
}];

ko.applyBindings(new ViewModel(doors, schedules));
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

<ul data-bind="foreach: doors">
  
  <li>
    <input type="checkbox" data-bind="checked: checked">
    <span data-bind="text: DoorName"></span>
    
    <select data-bind="options: schedules, 
                       value: selectedSchedule,
                       optionsText: 'ScheduleName'"></select>
                       
    
  </li>
</ul>

<pre data-bind="text: JSON.stringify(selectedScheduleIds(), null, 2)"></pre>

Upvotes: 0

Related Questions