I have change color of my cell when I click in my button but when I click second time my color cell is not keep.
I wish that when I click a second time on another button my first cell keeps color
First click:
Second click:
HTML:
<table class="table table-striped table-bordered" cellspacing="0" width="100%">
<thead>
<tr class="warning">
<th>Key</th>
<th>Valeur version {{application.version}}</th>
<th></th>
<th>Valeur version {{applicationcible.version}}</th>
</tr>
</thead>
<tbody ng-repeat="group in groups">
<tr>
<td class="danger" colspan="4" ng-click="hideGroup = !hideGroup">
<a href="" ng-click="group.$hideRows = !group.$hideRows">
<span class="glyphicon" ng-class="{ 'glyphicon-chevron-right': group.$hideRows, 'glyphicon-chevron-down': !group.$hideRows }"></span>
<strong>{{group.name}}</strong>
</a>
</td>
</tr>
<tr ng-repeat-start="member in group.members" ng-hide="hideGroup">
<td rowspan="2">
{{ member.name }}
</td>
<td rowspan="2" ng-class="{selected: $index==selectedRowLeft}">{{ member.valueRef }}</td>
<td class="cube" >
<div ng-if="group.id != 1">
<button type="button" ng-click="moveLeft($index, group)" ><span class="glyphicon glyphicon-chevron-left"></span></button>
</div>
</td>
<td rowspan="2" ng-class="{selected: $index==selectedRowRight}">{{ member.valueCible }}</td>
</tr>
<tr ng-repeat-end ng-hide="hideGroup" >
<td class="cube" >
<div ng-if="group.id != 2">
<button type="button" ng-click="moveRight($index, group)"><span class="glyphicon glyphicon-chevron-right"></span></button>
</div>
</td>
</tr>
</tbody>
</table>
CSS:
.selected { background-color: #ffff05; }
JS:
scope.moveLeft = function (index, group) {
move(scope.properties, group.id, index, 'left');
};
scope.moveRight = function (index, group) {
move(scope.propertiescible, group.id, index, 'right');
};
var move = function (properties, groupId, origin, destination) {
unregister();
var value;
if (destination === 'right') {
scope.selectedRowRight = origin;
} else {
scope.selectedRowLeft = origin;
}
...
You might need to create an array to keep the cells that are selected thus background color is changed.
Also you will need to change the ng-click function to check the array, and implement the following logic "if there is a record for the clicked row as selected change it's bg-color to yellow"
You will need to do something like this
<td ng-repeat="group in groups" ng-class="{'selected': check == group.title}" ng-click="select(group)">{{group.title}}</li>
in css make sure you have this selected class defined
.selected {
background: 'red';
}
in controller
$scope.check = '';
$scope.select = function (group) {
$scope.check = group.title
};
See this plunker http://plnkr.co/edit/pLbLMWsJ7A6Zr1Z9uAmz?p=preview
Related
I have the following html table:
<table border="1" cellpadding="5" class="test">
<tr>
<td class="talent-cell"><div class="btn7" data-value="0">aaa</div></td>
<td class="talent-cell"><div class="btn8" data-value="1">bbb</div></td>
<td class="talent-cell"><div class="btn9" data-value="2">ccc</div></td>
</tr>
<tr>
<td class="talent-cell"><div class="btn7" data-value="0">ddd</div></td>
<td class="talent-cell"><div class="btn8" data-value="1">eee</div></td>
<td class="talent-cell"><div class="btn9" data-value="2">fff</div></td>
</tr>
<tr>
<td class="talent-cell"><div class="btn7" data-value="0">ggg</div></td>
<td class="talent-cell"><div class="btn8" data-value="1">hhh</div></td>
<td class="talent-cell"><div class="btn9" data-value="2">iii</div></td>
</tr>
</table>
If you click on a "div attribute" inside a table cell I need to get the "data-value" of the clicked div attribute. After that I build a query string to use it with "URLSearchParams". This works so far.
Now I need a certain condition. It should be only allowed to select one div-attribute per table row and column. But I don't know how to implement this condition in my code.
This is the Fiddle and the code:
var btn7;
var btn8;
var btn9;
$('.btn7').click(function () {
if ($(this).attr('data-selected') === 'true') {
$(this).attr('data-selected', 'false');
$(this).removeClass('selected');
} else {
$(this).closest('tr').find('.btn7').not(this)
.removeClass('selected').attr('data-selected', 'false');
$(this).attr('data-selected', 'true');
$(this).addClass('selected');
params.set('var7', $(this).data("value"));
window.history.replaceState({}, '', `?${params}`);
}
});
$('.btn8').click(function () {
if ($(this).attr('data-selected') === 'true') {
$(this).attr('data-selected', 'false');
$(this).removeClass('selected');
} else {
$(this).closest('tr').find('.btn8').not(this)
.removeClass('selected').attr('data-selected', 'false');
$(this).attr('data-selected', 'true');
$(this).addClass('selected');
params.set('var8', $(this).data("value"));
window.history.replaceState({}, '', `?${params}`);
}
});
$('.btn9').click(function () {
if ($(this).attr('data-selected') === 'true') {
$(this).attr('data-selected', 'false');
$(this).removeClass('selected');
} else {
$(this).closest('tr').find('.btn9').not(this)
.removeClass('selected').attr('data-selected', 'false');
$(this).attr('data-selected', 'true');
$(this).addClass('selected');
params.set('var9', $(this).data("value"));
window.history.replaceState({}, '', `?${params}`);
}
});
const params = new URLSearchParams({
var7: btn7,
var8: btn8,
var9: btn9,
});
Idea
Mark each table cell with a data- attribute indicating its respective row and column, and maintain 2 arrays that hold the currently selected element (if any) for each of the columns and row.
Implementation
The following code implements the selection logic. Based on the arrays holding the currently active selections you can visit all relevant elements and assemble the parameters when you send a request to the server.
The specs of single cell/row selection implies that there will usually be rows and columns that do not carry a selection.
Note that the case of expressly deselecting a cell is not handled.
The code does not resort to jquery.
<!DOCTYPE html>
<html>
<head>
<title>SO _: 1-in-a-row, 1-in-a-col selection</title>
<style type="text/css">
.selected {
background: #333;
color: #fff;
}
</style>
<script type="text/javascript">
let a_colSelection = new Array(3)
, a_rowSelection = new Array(3)
;
document.addEventListener ( 'DOMContentLoaded', () => {
Array.from(document.querySelectorAll('div[data-row][data-col]')).forEach ( el => {
el.addEventListener ( 'click', eve => {
let c = parseInt(eve.target.getAttribute('data-col'))
, r = parseInt(eve.target.getAttribute('data-row'))
;
if (a_colSelection[c] !== undefined) {
document.querySelector(`div[data-col="${a_colSelection[c][1]}"][data-row="${a_colSelection[c][0]}"]`).classList.remove("selected");
}
if (a_rowSelection[r] !== undefined) {
document.querySelector(`div[data-col="${a_rowSelection[r][1]}"][data-row="${a_rowSelection[r][0]}"]`).classList.remove("selected");
}
a_colSelection[c] = [r, c];
a_rowSelection[r] = [r, c];
document.querySelector(`div[data-col="${a_colSelection[c][1]}"][data-row="${a_rowSelection[r][0]}"]`).classList.add("selected");
});
});
});
</script>
</head>
<body>
<table border="1" cellpadding="5" class="test">
<tr>
<td class="talent-cell"><div data-value="0" data-col="0" data-row="0">aaa</div></td>
<td class="talent-cell"><div data-value="1" data-col="1" data-row="0">bbb</div></td>
<td class="talent-cell"><div data-value="2" data-col="2" data-row="0">ccc</div></td>
</tr>
<tr>
<td class="talent-cell"><div data-value="0" data-col="0" data-row="1">ddd</div></td>
<td class="talent-cell"><div data-value="1" data-col="1" data-row="1">eee</div></td>
<td class="talent-cell"><div data-value="2" data-col="2" data-row="1">fff</div></td>
</tr>
<tr>
<td class="talent-cell"><div data-value="0" data-col="0" data-row="2">ggg</div></td>
<td class="talent-cell"><div data-value="1" data-col="1" data-row="2">hhh</div></td>
<td class="talent-cell"><div data-value="2" data-col="2" data-row="2">iii</div></td>
</tr>
</table>
</body>
</html>
Consider the following.
Fiddle: https://jsfiddle.net/Twisty/dzng31f5/39/
HTML
<table border="1" cellpadding="5" class="test">
<tr class="var7">
<td class="talent-cell">
<div class="btn" data-value="0">aaa</div>
</td>
<td class="talent-cell">
<div class="btn" data-value="1">bbb</div>
</td>
<td class="talent-cell">
<div class="btn" data-value="2">ccc</div>
</td>
</tr>
<tr class="var8">
<td class="talent-cell">
<div class="btn" data-value="0">ddd</div>
</td>
<td class="talent-cell">
<div class="btn" data-value="1">eee</div>
</td>
<td class="talent-cell">
<div class="btn" data-value="2">fff</div>
</td>
</tr>
<tr class="var9">
<td class="talent-cell">
<div class="btn" data-value="0">ggg</div>
</td>
<td class="talent-cell">
<div class="btn" data-value="1">hhh</div>
</td>
<td class="talent-cell">
<div class="btn" data-value="2">iii</div>
</td>
</tr>
</table>
I adjusted the HTML Structure, such that each Row has a Class that represents the Index name that will be used in the Object.
jQuery
$(function() {
function checkCol(colIndex, table) {
var result = true;
console.log("Col Index:" + colIndex)
$("tbody tr", table).each(function(i, el) {
result = result && !$("td:eq(" + colIndex + ") div.btn", el).hasClass("selected");
});
return !result;
}
function checkRow(target, row) {
var isInCol = checkCol($(target).parent().index(), $(row).closest("table"));
if (!isInCol) {
if ($(".selected", row).length) {
$(".selected", row).removeClass("selected");
$(target).addClass("selected");
} else {
$(target).addClass("selected");
}
}
}
var selected = {};
$('.btn').click(function(event) {
var row = $(this).closest("tr");
checkRow(this, row);
$(".test tbody tr").each(function(i, el) {
selected[$(el).attr("class")] = $(".selected", el).length ? $(".selected", el).data("value") : "";
});
console.log(selected);
var params = new URLSearchParams(selected);
console.log(params.toString());
});
});
You can now use selected as your Data in a POST or GET call.
Updated
I had missed that each Row and Column needed to be unique. Code is updated to use Functions to check both conditions.
"Now I need a certain condition. It should be only allowed to select one div-attribute per table row and column."
The versatility of jQuery is leveraged by the use of this because it narrows down from many objects (all <td> in <table>) to a single object (<td> the user clicked). The behavior needed is common with radio button groups called "mutual exclusive selection", using .not(this) makes it simple.
In HTML,
assign a common class to each <div> (ex. '.col', see Figure I)
assign a class to each <div> that corresponds to the value of it's [data-value] (ex. '.c0', see Figure I)
Figure I
<div class='col c0' data-value='0'>
I did not include the params part in OP since it's beyond the scope of the question (see beginning of this answer). The values are stored in object C and is easily accessible (ex. C.c0).
BTW, I hope that the logic is different with your real code. For example, there is no difference between .c0 2nd row and .c0 1st row.
Details are commented in example below
// Declare object to store [data-value]
let C = {};
// Any click on a .col calls the event handler
$('.col').on('click', function() {
// Flip .selected on this .col
$(this).toggleClass('selected');
// If this .col is flipped to be .selected...
if ($(this).is('.selected')) {
//... get this .col [data-value] (0, 1, or 2)...
let idx = $(this).data('value');
/*
... find all .c0, .c1, or .c2 BUT NOT this .col and
remove .selected from them...
*/
$('.c' + idx).not(this).removeClass('selected');
/*
... then find the closest <tr>, then find all .col of
<tr> BUT NOT this .col and remove .selected from them
*/
$(this).closest('tr').find('.col')
.not(this).removeClass('selected');
// set key 'c0', 'c1', or 'c2' of C to this .col [data-value]
C['c'+idx] = $(this).data('value');
}
console.log(C);
});
<table border="1" cellpadding="5" class="test">
<tr>
<td><div class="col c0" data-value="0">aaa</div></td>
<td><div class="col c1" data-value="1">bbb</div></td>
<td><div class="col c2" data-value="2">ccc</div></td>
</tr>
<tr>
<td><div class="col c0" data-value="0">aaa</div></td>
<td><div class="col c1" data-value="1">bbb</div></td>
<td><div class="col c2" data-value="2">ccc</div></td>
</tr>
<tr>
<td><div class="col c0" data-value="0">aaa</div></td>
<td><div class="col c1" data-value="1">bbb</div></td>
<td><div class="col c2" data-value="2">ccc</div></td>
</tr>
</table>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
I have 3 columns, one column total_column_price uses to display the calculation result of amount and device_price. How to achieve that?
The Table
{{ Form::open(['action' => 'TransactionsINController#store', 'method' => 'POST']) }}
<table class="table table-hover table-bordered">
<thead align="center">
<tr>
<th>Amount</th>
<th>Device Price</th>
<th><a href="#" class="btn btn-primary btn-sm addRow">
<i class="fa fa-plus"></i>
</a>
</th>
<th>Column Total Price</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<div class="form-group">
{{ Form::number('amount[]', 'value', ['name' => 'amount[]']) }}
</div>
</td>
<td>
<div class="form-group">
{{ Form::number('device_price[]', 'value', ['name' => 'device_price[]']) }}
</div>
</td>
<td align="center">
<a href="#" class="btn btn-danger btn-sm remove">
<i class="fa fa-times"></i>
</a>
</td>
<td>
{{ Form::text('total_column_price', '') }}
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td>Total: </td>
<td style="border: none"><b class="total_price"></b></td>
<td style="border: none"></td>
</tr>
</tfoot>
</table>
{{ Form::button('<i class="far fa-save"></i> Submit', ['type' => 'submit', 'class' => 'btn btn-info'] ) }}
{{ Form::close() }}
This is the calculation I try to use. the purpose is when I make input in amount and device_price column the result will automatically appear in total_column_price.
The Script to Calculate
<script type="text/javascript">
$('tbody').delegate('.amount,.device_price','keyup',function(){
var tr=$(this).parent().parent();
var amount=tr.find('.amount').val();
var device_price=tr.find('.device_price').val();
var total_column_price=(amount*device_price);
tr.find(.total_column_price).val(total_column_price);
total_price();
});
function total_price(){
var total_price=0;
$('.total_column_price').each(function(i,e){
var total_column_price=$(this).val()-0;
total_price +=total_column_price;
});
$('.total_price').html(total_price+",00");
}
</script>
Everything seems to be good in your code the problem is way you are using the JQuery find function, you need to add quotes while entering the selector.
tr.find('.total_column_price').val(total_column_price);
Use the new event handle .on()
The .on() syntax is the new syntax that version 1.7 uses and it is meant to substitute .bind(), .delegate() and .live().
Another problem in your javascript was related to fetching the parent from on keyup in input box.
It should be like this
var tr = $(this).parent().parent().parent();
Try the code below:
$(function() {
$(document).on('keyup', 'input[name="amount[]"],input[name="device_price[]"]', function() {
var tr = $(this).parent().parent().parent();
var amount = tr.find('input[name="amount[]"]').val();
var device_price = tr.find('input[name="device_price[]"]').val();
var total_column_price = (amount * device_price);
total_price();
});
function total_price() {
var total_price = 0;
$('input[name="total_column_price[]"]').each(function(i, e) {
var total_column_price = $(this).val() - 0;
total_price += total_column_price;
});
$('.total_price').html(total_price + ",00");
}
})
I have a table and a list. I want the user to click on an item in the table and the text from the cell is added to the list.
function history_buff(obj){
var elList = Document.getElementById("user_history");
//alert("Trying to add item " + obj);
var element = Document.getElementById(str(obj))
var text = element.innerText || element.textContent;
var user_item = element.innerHTML = text;
alert("Trying to add: " + user_item)
var li = document.createElement("li");
li.innerHTML = user_item.value;
elList.appendChild(user_item);
}
function welcome(){
alert("Welcome home!");
}
And here's the HTML:
<div class="block" id="one">
<table id="name_table">
<tr>
<th>Name</th>
<th>Age</th>
<th>Job</th>
</tr>
<tr id="name_1">
<td><a onclick="history_buff();" href="static\text_files\alex.txt">Alex</a></td>
<td onclick="welcome();">12</td>
<td>Analyst</td>
</tr>
<tr id="name_2">
<td>Bill</td>
<td>54</td>
<td>Car Salesman</td>
</tr>
<tr id="name_3">
<td><a id="item_3" href="static\text_files\Rodrigo.txt">Rodrigo</a></td>
<td>7</td>
<td id="job_3" onclick="history_buff(this.id)">Merchant</td>
</tr>
</table>
</div>
<div class="block" id="two">
<h2>History</h2>
<ul id="user_history">
<li>Nothing</li>
<li>Something</li>
</ul>
</div>
I've tried many different ways similar to this, but can't seem to get it.
There are some errors in your function. Here is a fixed and working version:
function history_buff(obj) {
var elList = document.getElementById("user_history");
//alert("Trying to add item " + obj);
var element = document.getElementById(obj)
var text = element.textContent;
var user_item = text;
alert("Trying to add: " + user_item);
var li = document.createElement("li");
li.innerHTML = user_item;
elList.appendChild(li);
}
function welcome() {
alert("Welcome home!");
}
<div class="block" id="one">
<table id="name_table">
<tr>
<th>Name</th>
<th>Age</th>
<th>Job</th>
</tr>
<tr id="name_1">
<td>Alex</td>
<td onclick="welcome();">12</td>
<td id="job_1" onclick="history_buff(this.id)">Analyst</td>
</tr>
<tr id="name_2">
<td>Bill</td>
<td>54</td>
<td id="job_2" onclick="history_buff(this.id)">Car Salesman</td>
</tr>
<tr id="name_3">
<td><a id="item_3" href="static\text_files\Rodrigo.txt">Rodrigo</a></td>
<td>7</td>
<td id="job_3" onclick="history_buff(this.id)">Merchant</td>
</tr>
</table>
</div>
<div class="block" id="two">
<h2>History</h2>
<ul id="user_history">
<li>Nothing</li>
<li>Something</li>
</ul>
</div>
This is not the best way to do things, though.
Embrace the function addEventListener to bind events.
A string doesn't have a property called value, so, this user_item.value won't work.
Append to the list the new element li.
This approach is preventing the default behavior of a link using the function preventDefault from the event object, this way you will be able to see the added elements to the parent element user_history.
Array.prototype.forEach.call(document.querySelectorAll('td a'), function(a) {
a.addEventListener('click', history_buff)
});
function history_buff(event) {
event.preventDefault();
var elList = document.getElementById("user_history");
var text = this.innerText || element.textContent;
var user_item = this.innerHTML = text;
//console.log("Trying to add: " + user_item)
var li = document.createElement("li");
li.innerHTML = user_item;
elList.appendChild(li);
}
function welcome() {
alert("Welcome home!");
}
<div class="block" id="one">
<table id="name_table">
<tr>
<th>Name</th>
<th>Age</th>
<th>Job</th>
</tr>
<tr id="name_1">
<td>Alex</td>
<td onclick="welcome();">12</td>
<td>Analyst</td>
</tr>
<tr id="name_2">
<td>Bill</td>
<td>54</td>
<td>Car Salesman</td>
</tr>
<tr id="name_3">
<td><a id="item_3" href="static\text_files\Rodrigo.txt">Rodrigo</a></td>
<td>7</td>
<td id="job_3" onclick="history_buff(this.id)">Merchant</td>
</tr>
</table>
</div>
<div class="block" id="two">
<h2>History</h2>
<ul id="user_history">
<li>Nothing</li>
<li>Something</li>
</ul>
</div>
First, it is a bad habit to give your rows an ID, cause the records in the table could be dynamically generated,
Secondly, one likely reason your code didn't run is that when defining the
function history_buff(obj){
... do something
}
but when calling the function, you didn't pass the obj as a parameter
ie <td><a onclick="history_buff();" href="static\text_files\alex.txt">Alex</a></td>
finally,
` var element = Document.getElementById(str(obj)),
why dont you try
var element = Document.getElementById(${obj})`
I hope this helps
Try check this snippet :
function history_buff(value){
$("#user_history").append('<li><span class="tab">'+value+'</span></li>');
}
function welcome(){
alert("Welcome home!");
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="block" id="one">
<table id="name_table">
<tr>
<th>Name</th>
<th>Age</th>
<th>Job</th>
</tr>
<tr id="name_1">
<td><span onclick="history_buff('Alex');">Alex</span></td>
<td onclick="welcome();">12</td>
<td>Analyst</td>
</tr>
<tr id="name_2">
<td><span onclick="history_buff('Bill');">Bill</span></td>
<td>54</td>
<td>Car Salesman</td>
</tr>
<tr id="name_3">
<td><a id="item_3" href="static\text_files\Rodrigo.txt">Rodrigo</a></td>
<td>7</td>
<td id="job_3" onclick="history_buff(this.id)">Merchant</td>
</tr>
</table>
</div>
<div class="block" id="two">
<h2>History</h2>
<ul id="user_history">
<li>Nothing</li>
<li>Something</li>
</ul>
</div>
You should go through understanding and basic tutorials on Javascript and jQuery. You should achieve your desired outcome easily.
https://www.w3schools.com/js/default.asp
https://www.w3schools.com/jquery/default.asp
function history_buff(obj){
var elList = document.getElementById("user_history");
var element = document.getElementById(obj)
var text = element.innerText || element.textContent;
var user_item = element.innerHTML = text;
alert("Trying to add: " + user_item)
var li = document.createElement("li");
li.innerHTML = user_item;
elList.appendChild(li);
}
Notice from your code:
str() is not a js function
li.innerHtml should equal to user_item instead of user_item.value - which is undefined. Then append li to the ul list
I got something like this:
<tr bgcolor="lightgrey">
<th>ID</th>
<th>Name</th>
</tr>
<tr ng-repeat="s in schools| filter:searchField | orderBy:'schoolId'"
ng-click="selectSchool(s, $index)"
ng-class="getSelectedClass(s)">
<td>{{s.schoolId}}</td>
<td>{{s.schoolName}}</td>
</tr>
Ok, now that school has an int parameter, and now I want to add a simple image (green and/or red dot) to my table...but if the parameter is 0 it should be the red dot else it should be the green one...
So is it possible to do it somehow with an if statement in angular?
And if yes, i need it to be clickable, so once i press the red dot, it should become green and vice versa.
Use ng-if="parameter === 0"
<img> red dot image
ng-if="parameter!==0"
<img> green dot image
Or you may also do
<img ng-src="{{parameter===0?'reddotsrc' : 'greendotsrc'}}" ng-click="parameter!=parameter">
If parameter is 0 then it toggle 1 and if 1 then it to 0.
You can use ng-show :
Html:
<div ng-app>
<div ng-controller="TodoCtrl">
<table>
<tr ng-repeat = "data in comments">
<td>{{data.type}}, {{data.type == 1}}</td>
<td ng-show="data.type == 1 ">
<img style="height:10px; width:10px; padding:5px;" src="http://greensportsalliance.org/images/darkGreenSquare.gif">
</td>
<td ng-show="data.type == 0 ">
<img style="height:10px; width:10px; padding:5px;" src="http://cdn.playbuzz.com/cdn/04854427-89c9-48dc-bb5b-9705e0a298b5/6cb7bccb-3dcd-4af2-8da8-8c6260f2f934.jpg">
</td>
</tr>
</table>
</div>
</div>
Javascript:
function TodoCtrl($scope) {
$scope.comments = [
{type:1},{type:0},{type:0},{type:1}
]
}
Working example
this may help you
<tr bgcolor="lightgrey">
<th>ID</th>
<th>Name</th>
</tr>
<tr ng-repeat="s in schools| filter:searchField | orderBy:'schoolId'"
ng-click="selectSchool(s, $index)"
ng-class="getSelectedClass(s)">
<td ng-if="s.parameter == 0"><img src='reddot.png' ng-click="s.parameter = 1"></td>
<td ng-if="s.parameter != 0"><img src='greendot.png' ng-click="s.parameter = 0"></td>
<td>{{s.schoolId}}</td>
<td>{{s.schoolName}}</td>
</tr>
ok so i have my view model
function viewModel(calendarData) {
var self = this;
self.Calendars = ko.mapping.fromJS(calendarData);
self.ViewedCalendar = {};//what can/should i set this to be on initial creation?
self.DisplayCalendar = function (calendar) {
self.ViewedCalendar = calendar;
};
};
I then have my html:
<div data-bind="visible: Calendars().length > 0">
<h2>You have <span data-bind="text: Calendars().length"></span> calendars</h2>
<table class="table">
<thead>
<tr>
<th>Calendars</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody data-bind="foreach: Calendars">
<tr>
<td data-bind="text: Name"></td>
<td><span data-bind="text: Events().length"></span> events</td>
<td><a href='#' data-bind='click: $root.DisplayCalendar'>View</a></td>
</tr>
</tbody>
</table>
</div>
<div data-bind="visible: ViewedCalendar() !== null">
Your are viewing <span data-bind="text: ViewedCalendar.Name"></span><br />
</div>
What I am trying to achieve is when the user clicks View for a given calendar, that via DisplayCalendar() I set the property ViewedCalendar to be set to the given calendar.
This then shows my div that contains the label stating what calendar is being viewed.
This is all rough code at the minute just to get the basic functionality in place but I'm new to knockout so could use some help.
I'm getting TypeError: ViewedCalendar is not a function or ViewedCalendar is undefined.
Any help would be much appreciated.
The ViewedCalendar property needs to be an observable for knockout to reach to changes in it's value. You defined it like this:
self.ViewedCalendar = {};
Which is an (empty) object literal and not a function (as the error message correctly stated). What you need is:
self.ViewedCalendar = ko.observable(); // empty () give you an empty observable - no calendar selected yet
And then you can update it in your click handler with:
self.ViewedCalendar(calendar);
Here's a working full example:
function viewModel(calendarData) {
var self = this;
self.Calendars = ko.mapping.fromJS(calendarData);
self.ViewedCalendar = ko.observable();
self.DisplayCalendar = function (calendar) {
self.ViewedCalendar(calendar);
};
};
ko.applyBindings(new viewModel([{Name:'some calendar', Events: []}, {Name:'another calendar', Events: []}]));
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.js"></script>
<div data-bind="visible: Calendars().length > 0">
<h2>You have <span data-bind="text: Calendars().length"></span> calendars</h2>
<table class="table">
<thead>
<tr>
<th>Calendars</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody data-bind="foreach: Calendars">
<tr>
<td data-bind="text: Name"></td>
<td><span data-bind="text: Events().length"></span> events</td>
<td><a href='#' data-bind='click: $root.DisplayCalendar'>View</a></td>
</tr>
</tbody>
</table>
</div>
<div data-bind="with: ViewedCalendar">
Your are viewing <span style="font-weight: bold" data-bind="text: Name"></span><br />
</div>