Reputation: 10460
I'm experimenting with Knockout.js, and can't make the visible
binding to work in the following code when returning an empty array (here's its fiddle):
$(document).ready()
{
BuildFactoryGrid();
}
function BuildFactoryGrid ()
{
var factoryViewModel = new FactoryViewModel();
ko.applyBindings(factoryViewModel);
factoryViewModel.init();
}
function FactoryViewModel ()
{
var self = this;
self.FactoryRecords = ko.observableArray([]);
self.FactoryRecordsLength = ko.computed(function ()
{
return self.FactoryRecords().length;
});
self.init = function ()
{
self.FactoryRecords(GetFactoryData());
};
}
function GetFactoryData ()
{
var objArr =
[
{
District: 1,
Department: 22,
Team: 33
},
{
District: 1,
Department: 24,
Team: 35
},
{
District: 2,
Department: 54,
Team: 9
},
];
return objArr;
// return []; // remove comment to return an empty array
}
tr>th, td {
text-align: center;
vertical-align: middle;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<table class="table table-bordered table-condensed hover">
<thead>
<tr class="active">
<th></th>
<th>District</th>
<th>Department</th>
<th>Team</th>
</tr>
</thead>
<tbody data-bind="foreach: FactoryRecords">
<tr>
<td>
<input type="checkbox" />
</td>
<td data-bind="text: District"></td>
<td data-bind="text: Department"></td>
<td data-bind="text: Team"></td>
</tr>
<tr data-bind="visible: $parent.FactoryRecordsLength() == 0 ">
<td colspan="4">No Records</td>
</tr>
</tbody>
</table>
When returning an empty array, the "No Records" span
should appear, but it doesn't. Be glad to understand why.
Upvotes: 1
Views: 61
Reputation: 1088
Your visible binding "doesn't work", because you using it inside foreach. And since your FactoryRecords that binded to foreach have no element - no elements won't be generated and your visible binding won't be ever called.
Just fix you markup and separate foreach and default row:
<table class="table table-bordered table-condensed hover">
<thead>
<tr class="active">
<th></th>
<th>District</th>
<th>Department</th>
<th>Team</th>
</tr>
</thead>
<tbody>
<!-- Foreach generate elements if they are exists -->
<!-- ko foreach: FactoryRecords -->
<tr>
<td>
<input type="checkbox" />
</td>
<td data-bind="text: District"></td>
<td data-bind="text: Department"></td>
<td data-bind="text: Team"></td>
</tr>
<!-- /ko -->
<!-- If no elements present - create our row with message -->
<tr data-bind="visible: FactoryRecordsLength() === 0 ">
<td colspan="4">No Records</td>
</tr>
</tbody>
</table>
Upvotes: 1
Reputation: 4304
Your "No Records" block is nested within a foreach
binding, which will not be drawn if there are no records to loop over. You'll have to move the "No Records" out of the foreach binding context, and to do that you'll want to move your foreach
to a virtual element instead of the <tbody>
element.
<tbody>
<tr data-bind="visible: FactoryRecordsLength() == 0 ">
<td colspan="4">No Records</td>
</tr>
<!--ko foreach: FactoryRecords-->
<tr>
<td>
<input type="checkbox" />
</td>
<td data-bind="text: District"></td>
<td data-bind="text: Department"></td>
<td data-bind="text: Team"></td>
</tr>
<!--/ko-->
</tbody>
Upvotes: 1
Reputation: 2665
If you do
return objArr;
// return []; // remove comment to return an empty array
The array will be populated and FactoryRecordsLength().length
will be 3
If you do
//return objArr;
return []; // remove comment to return an empty array
The foreach binding will have nothing to display and you will not see anything in your table at all.
Ideally you should add another record to your object to determine if there are records, for example:
var objArr =
[
{
District: 1,
Department: 22,
Team: 33,
Records: 0
},
{
District: 1,
Department: 24,
Team: 35,
Records: 1
},
{
District: 2,
Department: 54,
Team: 9,
Records: 0
},
];
Upvotes: 0