I have an html table with a checkbox on first column. I would like to highlight the row where checkboxes are checked with knockout.
<table class="defaultGrid">
<thead>
<tr>
<th>Check</th>
<th>ID</th>
<th>Name</th>
</tr>
</thead>
<tbody data-bind="foreach: model.Things">
<tr>
<td><input type="checkbox" data-bind="click: $root.selectThing " /></td>
<td data-bind="text: ID"></td>
<td data-bind="text: Name"></td>
</tr>
</tbody>
</table>
Here is an example on jsFiddle: http://jsfiddle.net/jJ4H6/1/
I don't know how to proceed. I don't want to add an extra property on my model like 'isSelected'.
Any idea?
Thanks.
I would definitely add a knockout observable to your 'Thing' that determines whether or not your tr element has a yellow background or not.
However, if you really don't want to add something like this to your view model, you'll have to add some logic to your selectThing function to handle this for you e.g.
self.selectThing = function(item, event) {
$(event.target).parent().parent().addClass('selected');
};
Check out this Jfiddle http://jsfiddle.net/jJ4H6/27/
$(function() {
Thing = function(id, name, selected) {
var self = this;
self.ID = id,
self.Name = name
self.isChecked = ko.observable(false);
};
function viewModel() {
var self = this;
self.model = {};
self.model.CurrentDisplayThing = ko.observable();
self.model.Things = ko.observableArray(
[
new Thing(1, "Thing 1"),
new Thing(2, "Thing 2"),
new Thing(3, "Thing 3")
]);
self.selectThing = function(item) {
};
}
ko.applyBindings(new viewModel());
});
Related
I need to put each element of an array into the corresponding table column, but currently it just puts the entire array into the first column. I feel like this solution will be a simple nested for loop but I am unsure, would appreciate any help. Thanks!
index.html
<div id="PersonContainer" class="DBcontainer">
<form action='/addPerson' method="GET"></form>
<table class="center" id="personTable">
<caption>People Table</caption>
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Hooks ID</th>
<th>Soft Plastic ID</th>
<th>Rods ID</th>
<th>Number of Hooks</th>
<th>Number of Soft Plastics</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<button type="button" onclick="displayPerson()">Click Me</button>
</form>
</div>
index.html script
<script>
function displayPerson() {
// console.log('test');
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function () {
if (this.readyState == 4 && this.status == 200) {
var person = xhttp.responseText;
var element = document.getElementById("personTable");
var result = JSON.parse(person).map((item) => Object.values(item));
for(i = 0; i < result.length; i++){
element.innerHTML += '<td>' + result[i] + '</td>';
}
}
};
xhttp.open("GET", "/AddPerson", true);
xhttp.send();
}
</script>
the xhttp.responseText
[{"id":1,"first_name":"Tyler","last_name":"Marlow","hooks_id":1,"sp_id":1,"rods_id":1,"num_hooks":10,"num_sp":30},{"id":2,"first_name":"Jon","last_name":"Marlow","hooks_id":2,"sp_id":1,"rods_id":1,"num_hooks":50,"num_sp":200}]
Also note that when another person is added I would like another row to be added to the table with the values in proper columns
Putting a new row onto a table in JavaScript can be done with the insertRow function and adding a cell to a row can be done with the insertCell function.
So in your code (depending on exactly what your parsed JSON looks like) in your for loop you are going to do something like:
row = element.insertRow(i); // add a new row to your table
row.insertCell(0).innerHTML =
row.insertCell(1).innerHTML =
and so on
....
But of course you'd put the insertCell line into a for loop as well.
function displayPerson() {
// console.log('test');
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var person = xhttp.responseText;
var element = document.getElementById("personTable");
var rows = ``;
JSON.parse(person).forEach(item => {
var row = `<tr>`;
row += `<td>${item.first_name}</td>`;
row += `<td>${item.last_name}</td>`;
row += `<td>${item.hooks_id}</td>`;
row += `<td>${item.sp_id}</td>`;
row += `<td>${item.rods_id}</td>`;
row += `<td>${item.num_hooks}</td>`;
row += `<td>${item.num_sp}</td>`;
row += `</tr>`;
rows += row;
});
element.innerHTML = rows;
}
};
xhttp.open("GET", "/AddPerson", true);
xhttp.send();
}
<div id="PersonContainer" class="DBcontainer">
<form action='/addPerson' method="GET">
<table class="center">
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Hooks ID</th>
<th>Soft Plastic ID</th>
<th>Rods ID</th>
<th>Number of Hooks</th>
<th>Number of Soft Plastics</th>
</tr>
<thead>
<tbody id="personTable">
</tbody>
</table>
<button type="button" onclick="displayPerson()">Click Me</button>
</form>
</div>
I have the following table where I'm attempting to loop through coverage lines. I would like 2 columns with a different line in each, however my code duplicates the same coverage in each column. Any suggesions on how to get a 2 column layout without the repetition? Which element should my foreach binding go on? Thanks.
<table class="coverage-table" data-bind="foreach: $root.clientVM.CustomCoverageLines">
<tr>
<td>
<input type="checkbox" data-bind="checked: Checked" />
<label>
<span data-bind="text: $data.Description"></span>
</label>
</td>
<td>
<input type="checkbox" data-bind="checked: Checked" />
<label>
<span data-bind="text: $data.Description"></span>
</label>
</td>
</tr>
</table>
You could add a computed property to your model that structures the data in the way that you want. See this JSFiddle for an example: http://jsfiddle.net/6gvtz51g/. An advantage to this approach is that you can specify a different row size if you would like.
HTML
<table data-bind="foreach: coverageLineRows">
<tr data-bind="foreach: $data">
<td>
<span data-bind="text: $data"></span>
</td>
</tr>
</table>
JavaScript
function ViewModel () {
var self = this;
self.coverageLines = ko.observableArray([
'Medical',
'Dental',
'Vision',
'Life'
]);
self.coverageLineRowSize = ko.observable(2);
self.coverageLineRows = ko.computed(function () {
var rows = [];
var i = 0;
var lines = self.coverageLines();
var size = self.coverageLineRowSize();
while (i < lines.length) {
rows.push(lines.slice(i, i += size));
}
return rows;
});
}
ko.applyBindings(new ViewModel());
How do you feel about this as a solution? Its not as flexible as the solution given by #JackieChiles in that it would need some tweaking to work with different amounts of rows. But the code I've provided does provide for a prettier look for two columns and it also has the ability to keep track of the check boxes next to each of your items. I suspect a combination of both our solutions will be in your end product :)
var vm = function () {
var self = this;
this.array = ko.observableArray([{
name: ko.observable('Medical'),
checked: ko.observable()
}, {
name: ko.observable('Dental'),
checked: ko.observable()
}, {
name: ko.observable('Vision'),
checked: ko.observable()
}, {
name: ko.observable('Life'),
checked: ko.observable()
}, {
name: ko.observable('Other'),
checked: ko.observable()
}]);
this.coverageSplit = ko.computed(function () {
var retArray = [];
var i = 0;
var arrayUnWrapped = this.array();
while (i < arrayUnWrapped.length) {
if (i >= arrayUnWrapped.length - 1) {
retArray.push({
col1: arrayUnWrapped[i],
col2: {
name: '',
checked: false,
hideThisCheck: true
}
})
console.log(retArray[retArray.length - 1]);
break;
}
retArray.push({
col1: arrayUnWrapped[i],
col2: arrayUnWrapped[i + 1]
});
i += 2;
}
return retArray;
});
this.check_click = ko.observable('None');
this.setLastClicked = function (name) {
if (name.length > 0) self.check_click(name);
};
};
ko.applyBindings(vm);
Here is a fiddle of it in action http://jsfiddle.net/ozrevulsion/sva9tnje/
All i want is to delete a row of a table by clicking a button. I am diong something like this
.controller('removeInput' , function($scope, $http) {
$scope.remove = function(index){
var inputId = {'inputId': $scope.inputId};
$http.delete(baseUrl + '/input/' ,inputId, _auth)
.success(function (){
console.log('deleted');
}).error(function(err){
console.log(err);
});
};
});
and in html its something like this
<tbody ng-controller = "input">
<tr ng-repeat = "inputs in inputData">
<td ng-model = "inputId">{{inputs.inputId}}</td>
<td><img ng-src = "{{inputs.thumbnailUrl}}"/></td>
<td>{{inputs.filename}}</td>
<td></td>
<td>{{inputs.updatedAt.date}}</td>
<td ng-controller = "removeInput">
<a class = "btn btn-option" ng-click = "remove(index)">
<span class = "glyphicon glyphicon-remove"></span>
</a>
</td>
</tr>
</tbody>
and its not working. Please suggest where I am wrong?
You aren't really passing the correct value here. It's not clear what $scope.inputId is, but it isn't the value of the item you are trying to remove. Try this instead:
<a class = "btn btn-option" ng-click = "remove(inputs.inputId)">
and in the JavaScript:
$scope.remove = function(index){
$http.delete(baseUrl + '/input/' + index, _auth)
....
I have a HTML table which has a column for checked rows(which has a check box in the cell).
I am using knockout to bind the selected check boxes to an observable array with an attribute ID as shown below.(this works fine without "checked")
The NListTable is an observable array from getJson (which populate the table on return).I want to be able to post the selected IDs after the table is populated.
<thead>
<tr>
<th style=" text-align:center"><b>Generate Notice</b><input type="checkbox" data-bind="checked: SelectAll" /></th>
<th style=" text-align:center"><b>Name</b></th>
<th style=" text-align:center"><b>Application Number</b></th>
<th style=" text-align:center"><b>Right ID</b></th>
<th style=" text-align:center"><b> Division</b></th>
<th style=" text-align:center"><b>Use ID</b></th>
</tr>
</thead>
<tbody data-bind="foreach:NListTable">
<tr>
<td style=" text-align:center">
<input type="checkbox" data-bind="checked: Selected">
</td>
<td style=" text-align:center">
<p data-bind="text:Name"></p>
</td>
<td style=" text-align:center">
<p data-bind="text:AppNum"></p>
</td>
<td style=" text-align:center">
<p data-bind="text:ID"></p>
</td>
<td style=" text-align:center">
<p data-bind="text:DivName"></p>
</td>
<td style=" text-align:center">
<p data-bind="text:useID"></p>
</td>
</tr>
</tbody>
JS
function RowData(Name, AppNum, ID, DivName, useID) {
var self = this;
self.Selected = ko.observable(true);
self.Name = ko.observable(Name);
self.AppNum = ko.observable(AppNum);
self.ID = ko.observable(ID);
self.DivName = ko.observable(DivName);
self.useID = ko.observable(useID);
}
self.NListTable = ko.observableArray([new RowData()]);
//self.selectedThings = ko.observableArray([]);
self.SelectAll = ko.computed({
read: function () {
var item = ko.utils.arrayFirst(self.NListTable(), function (item) {
return !item.Selected();
});
return item == null;
},
write: function (value) {
ko.utils.arrayForEach(self.NListTable(), function (rowData) {
rowData.Selected(value);
});
}
});
getJSON
function (data) {
$("#nListTable").show();
for (var i = 0; i < data.length; i++) {
if (data[i] != null) {
self.NListTable.push(RowData(data[i].FirstName + ' ' + data[i].LastName, data[i].AppPre + '-' + data[i].AppNum, data[i].ID, data[i].DivName, data[i].useID));
}
}
});
I am trying to select all check boxes when the page loads by using the HTML attribute "checked" but this does not work all my check boxes are unchecked even when I use this.
How do I pre select all check boxes
Well you should be doing something like this
View Model:
self.SelectAll = ko.computed({
read: function () {
var item = ko.utils.arrayFirst(self.NListTable(), function (item) {
return !item.Selected();
});
return item == null;
},
write: function (value) {
ko.utils.arrayForEach(self.NListTable(), function (rowData) {
rowData.Selected(value);
});
}
});
Working fiddle here
I have a html table stucture. I need to get the value of the value of the first <td> in the final <tr> tag. Here is my table structure. The value I require from the below function getFinalNodeValue is "3".
<table id="test">
<tr>
<td>ID</td>
<td>Name</td>
<td>Age</td>
</tr>
<tr>
<td>1</td>
<td>Yasoda</td>
<td>21</td>
</tr>
<tr>
<td>2</td>
<td>Samantha</td>
<td>25</td>
</tr>
<tr>
<td>3</td>
<td>Sajee</td>
<td>26</td>
</tr>
</table>
Here is the code I wrote using HtmlAgilityPack.
public String getFinalNodeValue(String URL)
{
var webGet = new HtmlWeb();
var pageSource = webGet.Load(URL);
var table = pageSource.DocumentNode.SelectSingleNode("//table[#id='test']//tr[1]");
string id = null;
IEnumerable<HtmlNode> trNodes = table.DescendantsAndSelf();
foreach (var currentItem in trNodes)
{
if (currentItem == trNodes.Last())
{
IEnumerable<HtmlNode> tdNodes = currentItem.Descendants();
foreach (var x in tdNodes)
{
if(x == tdNodes.First())
{
id = x.InnerText;
}
else
{
break;
}
}
}
else
{
continue;
}
}
return id;
}
The method doesn't return a value. Any help is highly appreciated.
This should do it:
HtmlDocument doc = new HtmlDocument();
doc.Load(MyHtmlFile);
HtmlNode node = doc.DocumentNode.SelectSingleNode("//table[#id='test']/tr[last()]/td");
Console.WriteLine(node.InnerText);
Note the usage of the XPATH last() function
The XPath you use to populate the table variable - "//table[#id='test']//tr[1]", selects the second TR element, no the table.
This most likely should just be "//table[#id='test']".
At this point, to fetch the descendant TR nodes into the trNodes variable, you should use:
IEnumerable<HtmlNode> trNodes = table.SelectNodes("tr");
if you change your table like this:
<table id="test" runat="server">
You can iterate over it in the codebehind, like this:
HtmlTable myTable = this.test;
int rowCount = myTable.Rows.Count;
HtmlTableCell td = myTable.Rows(rowCount - 1).Cells(0);
string val = td.InnerText;