How to capture table row on button click to add css class knockout js - css

i have table with data and data populated by knockout js foreach bind.
i would like to know how to access specific table row's data when it gets updated.
if i could access table row then could add css class to that tr. my objective is to do bit color animation for a row which will be updated just clicking on button. when any data will be push to table row clicking on "Update Data" button then i want to add a class to that table row and after few minute remove that class too. hence i am new so no logic is coming to my mind to achieve this....any help would be appreciated. thanks
jsfiddle http://jsfiddle.net/62Ls6x9n/157/
full code
<button data-bind="click: AddNewData">Add New Data</button>
<button data-bind="click: UpdateDataByIds">Update Data</button>
<br><br>
<table class="imagetable">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Price</th>
<th>Status</th>
<th>Edit</th>
<th>Delete</th>
</tr>
</thead>
<tbody data-bind="foreach: Stocks">
<tr>
<td data-bind="text: id"></td>
<td data-bind="text: name"></td>
<td data-bind="text: price"></td>
<td data-bind="text: status"></td>
<td>edit</td>
<td>delete</td>
</tr>
</tbody>
</table>
table.imagetable {
font-family: verdana,arial,sans-serif;
font-size:11px;
color:#333333;
border-width: 1px;
border-color: #999999;
border-collapse: collapse;
}
table.imagetable th {
background:#b5cfd2 url('cell-blue.jpg');
border-width: 1px;
padding: 8px;
border-style: solid;
border-color: #999999;
}
table.imagetable td {
background:#dcddc0 url('cell-grey.jpg');
border-width: 1px;
padding: 8px;
border-style: solid;
border-color: #999999;
}
var StockItem = function(_id, _name, _price, _status){
var self = this;
self.id = ko.observable(_id);
self.name = ko.observable(_name);
self.price = ko.observable(_price);
self.status = ko.observable(_status);
};
var data= [
new StockItem("12345", "Acme Widget 1", "£25.99", "In Stock"),
new StockItem("67890", "Acme Widget 2", "£28.99", "In Stock"), new StockItem("11123","Acme Widget 3","£15.99", "In Stock"),
new StockItem("14156", "Acme Widget 4", "£33.99", "In Stock")
];
var NewData = [new StockItem("99999", "HSL Limited", "£78.99", "In Stock")];
var appViewModel = function()
{
var self = this;
self.Stocks = ko.observableArray(data);
self.AddNewData = function(){
self.Stocks.push.apply(self.Stocks,NewData);
};
self.DeleteItem = function(dataContext){
var itemToDelete = dataContext;
self.Stocks.remove(itemToDelete);
}
self.UpdateDataByIds = function(){
var id1 = '11123';
var id2 = '12345';
self.UpdateById(id1,null,null,"Out of Stock");
self.UpdateById(id2,null,"31.45",null);
};
self.UpdateById = function(_id, _name, _price, _status){
var matchedItem = ko.utils.arrayFirst(self.Stocks(), function(item) {
return item.id() === _id;
});
if (matchedItem != null){
if (_name != null) matchedItem.name(_name);
if (_price != null) matchedItem.price(_price);
if (_status != null) matchedItem.status(_status);
}
};
self.UpdateData = function(dataContext){
var itemToEdit = dataContext;
itemToEdit.status("Out of Stock");
};
};
var vm = new appViewModel();
ko.applyBindings(vm);

You can add a Mutated array to your view-model:
self.Mutated = ko.observableArray();
And upon updating / adding, add the item id to the array:
self.Mutated.push(_id);
Then in your HTML, have a mutated class on each <TR> that is indeed mutated:
<tr data-bind="css: { mutated: $root.Mutated.indexOf(id()) > -1 }">
And the CSS:
table.imagetable tr.mutated td { background-color: red; }
See Fiddle

Related

Table td style for CSS

I would like my TD text to move a bit but so far I am only able to text align left, center, right:
<div class= "col-md-7" id = "recyclable-list">
<table class="table">
<thead>
<tr>
<th style=" padding-left:25px;";>RecyclableID</th>
<th style=" padding-left:100px;">Name</th>
<th style=" text-align: center;">RecyclableType</th>
</tr>
</thead>
<tbody id="recycleTable">
</tbody>
</table>
This is my script call for the database:
var myarray = [];
$.ajax({
url:"https://ecoexchange.dscloud.me:8080/api/get",
method:"GET",
// In this case, we are going to use headers as
headers:{
// The query you're planning to call
// i.e. <query> can be UserGet(0), RecyclableGet(0), etc.
query:"RecyclableGet(0)",
// Gets the apikey from the sessionStorage
apikey:sessionStorage.getItem("apikey")
},
success:function(data,xhr,textStatus) {
myarray = data;
buildTable(myarray);
console.log(myarray);
},
error:function(xhr,textStatus,err) {
console.log(err);
}
});
function buildTable(data) {
var table = document.getElementById("recycleTable")
for (var i = 0; i < data.length; i++) {
var row = `<tr>
<td>${data[i].RecyclableID}</td>
<td>${data[i].Name}</td>
<td>${data[i].RecyclableType}</td>
</tr>`
table.innerHTML += row
}
};
This is how the table looks like currently:
Table image look like
Now, how do I style this to match the header rows?
You have used inline-styles for your table head. Try to repeat the same in JQuery within the template literals where you are creating the table rows on fly to match the thead styling for all the rows.
for (var i = 0; i < data.length; i++) {
var row = `<tr>
<td style="padding-left:25px;">${data[i].RecyclableID}</td>
<td style="padding-left:100px;">${data[i].Name}</td>
<td style="text-align: center;">${data[i].RecyclableType}</td>
</tr>`
table.innerHTML += row
}
This should do it !

Table row is resizing when adding filter script class?

I need to filter table rows by category so class filterTr is added to element <tr> but then element <tr> resizes in width and no longer aligns with element <th> above.
I don't know why this happens. The snippet below is a simplified version but the same thing happens here:
filterSelection("all")
function filterSelection(c) {
var x, i;
x = document.getElementsByClassName("filterTr");
if (c == "all") c = "";
for (i = 0; i < x.length; i++) {
w3RemoveClass(x[i], "show");
if (x[i].className.indexOf(c) > -1) w3AddClass(x[i], "show");
}
}
function w3AddClass(element, name) {
var i, arr1, arr2;
arr1 = element.className.split(" ");
arr2 = name.split(" ");
for (i = 0; i < arr2.length; i++) {
if (arr1.indexOf(arr2[i]) == -1) {element.className += " " + arr2[i];}
}
}
function w3RemoveClass(element, name) {
var i, arr1, arr2;
arr1 = element.className.split(" ");
arr2 = name.split(" ");
for (i = 0; i < arr2.length; i++) {
while (arr1.indexOf(arr2[i]) > -1) {
arr1.splice(arr1.indexOf(arr2[i]), 1);
}
}
element.className = arr1.join(" ");
}
var btnContainer = document.getElementById("sowClndr-filter");
var btns = btnContainer.getElementsByClassName("btn");
for (var i = 0; i < btns.length; i++) {
btns[i].addEventListener("click", function(){
var current = document.getElementsByClassName("active");
current[0].className = current[0].className.replace(" active", "");
this.className += " active";
});
}
/* Table filter */
.filterTr {
display: none;
}
.filterBtn {
margin-top:-10px!important;
background-color:rgba(55,175,75,1.00)!important;
color:rgba(255,255,255,1.00)!important;
border:1px solid rgba(55,175,75,1.00)!important;
text-align:left!important;
font-weight:400!important;
text-overflow:ellipsis!important;
white-space:nowrap!important;
overflow:hidden!important;
}
.filterBtn:hover {
background-color:rgba(255,255,255,0.00)!important;
color:rgba(0,145,255,1.00)!important;
border:1px solid rgba(0,145,255,1.00)!important;
}
.btn.active {
background-color:rgba(255,255,255,0.00)!important;
color:rgba(0,145,255,1.00)!important;
border:1px solid rgba(0,145,255,1.00)!important;
}
.show {
display: block;
}
/* Table styles */
.sowClndr-tr {
background-color:rgba(255,255,255,1.00)!important;
border:0!important;
}
.sowClndr-tr:hover {
background-color:rgba(55,175,75,0.15)!important;
border:0!important;
}
<div id="sowClndr-filter">
<button class="btn btn-primary filterBtn active" onclick="filterSelection('all')"> All selections</button>
<button class="btn btn-primary filterBtn" onclick="filterSelection('A')"> selection A</button>
<button class="btn btn-primary filterBtn" onclick="filterSelection('B')"> selection B</button>
</div>
<table id="myTable">
<tr class="header">
<th style="width:60%;">Name</th>
<th style="width:40%;">Country</th>
</tr>
<tr class="sowClndr-tr filterTr A">
<td>S1 fname lname</td>
<td>lorem ipsum</td>
</tr>
<tr class="sowClndr-tr filterTr B">
<td>lorem ipsum</td>
<td>lorem ipsum</td>
</tr>
</table>
SOLVED
The CSS style display:block; for class .show messes up the table layout because class .show is added to <tr> using JS to make it visible. The solution is to use CSS style display:table-row; instead, now it works. I did not know that this style existed untill now.

Knock out- css binding to highlight areas with no text in them

I'm currently working on making a contacts editor but dont fully understand the knockout conditional css binding. Basically what i would like to have happen is when you click the Add employee button two text boxes are created to add a first and last name. I would like those fields to be highlighted using the knockout conditional css binding . I would like the same thing to happen when clicking the add number option.
here is my code
and a fiddle http://jsfiddle.net/grahamwalsh/c2fmnoub/
html
<div data-bind="if:!loaded()"> Loading...Please Wait</div>
<div class='NbiEmployees'data-bind="if:loaded()">
<h2>NBI Employees</h2>
<h3>NBI has <span data-bind="text: employees().length"></span> Employees</h3>
<div id='employeesList'>
<table class='employeesEditor'>
<tr>
<th>First name</th>
<th>Last name</th>
<th>Phone numbers</th>
</tr>
<tbody data-bind="foreach: employees">
<tr>
<td>
<input data-bind='value: firstName' />
<div><a href='#' data-bind='click: $root.removeEmployee'>Delete</a></div>
</td>
<td><input data-bind='value: lastName' /></td>
<td>
<table>
<tbody data-bind="foreach: phones">
<tr>
<td><input data-bind='value: type' /></td>
<td><input data-bind='value: number' /></td>
<td><a href='#' data-bind='click: $root.removePhone'>Delete</a></td>
</tr>
</tbody>
</table>
<a href='#' data-bind='click: $root.addPhone'>Add number</a>
</td>
</tr>
</tbody>
</table>
</div>
<p>
<button data-bind='click: addEmployee'>Add an Employee</button>
<button data-bind='click: save, enable: employees().length > 0'>Save to JSON</button>
</p>
<textarea data-bind='value: lastSavedJson' rows='5' cols='60' disabled='disabled'> </textarea>
css
body { font-family: arial; font-size: 14px; }
.NbiEmployees { padding: 1em; background-color: #EEEEDD; border: 1px solid #CCC; max-width: 655px; }
.NbiEmployees input { font-family: Arial; }
.NbiEmployees b { font-weight: bold; }
.NbiEmployees p { margin-top: 0.9em; margin-bottom: 0.9em; }
.NbiEmployees select[multiple] { width: 100%; height: 8em; }
.NbiEmployees h2 { margin-top: 0.4em; font-weight: bold; font-size: 1.2em; }
.NbiEmployees TR { vertical-align: top; }
.NbiEmployees TABLE, .NbiEmployees TD, .NbiEmployees TH { padding: 0.2em; border-width: 0; margin: 0; }
.NbiEmployees TD A { font-size: 0.8em; text-decoration: none; }
.NbiEmployees table.contactsEditor > tbody > TR { border-bottom: 1px solid silver; }
.NbiEmployees td input { width: 8em; }
li { list-style-type: disc; margin-left: 20px; }
Knockout
var EmployeesModel = function () {
var self = this;
self.employees = ko.observableArray(
);
self.loaded = ko.observable(false);
self.loadData = function loadData() {
self.loaded(false);
setTimeout(function () {
var data = [
{
firstName: "Graham", lastName: "Walsh", phones: [
{ type: "Office", number: "(555) 121-2121" },
{ type: "Mobile", number: "(555) 123-4567" }]
},
{
firstName: "Kimi", lastName: "Shirasaki", phones: [
{ type: "Office", number: "(555) 444-2222" },
{ type: "Mobile", number: "(555) 999-1212" }]
}
];
self.employees(ko.utils.arrayMap(data, function (employee) {
return {
firstName: employee.firstName,
lastName: employee.lastName,
phones: ko.observableArray(employee.phones)
};
}));
self.loaded(true);
}, 5000);
};
self.addEmployee = function () {
self.employees.push({
firstName: "",
lastName: "",
phones: ko.observableArray()
});
};
self.removeEmployee = function (employee) {
self.employees.remove(employee);
};
self.addPhone = function (employee) {
employee.phones.push({
type: "",
number: ""
});
};
self.removePhone = function (phone) {
$.each(self.employees(), function () { this.phones.remove(phone) })
};
self.save = function () {
self.lastSavedJson(JSON.stringify(ko.toJS(self.employees), null, 2));
};
self.lastSavedJson = ko.observable("")
self.loadData();
};
$(document).ready(function () {
ko.applyBindings(new EmployeesModel());
});
If you add something like this to the 'required' fields:
<input data-bind='value: firstName, css: {warn: !firstName()}' />
and then define your warn class:
.warn {
border-color: red;
}
then the field will be highlighted. However, for this to work, the fields have to be observable:
http://jsfiddle.net/c2fmnoub/14/
here, I've created an Employee() class with observable fields (except for the phone number, which can also be observable if needed), of which a new one needs to be created when calling the addEmployee() function
Edit: the phone number:
http://jsfiddle.net/c2fmnoub/16/
in the same way I defined an Employee object with observable fields, I defined a Phone object with observable fields. This should have been a simple extension for the OP to have done. I really hope I didn't just do your homework for you.

AjaxPro Framework hitting timeout function?

I am trying to develop a chat application.I am using Asp.Net2.0 and vs2005.Iam using AjaxPro Framework for getting asynchronous calls to the server side.
My problem is when i send message im getting timeout error after a few seconds.What could be the problem and how will i resolve it?
My another doubt is that is there some serious problem in using AjaxPro Framework
Heres the code i have used in the client side to send messages
<script language="javascript">
// Send messages
function sendMessage()
{
// input box for entering message
var ta_content = el("txtcontent");
// if the content input is not empty
if (ta_content.value.length > 0)
{
//the message show area
var div_recentMsg = el("recentMsg");
var clientUname=document.getElementById("<%=hFieldClientUserName.ClientID %>").value;
var adminUname=document.getElementById("<%=hFieldAdminUserName.ClientID %>").value;
// send the message
AjaxProChat.SendMessage(clientUname,adminUname,ta_content.value);
// clear the input box
ta_content.value = "";
// roll up the web page with the messages
ta_content.scrollIntoView(false);
getNewMessage();
}
}
//Obtain the new messages
function getNewMessage()
{
// AjaxProChat.timeouPeriod(1800000);
// the user name
var username = document.getElementById("<%=hFieldClientUserName.ClientID %>").value;
// the message show area
var div_recentMsg = el("recentMsg");
// Obtain the DataTable for the newest messages
var dt = AjaxProChat.GetNewMsg(username).value;
for (var i = 0;i < dt.Rows.length;i++)
{
// one message in response to one <span> object
var oneMsg = document.createElement("span");
// the message sender and corresponding sent content
var strLine1 = dt.Rows[i].Sender + " says: (" + dt.Rows[i].SendTime + ")";
strLine1 = DealBrackets(strLine1);
// the content of the message
var strLine2 = dt.Rows[i].Contents;
strLine2 = DealBrackets(strLine2);
// show style
oneMsg.innerHTML = "<pre>" + strLine1 + "<br> " + strLine2 + "</pre>";
oneMsg.style.padding = "2px 2px 2px 2px";
oneMsg.style.color = (dt.Rows[i].Sender == username) ? "blue" : "red";
oneMsg.style.fontFamily = "'Courier New'";
// attached to DOM
div_recentMsg.appendChild(oneMsg);
}
}
</script>
Heres the html code
<div style="text-align: center">
<strong><span style="font-size: 24pt"><span style="color: #333399; background-color: #ffffff">
Chatting Room</span></span></strong>
</div>
<table border="2" style="width: 792px; height: 443px;background-color:#ffffff;">
<tr>
<td colspan="3" style="height: 373px; width: 729px;">
<div id="recentMsg" style="width: 779px; height: 368px; overflow:auto;">
</div>
</td>
</tr>
<tr>
<td colspan="3" style="height: 30px; width: 729px;">
<asp:Label ID="Label1" runat="server" Font-Size="X-Large" ForeColor="Maroon">Input the message and click Send or press ENTER key:</asp:Label>
</td>
</tr>
<tr>
<td colspan="3" style="height: 40px; width: 729px;">
<input id="txtcontent" onkeydown="if (event.keyCode==13) {sendMessage();return false;}"
style="width: 55%; height: 30px" type="text" runat="server" />
<input onclick="javascript:sendMessage();" style="width: 58px; border-top-style: groove;
border-right-style: groove; border-left-style: groove; background-color: #ebf1fa;
border-bottom-style: groove; height: 34px;" type="button" value="Send" id="btnSend" /></td>
</tr>
<tr>
<td colspan="3" style="width: 729px">
</td>
</tr>
</table>
Heres the code for sending and receving messages i have written in server side
[AjaxPro.AjaxMethod]//code for sending messages
public void SendMessage(string Sender,string Receiver,string Content)
{
ChatBAL clsChat = new ChatBAL();
clsChat.SENDER = Sender;
clsChat.RECEIVER = Receiver;
clsChat.CONTENT = Content;
clsChat.SendMessage();
}
[AjaxPro.AjaxMethod]//code for getting latest message and returns datatable
public DataTable GetNewMsg(string UserName)
{
ChatBAL clsChat = new ChatBAL();
DataTable dtNewMsg =new DataTable();
try
{
clsChat.USERNAME = UserName;
dtNewMsg = clsChat.GetNewMessage();
}
catch
{
throw;
}
finally
{
clsChat = null;
}
return dtNewMsg;
}
In your javascript code, you can use this code right before of the ajax call.
AjaxPro.timeoutPeriod = 120 * 1000; //this will add a 2 minutes timeout
AjaxPro.onTimeout = (function (time, obj, something) {
if (time < AjaxPro.timeOutPeriod || obj.method !="SendMessage") return false;
else
{
console.log("Ajaxpro timeout exception after 120 seconds!");
}
});

Table sorter icons in thead

I have some JavaScript that toggles the class of the th element clicked to "ascending" or "descending".
Q: In the css, how can I display a jQuery-UI icon associated with .ascending or .descending?
<table>
<thead>
<tr>
<th class="ascending">Cust</th>
<th>Name</th>
</tr>
</thead>
...
</table>
Here's the code, just in case someone spots an inefficiency:
jQuery(function($) {
$('.thSort th').click(function() {
var $th = $(this);
$th.siblings().removeClass('selected ascending descending');
$th.addClass('selected');
var column = $th.index();
var $table = $th.closest('table');
var rows = $table.find('tbody > tr').get();
if ($th.hasClass('ascending')) {
$th.removeClass('ascending');
$th.addClass('descending');
rows.sort(function(rowA,rowB) {
var keyA = $(rowA).children('td').eq(column).text().toUpperCase();
var keyB = $(rowB).children('td').eq(column).text().toUpperCase();
if (keyA < keyB) return 1;
if (keyA > keyB) return -1;
return 0;
});
} else {
$th.removeClass('descending');
$th.addClass('ascending');
rows.sort(function(rowA,rowB) {
var keyA = $(rowA).children('td').eq(column).text().toUpperCase();
var keyB = $(rowB).children('td').eq(column).text().toUpperCase();
if (keyA < keyB) return -1;
if (keyA > keyB) return 1;
return 0;
});
}
$.each(rows, function(index,row) {
$table.children('tbody').append(row);
});
return false;
});
});
taking this from the jquery Tablesorter plugin
you can write some css like this:
table thead th{
background-repeat: no-repeat;
background-position: center right;
cursor: pointer;
}
.ascending{
background-image: url(asc.gif);
}
.decending{
background-image: url(desc.gif);
}
<th scope="col"><div class="floatleft">Topic</div>
<div class="floatright ui-state-default ui-corner-all">
<span class="ui-icon ui-icon-circle-triangle-n"></span>
</div>
</th>
In JavaScript, toggle between ui-icon-circle-triangle-n and ui-icon-circle-triangle-s.
If the user clicks on a new th, replace all the html inside the previous th with only the text that is in the first div.

Resources