Collapsible data row with dynamic values - javascript

Context: There are a set of months in a table (e.g. May, Jun, July) and under those months will be all of the readings for the given month.
The code:
<tbody data-bind="visible: !MeterReadingHistory_IsBusy(), foreach: HeaderLines()" style="display: none">
<tr data-toggle="collapse" data-target=".order1">
<td>
<!-- ko if: meterReadings.length > 0-->
<span class="glyphicon glyphicon-chevron-down"></span>
<span class="reading-history-data" data-bind="html: monthName"></span>
<!-- /ko -->
<!-- ko if: meterReadings.length == 0-->
<span class="reading-history-data" data-bind="html: monthName"></span>
<!-- /ko -->
</td>
<td>
<span class="reading-history-data" data-bind="html: latestReadingDate"></span>
</td>
<td>
<span class="reading-history-data" data-bind="html: latestReadingType"></span>
</td>
<td>
<span class="reading-history-data" data-bind="html: latestReadingElectric"></span>
</td>
<td>
<span class="reading-history-data" data-bind="html: latestReadingGas"></span>
</td>
</tr>
<!-- ko if: meterReadings.length > 0 -->
<tr class="collapse order1" >
<td colspan="5">
<table class="table mb-none desktop-only">
<thead>
<tr>
<th>Day</th>
<th>Reading Source</th>
<th>Electricity</th>
<th>Gas</th>
</tr>
</thead>
<tbody>
<!-- ko foreach: meterReadings -->
<tr>
<td data-bind="text: readingDateParsed"></td>
<td data-bind="html: readingType"></td>
<!-- ko foreach: readings -->
<td data-bind="html: reading"></td>
<!-- /ko -->
<!-- ko if: readings.length == 0 -->
<td></td>
<td></td>
<!-- /ko -->
<!-- ko if: readings.length == 1 -->
<td></td>
<!-- /ko -->
</tr>
<!-- /ko -->
</tbody>
</table>
</td>
</tr>
<!-- /ko -->
</tbody>
The problem: When i click on any of the rows, it expands every month row exposing all of the data when in fact i only want to display the sub-rows for the actual month that has been clicked.
The main problem is that this table is dynamic, and we wont know how many header rows will be produced, therefore it will be difficult to assign each row to a specific data source via the data-bind attribute.
So......how can I get this code to display only the row of data that I have clicked on, e.g. May, and display all the readings for this given month while all of the other header rows remain closed?
Thanks!

$([data-toggle="collapse"]).on('click',function(){
var thisCollapse = $(this).attr('data-target');
$(thisCollapse).slideToggle('slow');
})

Related

Knockout Js - Using with inside if condition

The isAdmin property inside foreach is related in authorization class.
I am getting an error saying isAdmin is not defined. Is it because I am using isAdmin in foreach? How can I use a use property in with in foreach.
<div data-bind="with: authorization">
<table>
<tbody data-bind="foreach: users">
<tr>
<td data-bind="text: id"></td>
<td data-bind="text: name"></td>
<!-- ko if: isAdmin -->
<td><a href="#" class="icon-trash" rel="tooltip" title="Delete" ></a></td>
<!-- /ko -->
</tr>
</tbody>
</table>
You are correct, it is not working because the foreach binding gets its own context. Use $parent to access the parent authorization context.
<!-- ko if: $parent.isAdmin -->
<td><a href="#" class="icon-trash" rel="tooltip" title="Delete" ></a></td>
<!-- /ko -->

Using knockout if binding inside a table

I was trying to use the if binding inside a table and the 3rd column is not at all displaying the text where as the entries in the 1st column are getting displayed.
<table id="searchPanelForm" cellspacing="0" cellpadding="0" align="center" class="conttable" width="100%" border="0" data-bind="">
<tbody>
<!-- ko foreach: searchPanelArray -->
<!-- ko if: $parent.isSearchEven($data.id) -->
<tr>
<td class="col2" data-bind="text: $data.label"></td>
<td class="col3"><input type="text"></td>
<!-- /ko -->
<!-- ko if: !$parent.isSearchEven($data.id) -->
<td class="col2" data-bind="text: $data.label"></td>
<td class="col3"><input type="text"></td>
</tr>
<!-- /ko -->
<!-- /ko -->
</tbody>
</table>
searchPanelArray is populated through an ajax call and isSearchEven returns true or false when the index is even or odd respectively.
Knockout expects "containerless control flow syntax" to act like elements. They cannot start on the outside of an element and end inside the element. So from Knockout's point of view, the comments internal to <tr> are simply malformed and ignored. So this is what it looks like for Knockout:
<!-- ko foreach: searchPanelArray -->
<!-- ko if: $parent.isSearchEven($data.id) -->
<tr>
<td class="col2" data-bind="text: $data.label"></td>
<td class="col3"><input type="text"></td>
<td class="col2" data-bind="text: $data.label"></td>
<td class="col3"><input type="text"></td>
</tr>
<!-- /ko -->
<!-- /ko -->
Logically, you want to group every two items in your array. You should create a computed observable the returns a new array with the two items grouped together.
this.searchPanelArrayGrouped = ko.pureComputed(function() {
var result = [], source = this.searchPanelArray();
for (var i = 0; i < source.length; i += 2) {
if (i + 1 >= source.length) {
result.push({left: source[i], right: {}});
} else {
result.push({left: source[i], right: source[i+1]});
}
}
return result;
}, this);
Html:
<!-- ko foreach: searchPanelArrayGrouped -->
<tr>
<td class="col2" data-bind="text: $data.left.label"></td>
<td class="col3"><input type="text"></td>
<td class="col2" data-bind="text: $data.right.label"></td>
<td class="col3"><input type="text"></td>
</tr>
<!-- /ko -->
https://jsfiddle.net/bg75xvxc/
Here is a related answer: https://stackoverflow.com/a/10577599/1287183

How to hide the rows in Table when the value is empty?

We need to hide the row when the value is empty . but cant able to get the value of the empty column value and check it . Code used so far is
(function($) {
$('#event tr').each(function() {
if ($(this).find('.event:empty').length) $(this).remove();
});
})(jQuery);
Please see the below screenshot and marked cell is empty we need to hide the entire row
HTML Structure
<table class="tribe-events-calendar" id="event">
<thead>
<tr>
<th id="tribe-events-date" class="width-print" title="date" style="width:10%">date</th>
<th id="tribe-events-date" class="width-print" title="Weekday" style="width:10%">Weekday</th>
<th id="tribe-events-date" title="holiday name" style="width:20%">holiday name</th>
<th id="tribe-events-date" title="holiday type" style="width:60%">holiday type</th>
</tr>
</thead>
<tbody>
<tr>
<td style="width:15%">
<div id="tribe-events-daynum-2-0">
2 </div>
</td>
<!-- day -->
<td style="width:15%">
Mon</td>
<!-- HOLIDAY NAME -->
<td style="width:85%" class="event">
some value
</td>
<!-- HOLIDAY Type-->
<td>
<p>National Holiday </p>
</td>
<!-- View More -->
</tr>
<tr>
<!-- Day Header -->
<td style="width:15%">
<div id="tribe-events-daynum-2-0">
2 </div>
</td>
<!-- day -->
<td style="width:15%">
Mon</td>
<!-- HOLIDAY NAME -->
<td style="width:85%" class="event">
</td>
<!-- HOLIDAY Type-->
<td>
<p>National Holiday </p>
</td>
<!-- View More -->
</tr>
</tbody>
</table>
The td contains whitespace and it acts as textNode so :empty selector don't work here since which only select element which doesn't have any child nodes.
So check the text content and filter out td with whitespace or empty using filter() method.
// get all `tr` within the table except the header
// to avoid header tr use tbody in selector
$('#event tbody tr').filter(function() {
// get the event column, get text content,
// trim out text and check string is empty
// 0(length) is falsy value so use `!`
return !$('.event', this).text().trim().length;
// hide the filtered element
// if you would like to remove then use remove() method
}).hide();
$('#event tbody tr').filter(function() {
return !$('.event', this).text().trim();
}).hide();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table class="tribe-events-calendar" id="event">
<thead>
<tr>
<th id="tribe-events-date" class="width-print" title="date" style="width:10%">date</th>
<th id="tribe-events-date" class="width-print" title="Weekday" style="width:10%">Weekday</th>
<th id="tribe-events-date" title="holiday name" style="width:20%">holiday name</th>
<th id="tribe-events-date" title="holiday type" style="width:60%">holiday type</th>
</tr>
</thead>
<tbody>
<tr>
<td style="width:15%">
<div id="tribe-events-daynum-2-0">
2</div>
</td>
<!-- day -->
<td style="width:15%">
Mon</td>
<!-- HOLIDAY NAME -->
<td style="width:85%" class="event">
some value
</td>
<!-- HOLIDAY Type-->
<td>
<p>National Holiday</p>
</td>
<!-- View More -->
</tr>
<tr>
<!-- Day Header -->
<td style="width:15%">
<div id="tribe-events-daynum-2-0">
2</div>
</td>
<!-- day -->
<td style="width:15%">
Mon</td>
<!-- HOLIDAY NAME -->
<td style="width:85%" class="event">
</td>
<!-- HOLIDAY Type-->
<td>
<p>National Holiday</p>
</td>
<!-- View More -->
</tr>
</tbody>
</table>
If your element have white spaces or new line then :empty will not be very effective. You can check for the length of the html after trimming the spaces for the same logic.
(function($) {
$('#event tbody tr').each(function() {
if ($.trim($(this).find("td.event").html()) == "")
$(this).remove();
});
})(jQuery);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table class="tribe-events-calendar" id="event">
<thead>
<tr>
<th id "tribe-events-date" class="width-print" title="date" style="width:10%">date</th>
<th id="tribe-events-date" class="width-print" title="Weekday" style="width:10%">Weekday</th>
<th id="tribe-events-date" title="holiday name" style="width:20%">holiday name</th>
<th id="tribe-events-date" title="holiday type" style="width:60%">holiday type</th>
</tr>
</thead>
<tbody>
<tr>
<td style="width:15%">
<div id="tribe-events-daynum-2-0">
2</div>
</td>
<!-- day -->
<td style="width:15%">
Mon</td>
<!-- HOLIDAY NAME -->
<td style="width:85%" class="event">
some value
</td>
<!-- HOLIDAY Type-->
<td>
<p>National Holiday</p>
</td>
<!-- View More -->
</tr>
<tr>
<!-- Day Header -->
<td style="width:15%">
<div id="tribe-events-daynum-2-0">
2</div>
</td>
<!-- day -->
<td style="width:15%">
Mon</td>
<!-- HOLIDAY NAME -->
<td style="width:85%" class="event">
</td>
<!-- HOLIDAY Type-->
<td>
<p>National Holiday</p>
</td>
<!-- View More -->
</tr>
</tbody>
</table>
Most likely empty isnt working because you have whitespace inside the td. Try
<!-- HOLIDAY NAME -->
<td style="width:85%" class="event"></td>
instead of
<!-- HOLIDAY NAME -->
<td style="width:85%" class="event">
</td>
You can do this
$('#event tr').each(function() {
var td= $(this).find("td");
var _this=this;
$(td).each(function() {
var text = $(this).text();
if(text=='' || text==null|| typeof text=='undefined'){
$(_this).hide();
}
});
});

If statement in knockout.js not working as expected

I'm trying to display the string "No data was found." inside a table row whenever the data array is empty, but it seems the message get always printed no matter what.
Reproduction online (ignoring the condition orders.length ==0)
What am I doing wrong?
<table>
<thead>
<tr>
<th>Truck</th>
<th>Pickup</th>
</tr>
</thead>
<!-- ko if: orders.length==2 -->
<tbody>
<tr colspan="2">No data was found.</tr>
</tbody>
<!-- /ko -->
<tbody data-bind="foreach: orders">
<tr>
<td data-bind="text: truck"></td>
<td></td>
</tr>
</tbody>
</table>
If your orders is an ko.observableArray you need to write orders() to get the underlying array and get the length from there:
<!-- ko if: orders().length== 0 -->
Your HTML also invalid, the td elements are missing from:
<!-- ko if: orders().length==0 -->
<tbody data-bind="if: orders().length==0">
<tr colspan="2"><td>No data was found.</td></tr>
</tbody>
<!-- /ko -->
Demo JSFiddle.

Nested containerless foreach in tbody failing for IE

I'm having a bit of trouble getting some nested, containerless foreach bindings to work. It works in grownup browsers, but not IE (8 OR 9).
The closest I could find was this question, but the root of that problem seems to be a lack of a tbody tag, which I have. The error IE is giving is
Cannot find closing comment tag to match: ko foreach: seniors
Sorry for the wall of text, but below is my markup.
<tbody data-bind="foreach: superGroups">
<tr>
<td style="font-weight: bold;" data-bind="text: superName() || 'No Super Set'" colspan="8">
</tr>
<!-- ko foreach: seniors -->
<tr>
<td></td>
<td style="font-weight: bold;" data-bind="text: seniorName() || 'No Senior Set'" colspan="7"></td>
</tr>
<!-- ko foreach: items -->
<tr>
<td>
<span data-bindX="text:superName"></span>
</td>
<td>
<span data-bindX="text:seniorName"></span>
</td>
<td>
<span data-bind="text:clientName"></span>
<i class="icon-tags" data-bind="attr:{title: labels}, visible: labels"></i>
</td>
<td>
<span data-bind="text:description"></span>
</td>
<td>
<span data-bind="visible:superPayAmount">$<span data-bind="text:superPayAmount"></span></span>
<span data-bind="visible:superPayAmount.length == 0">-</span>
</td>
<td>
<span data-bind="shortDate: superStartDate"></span> - <span data-bind="shortDate: superEndDate"></span>
</td>
<td>
<span data-bind="visible:seniorPayAmount">$<span data-bind="text:seniorPayAmount"></span></span>
<span data-bind="visible:!seniorPayAmount.length == 0">-</span>
</td>
<td>
<span data-bind="shortDate: seniorStartDate"></span> - <span data-bind="shortDate: seniorEndDate"></span>
</td>
</tr>
<!-- /ko -->
<!-- /ko -->
</tbody>
You missed closing td tag in the first tr:
<tr>
<td style="font-weight: bold;" data-bind="text: superName() || 'No Super Set'" colspan="8"></td>
</tr>

Categories

Resources