Reputation: 5021
I have an array doorsForSite
where 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 ?
Upvotes: 0
Views: 43
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
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