I have the following sample grid in which I push some new values to the bound list.
Press anywhere in the grid to push a new value to the grid.
As you can see in the fiddle, the updated cell will have a green color for 500 ms, and all the re-rendered elements will have yellow color.
The question is how we should configure Vue component so that it only re-render the changed element instead of them all?
If you look at the fiddle console output, you will see numbers like (13001, 26001, ...) and this equals to the number of all cells (1000 rows x 13 columns).
.yellow {
background-color: yellow;
}
.pushed {
background-color: lightgreen
}
<script src="https://unpkg.com/vue">
var globalCount = 0;
</script>
<head>
<title>Vue Render Performance</title>
</head>
<div id="demo">
<demo-grid :data="gridData" :columns="gridColumns"> </demo-grid>
</div>
<script type="text/x-template" id="grid-template">
<table #click="pushData()">
<thead>
<tr>
<th v-for="key in columns">
{{key}}
</th>
</tr>
</thead>
<tbody>
<tr v-for="(entry, i) in data">
<td v-for="(key, j) in columns" :id="'a'+i +'_'+j">
{{renderMe(entry[key], 'a'+i +'_'+j)}}
</td>
</tr>
</tbody>
</table>
</script>
<script>
const data = newData(1000);
var renderedCount = 0;
var startTime = performance.now();
Vue.component('demo-grid', {
props: {
data: Array,
columns: Array,
renderCount: Object,
},
template: '#grid-template',
methods: {
renderMe(el, id) {
const elm = document.getElementById(id);
if (elm) {
elm.className += " yellow";
}
if (!renderedCount) {
renderedCount = 0
} else {
renderedCount++;
}
return el;
},
pushData() {
debugger
var push = function() {
let cols = ["Col1", "Col2", "Col3", "Col4", "Col5", "Col6", "Col7", "Col8", "Col9", "Col10", "Col11", "Col12", "Col13"];
var t0 = performance.now();
for (let i = 0; i < 1; i++) {
let newVal = Math.random() * 10000,
row = Math.round(Math.random() * 1000),
cellIndex = Math.floor(Math.random() * cols.length);
cell = cols[cellIndex];
if (data[row])
data[row][cell] = newVal;
var el = document.querySelector('tbody tr:nth-child(' + row + ') td:nth-child(' +
cellIndex +
')');
if (el) {
el.className = 'pushed';
el.scrollIntoView();
var t = function() {
if (el) {
el.className = '';
}
clearTimeout(t);
};
setTimeout(t, 500);
}
console.log('pushed to cell [' + row + ',' + cellIndex + '] :' + newVal);
console.log('Rendered Count: ' + renderedCount)
renderedCount++;
};
var t1 = performance.now();
console.log(t1 - t0)
};
push();
}
}
});
// bootstrap the demo
var demo = new Vue({
el: '#demo',
data: {
searchQuery: '',
gridColumns: ["Col1", "Col2", "Col3", "Col4", "Col5", "Col6", "Col7", "Col8", "Col9", "Col10", "Col11", "Col12", "Col13"],
gridData: data
}
})
Vue.config.devtools = true;
function newData(count) {
const data = [];
for (let i = 0; i < count; i++) {
data.push({
Col1: "Record",
Col2: 818959475,
Col3: 467587749,
Col4: 438,
Col5: 439,
Col6: 440,
Col7: 2.1,
Col8: 436.2,
Col9: 2.4,
Col10: 5770,
Col11: 5771,
Col12: 5772,
Col13: 5773
});
}
return data;
}
</script>
When you don't want to re-render and entire list of information, the typical way to handle it is to push the things that need to re-render into a component. Here is an updated version of your code that pushes the rows into a component and renders a fraction of what you were doing before.
Vue.component("demo-row", {
props:["entry", "columns", "rowIndex"],
template:`
<tr>
<td v-for="(key, j) in columns" :id="'a'+rowIndex +'_'+j">
{{renderMe(entry[key], 'a'+rowIndex +'_'+j)}}
</td>
</tr>
`,
methods:{
renderMe(el, id) {
const elm = document.getElementById(id);
if (elm) {
elm.className += " yellow";
}
if (!renderedCount) {
renderedCount = 0
} else {
renderedCount++;
}
return el;
},
}
})
Vue.component('demo-grid', {
props: {
items: Array,
columns: Array
},
template: '#grid-template',
methods: {
pushData() {
this.$parent.pushData(this.$parent.gridItems, this.$parent.gridColumns);
}
}
});
Example codepen.
Note, I did not change anything else that you are doing that could probably be done more idiomatically in Vue, I just wanted to demonstrate that there is no need for everything to re-render.
Related
My problem is not making the chart, but when I input new values for the start freq and end freq, which are the first and last values of my x-axis array after calling getFreq(), the chart glitches when I hover, going back and forth between the old data and new data. Can anyone help me figure out how to delete the old data and make/update to a new chart where the chart doesn't flicker? My code is shown below.
If you want to test the graph
put 39.4 as attenuation, 0.1 as a, 0.05 as b, 0.16 for diameter, 15 for conductivity, and 25 and 125 as the start and end freq respectively. To test the flickering, just replace 25 with another number and hover over the graph.
let Conductivity = document.getElementById('Conductivity');
let StartFreq = document.getElementById('StartFreq');
let StopFreq = document.getElementById('StopFreq');
let a = document.getElementById('a');
let b = document.getElementById('b');
let unitInch = document.getElementById('unitInch');
let test = document.getElementById('test');
let diameter = document.getElementById('Diameter');
let ctx = document.getElementById('myChart').getContext('2d');
function generateLabels(){
// To generate the xa xis intervals
let xaxis = [];
for (let i = 0; i <= 10; i++) {
let valToAppend = Math.round((parseFloat(StartFreq.value) + (parseFloat(StopFreq.value)-parseFloat(StartFreq.value)) / 10 * i)*100)/100;
if (valToAppend <= parseFloat(StopFreq.value)){
xaxis.push(valToAppend)
}
}
return xaxis
}
function getFreq(){
let x = generateLabels();
let freq = [];
let start = x[0];
freq.push(start);
let end = x[x.length - 1];
for (let i=0; i < 4 * (end-start);i++){
let lastfreq = freq[freq.length - 1];
freq.push(lastfreq + 0.25)
}
// let rklen = freq.length;
return freq
}
function getRS(){
let RS = [];
let freq = getFreq();
freq.forEach(element =>{
let RStoAppend = Math.sqrt((2*Math.PI*(Math.pow(10,9)*element)*(4*Math.PI*Math.pow(10,-7)))/(2*(parseFloat(Conductivity.value)*Math.pow(10,7)))) ;
RS.push(RStoAppend)
});
return RS
}
function getRK(){
let RK = [];
let freq = getFreq();
freq.forEach(element => {
let RKtoappend = (2*Math.PI*(element * Math.pow(10,9))) / (3* Math.pow(10,8));
RK.push(RKtoappend)
});
return RK
}
function getRbeta(){
let Rbeta = [];
let RK = getRK();
RK.forEach(element => {
let Rbetatoappend = Math.sqrt(Math.pow(element,2) - Math.pow((Math.PI/(parseFloat(a.value)*25.4/1000)),2));
Rbeta.push(Rbetatoappend);
});
return Rbeta;
}
function getRatte(){
let Ratte = [];
let RS = getRS();
let RK = getRK();
let Rbeta = getRbeta();
for (let i = 0; i < RS.length ;i++){
let Rattetoappend = RS[i]*(2*(25.4/1000*parseFloat(b.value))*Math.pow(Math.PI,2)+Math.pow((parseFloat(a.value)*25.4/1000),3)*Math.pow(RK[i],2))/(Math.pow((parseFloat(a.value)*25.4/1000),3)*(25.4/1000*parseFloat(b.value))*Rbeta[i]*RK[i]*377)/(1000/25.4);
Ratte.push(Rattetoappend);
}
// test.innerHTML = '<td id="test">' + Ratte + '<td>';
return Ratte
}
function getRTE10(){
let RTE10 = [];
let Ratte = getRatte();
Ratte.forEach(element => {
if (isNaN(-20*Math.log10(Math.exp(-element)) * parseFloat(unitInch.value))) {
RTE10.push(0)
}
else {
RTE10.push(-20 * Math.log10(Math.exp(-element)) * parseFloat(unitInch.value))
}
});
return RTE10
}
//////////////////////// For CTE11/////////////
function getk(){
let k = [];
let freq = getFreq();
freq.forEach(element => {
k.push(2*Math.PI*element*Math.pow(10,9)/(3*Math.pow(10,8)))
});
return k
}
function getbeta(){
let beta = [];
let k = getk();
k.forEach(element => {
beta.push(Math.sqrt(Math.pow(element,2)-Math.pow((1.8412/(parseFloat(diameter.value)/2*25.4/1000)),2)))
});
return beta
}
function getTE11_1(){
let TE11_1 = [];
let k = getk();
let rs = getRS();
let beta = getbeta();
for (let i = 0; i < rs.length ;i++){
TE11_1.push(rs[i]*(Math.pow((1.8412/(parseFloat(diameter.value)/2*25.4/1000)),2)+Math.pow(k[i],2)/(Math.pow(1.8414,2)-1))/((parseFloat(diameter.value)/2*25.4/1000)*k[i]*beta[i]*377)/(1000/25.4));
}
return TE11_1
}
function getCTE11(){
let CTE11 = [];
let TE11_1 = getTE11_1();
TE11_1.forEach(element => {
if (isNaN(-20 * Math.log10(Math.exp(-element)) * parseFloat(unitInch.value))) {
CTE11.push(0)
}
else {
CTE11.push(-20 * Math.log10(Math.exp(-element)) * parseFloat(unitInch.value))
}
});
// test.innerHTML = '<td id="test">' + CTE11 + '<td>';
return CTE11
}
function getTM01(){
let TM01 = [];
let rs = getRS();
let freq = getFreq();
for (let i = 0; i < rs.length ;i++){
TM01.push(rs[i]/((parseFloat(diameter.value)/2 *25.4/1000)*377*Math.sqrt(1-Math.pow(((2.4049/(2*Math.PI*parseFloat(diameter.value)/2 *25.4/1000)*0.3)*Math.pow(10,9)/(freq[i]*Math.pow(10,9))),2)))/(1000/25.4));
}
return TM01
}
function getCTM01(){
let CTM01 = [];
let TM01 = getTM01();
TM01.forEach(element => {
if (isNaN(-20 * Math.log10(Math.exp(-element)) * parseFloat(unitInch.value))) {
CTM01.push(0)
}
else {
CTM01.push(-20 * Math.log10(Math.exp(-element)) * parseFloat(unitInch.value))
}
});
return CTM01
}
function getAt2(){
let at2 = [];
let freq = getFreq();
freq.forEach(element =>{
at2.push(Math.pow(((3.8318/(2*Math.PI*parseFloat(diameter.value)/2 *25.4/1000)*0.3)*Math.pow(10,9)/(element*Math.pow(10,9))),2)+1/(Math.pow(3.8318,2)-1))
});
return at2
}
function getAt1(){
let at1 = [];
let freq = getFreq();
let rs = getRS();
for (let i = 0; i < rs.length ;i++){
at1.push(rs[i]/(parseFloat(diameter.value)/2 *25.4/1000*377*Math.sqrt(1-Math.pow(((3.8318/(2*Math.PI*parseFloat(diameter.value)/2 *25.4/1000)*0.3)*Math.pow(10,9)/(freq[i]*Math.pow(10,9))),2)))/(1000/25.4));
}
return at1
}
function getCTE01(){
let CTE01 = [];
let at1 = getAt1();
let at2 = getAt2();
for(let i = 0;i < at1.length; i++){
if (isNaN((-20*Math.log10(Math.exp(-(at1[i]*at2[i])))*parseFloat(unitInch.value)))) {
CTE01.push(0)
}
else {
CTE01.push(-20 * Math.log10(Math.exp(-(at1[i] * at2[i]))) * parseFloat(unitInch.value))
}
}
return CTE01
}
function getdata(){
let data =[];
let xaxis = getFreq();
let RTE10 = getRTE10();
let CTE11 = getCTE11();
let CTM01 = getCTM01();
let CTE01 = getCTE01();
data.push(xaxis,RTE10,CTE11,CTM01,CTE01);
return data
}
function draw_chart(data) {
let chart = new Chart(ctx, {
// The type of chart we want to create
type: 'line',
// The data for our dataset
data: {
labels: data[0],
datasets: [{
label: 'R-TE10',
data: data[1],
pointStyle : 'line',
backgroundColor: 'transparent',
borderColor: 'blue',
pointRadius: '0'
},{
label: 'C-TE11',
data: data[2],
pointStyle : 'line',
backgroundColor: 'transparent',
borderColor: 'orange',
pointRadius: '0'
},{
label: 'C-TM01',
data: data[3],
pointStyle : 'line',
backgroundColor: 'transparent',
borderColor: 'green',
pointRadius: '0'
},{
label: 'C-TE01',
data: data[4],
pointStyle : 'line',
backgroundColor: 'transparent',
borderColor: 'red',
pointRadius: '0'
}]
},
// Configuration options go here
options: {
responsive : true,
scales: {
xAxes :[{
ticks: {
min: StartFreq,
max: StopFreq,
suggestedMin: StartFreq,
suggestedMax: StopFreq,
stepSize: 0.25,
}
}],
yAxes: [{
ticks: {
min:0,
max:10,
suggestedMin: 0,
suggestedMax: 10,
maxTicksLimit: 11,
stepSize : 1,
beginAtZero: true,
}
}]
}
}
});
}
function generateChart() {
// removeData(chart);
let data = getdata();
draw_chart(data);
}
HTML
<table class="inner">
<tr class="inner">
<td class="inner"> Attenuation (air) /</td>
<td class="inner"> <input class="numInput" type="number" id="unitInch"/></td>
<td class="inner">(in inches)</td>
</tr>
<tr class="inner">
<td class="inner" colspan="2">Rectangular WG</td>
<td class="inner">Circular WG</td>
<td class="inner">Material</td>
</tr>
<tr class="inner">
<td class="inner">a (inch)</td>
<td class="inner">b (inch)</td>
<td class="inner">Diameter (inch)</td>
<td class="inner">Conductivity ( x 10<sup>7</sup> S/m)</td>
<td class="inner">Start Freq (GHz)</td>
<td class="inner">Stop Freq (GHz)</td>
</tr>
<tr class="inner">
<td class="inner"><input class="numInput" type="number" id='a'/></td>
<td class="inner"><input class="numInput" type="number" id="b"/></td>
<td class="inner"><input class="numInput" type="number" id="Diameter"/></td>
<td class="inner"><input class="numInput" type="number" id="Conductivity"/></td>
<td class="inner"><input class="numInput" type="number" id="StartFreq"/></td>
<td class="inner"><input class="numInput" type="number" id="StopFreq"/></td>
</tr>
</table>
<button onclick="generateChart()"><strong>Generate Chart</strong></button>
<div id="chartsize">
<canvas id="myChart"></canvas>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.js"></script>
<script src="js/chart.js"></script>
By the way, my chart works completely fine the first time I load the page, then when I update, the chart flickers like crazy when hovering. I added in a lot more code, so that you guys can recreate the chart and figure it out. Please ignore the bad style, I am new to Web Development...
It is because chartjs doesn't redraw the chart, it creates a new one over the old one. You have to make a reset function that gets called before the new chart is drawn
I'm practicing javascript and learning on my own. I am creating a game where you enter a text coordinates and the game tells you whether you dug something up or not. But I am trying to implement a text box so you can play out of a browser instead of the command prompt, but I'm having trouble getting the game to take the text and then run the code using it when you click on the button.
Here is the HTML for the game.
<head>
<meta charset="UTF-8">
<title>Game Board</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8/jquery.min.js"></script>
<script type="text/javascript" src="board.js"></script>
<script type="text/javascript" src="game.js"></script>
</head>
<body>
<center>
<h1>Archaeology Board</h1>
Palace = 5 Spaces </br>
Temple = 4 Spaces </br>
Forum = 4 Spaces </br>
House = 3 Spaces </br>
Hut = 2 Spaces </br>
<h3>
<table id="board">
</table>
</h3>
<p>
<label for="DigBox">Enter dig coordinates:</label>
<input type="text" id="DigBox" size="3" value="" />
<input type="button" value="Dig" id="run" />
</p>
<p><input type="button" value="Restart Game" id="restart" /></p>
</center>
</body>
</html>
This is the js file to create the board.
function GameBoard()
{
this.ruins = [
{
name: "Palace",
size: 5,
successes: 0
},
{
name: "Temple",
size: 4,
successes: 0
},
{
name: "Forum",
size: 4,
successes: 0
},
{
name: "House",
size: 3,
successes: 0
},
{
name: "Hut",
size: 2,
successes: 0
}
];
this.rows = ["a", "b", "c", "d", "e", "f", "g", "h"];
this.columns = ["1", "2", "3", "4", "5", "6", "7", "8"];
this.cellMarker = 'X';
}
GameBoard.prototype.setBoard = function ()
{
var i, j, boardTags;
boardTags = "";
// build the first row of column labels
boardTags += "<tr><th> </th>";
for (j = 0; j < this.columns.length; j++) {
boardTags += "<th>" + this.columns[j] + "</th>";
}
boardTags += "</tr>";
// build the table with HTML tags
for (i = 0; i < this.rows.length; i++) {
boardTags += "<tr>";
boardTags += "<th>" + this.rows[i] + "</th>"; // row labels
for (j = 0; j < this.columns.length; j++) {
boardTags += "<td class='square' id='cell" +
this.rows[i] + this.columns[j] + "'>" + this.cellMarker + "</ td>";
}
boardTags += "</tr>";
}
$("#board").html(boardTags);
for (i = 0; i < this.ruins.length; i++) {
this.setRuin(this.ruins[i]);
}
}
GameBoard.prototype.dig = function(square, processResult)
{
var target, targetObj;
target = $("#cell"+square).attr('ruin');
if (target) {
targetObj = this.getRuin(target);
if (! $("#cell"+square).attr('dug')) {
$("#cell"+square).attr('dug', 'yes');
targetObj.successes++;
}
return targetObj;
}
else {
return undefined;
}
}
GameBoard.prototype.getRuin = function(ruinName)
{
for (var i = 0; i < this.ruins.length; i++) {
if (ruinName === this.ruins[i].name) {
return this.ruins[i];
}
}
return undefined;
}
GameBoard.prototype.randomSquare = function()
{
var colIndex = Math.floor(Math.random() * this.columns.length);
var rowIndex = Math.floor(Math.random() * this.rows.length);
return this.rows[rowIndex] + this.columns[colIndex];
}
GameBoard.prototype.setRuin = function(ruin)
{
// keeps randomly trying to place a ruin until it fits on the board
var candidateSquare = this.randomSquare();
var across = Math.random() < 0.5;
var success = this.tryPlacement(ruin, candidateSquare, across, ruin.size);
while (! success) {
candidateSquare = this.randomSquare();
across = Math.random() < 0.5;
success = this.tryPlacement(ruin, candidateSquare, across, ruin.size);
}
}
GameBoard.prototype.tryPlacement = function(ruin, square, across, size) {
var nextSquare;
if (size === 0) {
// ruin fits!
return true;
}
else if (! square) {
// invalid square
return false;
}
if (! $("#cell" + square).attr('ruin')) {
$("#cell" + square).attr('ruin', ruin.name);
// see if the rest of the ruin fits
if (this.tryPlacement(ruin, this.increment(square, across), across, size - 1)) {
// ruin fits!
return true;
}
else {
// ruin didn't fit --- undo occupied square and return false
$("#cell" + square).removeAttr('ruin');
return false
}
}
}
GameBoard.prototype.increment = function(square, across)
{
if (across) {
// need to increment the column dimension if possible
var colIndex = this.columns.indexOf(square.charAt(1));
colIndex++;
if (colIndex === this.columns.length) {
return undefined;
}
else {
return square.charAt(0) + this.columns[colIndex];
}
}
else {
// need to increment the row dimension if possible
var rowIndex = this.rows.indexOf(square.charAt(0));
rowIndex++;
if (rowIndex === this.rows.length) {
return undefined;
}
else {
return this.rows[rowIndex] + square.charAt(1);
}
}
}
This is the code I'm trying to implement in
$(function () {
tryDig = function(targetCell)
{
var targetObj = board.dig(targetCell);
if (targetObj) {
alert('Success finding the ' + targetObj.name);
$("#cell"+targetCell).html('#');
$("#cell"+targetCell).css('color', 'blue');
}
else {
alert('Failure!');
$("#cell"+targetCell).html('*').css('color', 'red');
}
}
board = new GameBoard();
board.setBoard();
});
initialize = function() {
$("#run").click(tryDig);
}
initialize = function() {
$("#restart").click(GameBoard.prototype.setBoard);
}
$(initialize);
I want to make it so whatever is in the text box, the game uses that as the coordinates to dig up in the board.
I have a table with some dynamic data, and columns as Name,Location, Salary. Problem i am facing in Step 2 i.e multiple condition check. Heres the step by step code.
JS Fiddle Demo
Step 1-
Auto generate Filters i.e dynamically add Checkboxes, depend on table row values
autoFilterItem("filterDiv");
Above function generate dynamic checkboxes, logic is it loop over table, read values row by row and return unique value array and generate checkbox respectively, currently am doing for 2 cols having class loc,sal.
Step 2-
Checkbox change event, depend on status (checked/unchekced) table rows will be hide/show .
The problem i am facing is, if user checked 100 ( class as sal), and Kerala ( class as loc) is unchecked then row having kerala should be hide.
For hide and show am adding/removing class .hideRow
///STEP TWO
// On any checkbox clicked returns desired out
$("body").on('change', '.chk', function () {
var arrObj = [],
arrCheckedValueCLass = [];
var objCheckedData = {};
$("#filterDiv .chk").each(function (index, val) {
var sf = $(this);
if (sf.is(":checked")) {
var sf = $(this);
arrObj.push({
dataValue: $(sf).attr('data-value'),
dataClass: $(sf).attr('data-class')
});
}
});
var self = $(this);
var getClassName = self.attr("data-class");
var matchTextValue = $.trim(self.attr("data-value"));
if (self.is(":checked")) {
if (matchTextValue == "All") {
$(".chk").prop('checked', true);
}
$("." + getClassName).each(function () {
var innerSelf = $(this);
var gVal = $.trim(innerSelf.html());
if (matchTextValue == "All") {
innerSelf.closest("tr").removeClass("hideRow");
} else {
if (matchTextValue === gVal) {
console.log("checked and matchTextValue");
var i = 0,
lg = arrObj.length;
var flagSet = false;
for (i; i < lg; ++i) {
var objValue = arrObj[i].dataValue;
var objClass = arrObj[i].dataClass;
if (getClassName != objClass) {
var prevDataCheck = $.trim(innerSelf.closest("tr").find("." + objClass).html());
if (prevDataCheck == objValue) {
flagSet = true;
return true;
}
}
}
if (!flagSet) {
innerSelf.closest("tr").removeClass("hideRow");
innerSelf.closest("tr").addClass(getClassName + "_X");
}
}
}
});
} else {
if (matchTextValue == "All") {
$(".chk").prop('checked', false);
}
$("." + getClassName).each(function () {
var innerSelf = $(this);
var gVal = $.trim(innerSelf.html());
if (matchTextValue === gVal) {
innerSelf.closest("tr").addClass("hideRow");
innerSelf.closest("tr").removeClass(getClassName + "_X");
}
});
}
});
<div id="filterDiv"></div>
<button>Click</button>
<br>
<div id="tableContainer">
<table id="myTable">
<thead>
<tr>
<th data-name='name'>Name</th>
<th data-loc='Location'>Location</th>
<th data-sal='salary'>Salary</th>
<th data-sts='Active'>Active</th>
</tr>
</thead>
<tbody>
<tr>
<td class="name">James</td>
<td class="loc">Mumbai</td>
<td class="sal">500</td>
<td class="sts">Yes</td>
</tr>
<tr>
<td class="name">Joseph</td>
<td class="loc">Kerala</td>
<td class="sal">100</td>
<td class="sts">No</td>
</tr>
<tr>
<td class="name">Jack</td>
<td class="loc">Delhi</td>
<td class="sal">500</td>
<td class="sts">Yes</td>
</tr>
<tr>
<td class="name">Andrea</td>
<td class="loc">Mumbai</td>
<td class="sal">1000</td>
<td class="sts">No</td>
</tr>
<tr>
<td class="name">David</td>
<td class="loc">Delhi</td>
<td class="sal">100</td>
<td class="sts">No</td>
</tr>
<tr>
<td class="name">David</td>
<td class="loc">Delhi</td>
<td class="sal">99900</td>
<td class="sts">No</td>
</tr>
</tbody>
</table>
</div>
I have created the fiddle from the things that you noted and able to produce the result( that is, if user checked 100 ( class as sal), and Kerala ( class as loc) is unchecked then row having kerala should be hide.)
I do not how efficient the solution is.There may be more efficient way to acheive that but anyway below is the js code.
$(document).ready(function () {
//STEP ONE STARTS
// This function generate checkbox from table data, which will be used for filteration
autoFilterItem("filterDiv");
function autoFilterItem(idOfHolderDiv) {
$("#" + idOfHolderDiv).empty();
var arr1 = [];
$(".sal").each(function () {
arr1.push($.trim($(this).html()));
});
var arrNew = unique(arr1).sort(function (a, b) {
return a - b
});
$.each(arrNew, function (i, val) {
$("<input/>", {
"type": "checkbox",
"class": "chk",
"data-class": "sal",
"data-value": val,
"id": "chk" + val,
"checked": "checked"
}).appendTo("#" + idOfHolderDiv).wrap("<div></div>").after(val);
});
$("#" + idOfHolderDiv).append("<hr>");
var arr2 = [];
$(".loc").each(function () {
arr2.push($.trim($(this).html()));
});
var arr2New = unique(arr2).sort();
$.each(arr2New, function (i, val) {
$("<input/>", {
"type": "checkbox",
"class": "chk",
"data-class": "loc",
"data-value": val,
"id": "chk" + val,
"checked": "checked"
}).appendTo("#" + idOfHolderDiv).wrap("<div></div>").after(val);
});
$("#" + idOfHolderDiv).append("<hr>");
function unique(array) {
return $.grep(array, function (el, index) {
return index == $.inArray(el, array);
});
}
}
// STEP ONE ENDS
///STEP TWO
// On any checkbox clicked returns desired out
var selectedSalaryArr = [];
var selectedLocationArr = [];
$("body").on('change', '.chk', function () {
var selectedVal = $(this).attr('data-value');
$('#filterDiv div').each(function () {
var checkedval = $(this).find('input.chk').attr('data-value');
var isChecked = $(this).find('input.chk').is(':checked');
var dataClass = $(this).find('input.chk').attr('data-class');
if (selectedVal === checkedval) {
if (dataClass === 'sal') {
var isExists = $.inArray(checkedval, selectedSalaryArr);
if (isExists === -1) {
selectedSalaryArr.push(checkedval);
} else {
selectedSalaryArr.splice($.inArray(checkedval, selectedSalaryArr), 1);
}
} else {
var isExists = $.inArray(checkedval, selectedLocationArr);
if (isExists === -1) {
selectedLocationArr.push(checkedval);
} else {
selectedLocationArr.splice($.inArray(checkedval, selectedLocationArr), 1);
}
}
}
});
$('#myTable tbody tr').each(function () {
var currentSalary = $(this).find('.sal').text();
var currentLocation = $(this).find('.loc').text();
var matchedSalaryValueExists = $.inArray(currentSalary, selectedSalaryArr);
var matchedLocationValueExists = $.inArray(currentLocation, selectedLocationArr);
if (selectedSalaryArr.length > 0 && selectedLocationArr.length > 0) {
if (matchedSalaryValueExists !== -1 && matchedLocationValueExists !== -1) {
if (!($(this).hasClass('hiderow'))) {
$(this).addClass('hiderow');
}
} else {
if ($(this).hasClass('hiderow')) {
$(this).removeClass('hiderow');
$(this).show();
}
}
}
else {
if (matchedSalaryValueExists !== -1 || matchedLocationValueExists !== -1) {
if (!($(this).hasClass('hiderow'))) {
$(this).addClass('hiderow');
}
} else {
if ($(this).hasClass('hiderow')) {
$(this).removeClass('hiderow');
$(this).show();
}
}
}
});
$('#myTable tbody tr.hiderow').hide();
});
});
Below is the jsfiddle link:
https://jsfiddle.net/shrawanlakhe/v8gyde77/
http://jsfiddle.net/Kapil_B/vz3r0bs3/9/
In this fiddle I am trying to update the formattedPrice2 value on changing the rates in the textbox.I am able to get the updated price but the price1 is not getting updated value.
Can you please tell me the reason why the price1 value is not getting updated? That is why formattedPrice2 is not getting updated.
<select data-bind="options: $root.newLot, value: dropdownAValue, optionsText: 'type'"></select>
<table align="left">
<thead>
<tr align="left">
<th width="10%">Pair</th>
<th width="10%">Rate</th>
<th width="10%">formattedPrice2</th>
</tr>
</thead>
<!-- Todo: Generate table body -->
<tbody data-bind="foreach:curArray">
<tr>
<td data-bind="text: rate().pair"></td>
<td> <input data-bind="value: myQuote, valueUpdate:'afterkeydown'" />
</td>
<td data-bind="text: formattedPrice2"></td>
</tr>
</tbody>
</table>
// Class to represent a row in the price calculation grid
function PriceCalculation(rate, myQuote, newPairs, nl, currentlotvalue) {
var self = this;
self.rate = ko.observable(rate);
self.newPairs = newPairs;
self.nl = ko.observable(nl);
self.myQuote = ko.observable(myQuote);
self.currentlotvalue = currentlotvalue;
self.leverage = self.rate().leverage;
self.formattedPrice2 = ko.computed(function () {
var cur = self.rate().pair;
//var price = self.rate().price;
var price = self.myQuote();
var pip = 1;
var lot1 = self.currentlotvalue;
var JPlot = lot1 * 100;
if (cur.indexOf("/USD") > -1) {
pip = lot1;
} else if (cur.indexOf("/JPY") > -1) {
pip = JPlot / price;
} else if (cur.indexOf("USD/") > -1) {
pip = lot1 / price;
} else {
var base = cur.split("/")[0];
var counter = cur.split("/")[1];
for (var i = 0; i < self.newPairs.length; i++) {
var base1 = self.newPairs[i].pair.split("/")[0];
var counter1 = self.newPairs[i].pair.split("/")[1];
var price1 = self.newPairs[i].price;
alert(price1);
if (base1 == "USD") {
if ((self.newPairs[i].pair) == ("USD/" + counter)) {
pip = lot1 / price1;
}
} else if (counter1 == "USD") {
if ((self.newPairs[i].pair) == (counter + "/USD")) {
pip = lot1 * price1;
}
}
}
}
//alert(pip? "$" + pip.toFixed(2): "None");
return pip ? "$" + pip.toFixed(2) : "None";
});
}
// Overall viewmodel for this screen, along with initial state
function ReservationsViewModel() {
var self = this;
self.curArray = ko.observableArray([]);
self.rates = ko.observableArray([]);
// Non-editable catalog data - would come from the server
self.rates = [ {
pair: "EUR/HUF",
price: 318.815,
leverage: "20:1*"
}, {
pair: "USD/HUF",
price: 265.13,
leverage: "20:1*"
}, {
pair: "XAG/USD",
price: 15.734,
leverage: "1:1*"
}, {
pair: "XAU/USD",
price: 1184.43,
leverage: "1:1*"
}];
self.newLot = [{
type: "Micro",
lotSize: 0.1
}, {
type: "Mini",
lotSize: 1
}, {
type: "Standard",
lotSize: 10
}];
self.newlots = ko.observableArray(self.newLot);
self.dropdownAValue = ko.observable(self.newlots);
var currentlotvalue = 0.1;
self.dropdownAValue.subscribe(function () {
if (self.dropdownAValue().type == "Micro") {
//alert("Micro");
currentlotvalue = 0.1;
} else if (self.dropdownAValue().type == "Mini") {
//alert("Mini");
currentlotvalue = 1;
} else if (self.dropdownAValue().type == "Standard") {
//alert("Standard");
currentlotvalue = 10;
}
var newItems = ko.utils.arrayMap(self.rates, function (item) {
return new PriceCalculation(item, item.price, self.rates, self.newLot[0], currentlotvalue)
});
self.curArray(newItems);
},this, "change");
}
ko.applyBindings(new ReservationsViewModel());
I was fiddling with Meteor and ran into some strange behaviour. My templates are rendered but after rendering immediately cleared again.
My template file; /client/game.html
<head>
<title>test</title>
</head>
<body>
<h1>test h1</h1>
{{> board}}
</body>
<template name="board">
<table class="gameboard">
{{#each model}}
{{>row}}
{{/each}}
</table>
</template>
<template name="row">
<tr>
{{#each this}}
{{>cell this}}
{{/each}}
</tr>
</template>
<template name="cell">
<td>
{{answer this}}
</td>
</template>
A client file; /client/client.js
Meteor.startup(function () {
Meteor.call('generateBoard');
});
Template.cell.answer = function (cell) {
console.log(cell.question.answer);
return cell.question.answer;
}
Template.board.model = function () {
//var game = Games.findOne(Session.get("selected"));
var game = Games.findOne(Session.get("selected"));
if(game) {
console.log(game);
return game.board;
}
}
and my model file /model.js
Games = new Meteor.Collection("games");
Meteor.methods({
generateBoard: function(){
var boardSize = 64;
var rowSize = cellSize = Math.sqrt(boardSize);
var board = [];
var row = [];
for(var rows = 0; rows < rowSize; rows++) {
for (var cells = 0; cells < cellSize; cells++) {
var cell = {
question: Meteor.call("generateAnswer"),
state: 0,
player: null
}
row.push(cell);
}
board.push(row);
row = [];
}
var gameId = Games.insert({
board: board
});
Session.set("selected", gameId);
},
generateAnswer: function(){
var lowerNumber = 2;
var higherNumber = 8;
var firstNumber = Math.round( Math.random() * (higherNumber - lowerNumber) ) + lowerNumber;
var secondNumber = Math.round(Math.random() * (higherNumber - lowerNumber) ) + lowerNumber;
return {
firstNumber: firstNumber,
secondNumber: secondNumber,
answer: firstNumber * secondNumber
};
}
});
Why do I get this behaviour? What did I do weird?
You should not use Session.set outside a Meteor.isClient-check