Why chrome.sync.set updates a value only once - google-chrome

I want the extension to count how many times the browser was opened.
Below is the piece of code which should do the job, but does not work as
expected. Why?
chrome.runtime.onStartup.addListener(function() {
chrome.storage.sync.get({'number' : 1}, function(result) {
// prints 1 the first time, then keeps printing 2 all the time, why?
console.log("Old number is " + result.number);
// Trying to increment 'number' value by 1
chrome.storage.sync.set({'number' : (result.number + 1)},
function() {})
});
});

I'm not sure you should be using "1" in get...
chrome.runtime.onStartup.addListener(function() {
chrome.storage.sync.get(['number'], function(result) {
let number;
if ('number' in result)
number = result.number;
else
number = 1;
// prints 1 the first time, then keeps printing 2 all the time, why?
console.log("Old number is " + number);
number += 1;
// Trying to increment 'number' value by 1
chrome.storage.sync.set({number: number},
function() {console.log("value as set to " + number);});
});
});
This code should probably be on a "background script", and the only console that will show anything is the console you open from "tools, more tools, extensions" and click the view link in your listed extension.
If you're having problems with syncing as mentioned in comments, you can try using chrome.storage.local.get / set.
I think that for what you're doing, this is better.

Related

Using DataTables how to display a running total of an amount entered in each row?

http://live.datatables.net/dalogaci/1/edit
I have an amount of money to be dispersed and am using DataTables to display a list of people and allow entry of an amount next to each person (their share of the disbursement). I want to provide a running total of the amount entered into the table so I can warn when the total to be dispersed has been reached or passed.
Kind regards,
Glyn
You can use the following approach.
In my case, I display the running total in a <div>, rather than an input box, as the value is only for display purposes:
<div id="showsum">Grand Total: $0.00</div>
The end result:
The script for this - which I have tried to explain with comments in the code:
<script type="text/javascript">
// define the table variable here so the doSum()
// function will have access to it, when needed:
var table;
// reads each value from the final column in the table, checks
// if the value is a number (as opposed to blank), and then
// keeps a running total. Ensure we round fractions of pennies
// as needed.
//
// When handling money, use a big number library - see this:
// https://stackoverflow.com/questions/1458633/how-to-deal-with-floating-point-number-precision-in-javascript
//
function doSum() {
//var foop = table.columns(5).nodes().to$();
var sum = 0.0;
// this gets each node (cell) in the final column:
table.columns(5).nodes().to$()[0].forEach(function (item) {
// see if the display value is a number (i.e. not blank):
var amt = parseFloat($('input', item ).val());
if (!isNaN(amt)) {
sum += amt;
}
});
// round and display to 2 decimal places:
sum = (Math.round((sum + Number.EPSILON) * 100) / 100).toFixed(2);
$('#showsum').text("Grand Total: $" + sum);
}
$(document).ready(function() {
table = $('#example').DataTable( {
"columnDefs": [ {
"targets": 5,
"data": function ( row, type, val, meta ) {
// note the use of onchange="doSum()" in the following:
return '<input type="number" min="0" max="99999.99" step=".01" placeholder="0.00" onchange="doSum()">';
}
} ]
} );
} );
</script>
For a change to be added to the grand total, you have to hit "enter", or click outside of the input field, if you type the value in manually.
Because you are dealing with money, the code should really be using a "big number" format to eliminate the risk of inaccuracies in fractions of pennies (due to limitations in floating point arithmetic). For example see here.
Final note: I see this question was down-voted. I think that may have been because you only link to your demo code, instead of showing the relevant parts in the question itself. The link to the demo is useful - but showing code in the question itself is generally a "must-do", I think.

Bubble chart and rowchart are not sync, dc.js

There is a simple bubble chart (dimension by level1, level2) and row chart(dimension by level_1)
see
https://codepen.io/shakraz/pen/dyYXxJy
var houseDim = ndx.dimension(d=>[d.district, d.name, d.price, d.flat_rate, d.building_rate]);
var districtDim = ndx.dimension(d=>[d.district])
When i click on row chart i expect to see only filtered bubbles, right? But it doesn't work.
But it works vice versa, clicking on bubble filters rowchart, why is that?
For sure it somehow related with reduce function.
Thank you for any advance.
It's a better practice to keep any measures in the value part of the crossfilter group, and leave only the index in the key.
Crossfilter will bin the groups according to the group and dimension key functions. Your instinct was correct that you should be able to use d.name because you want a bubble per row of your data, and d.name is a unique key.
var houseDim = ndx.dimension(d=>d.name);
Here is one simple way to copy each row into a group value:
var houseGroup=houseDim.group().reduce(
(p, d) => ({...p, ...d, count: (d.count || 0) + 1}), // add
(p, d) => ({...p, count: p.count - 1}), // remove
() => {} // init
);
When adding a row, it will copy the data from the row, adding a field called count. Since the keys are unique, the count will be either 1 or 0, depending whether the row is filtered in or out.
Now we can use descriptive field names instead of indexing arrays in the code:
.keyAccessor(function (p) {
return p.value.flat_rate;
})
.valueAccessor(function (p) {
return p.value.building_rate;
})
// ...
.title(function (p) {
return p.key + "\n"
+ "Индекс квартиры: " + p.value.flat_rate + "\n"
+ "Индекс дома: " + p.value.building_rate + " \n"
+ "Район: " + p.value.district + "\n"
+ "Цена: " + p.value.price
})
We also need to visually encode being excluded, by using d.value.count in some of the accessors. I like to send both radius and opacity to zero, but leaving the radius and only using opacity has a calm effect too.
.radiusValueAccessor(function (p) {
console.log('radius', p)
return p.value.count * priceScale(p.value.price);
})
// .colors(colorScale)
// .colorAccessor(function(p) {return p.value.district})
.colorCalculator(p => p.value.count ? colorScale(p.value.district) : 'rgba(0,0,0,0)')
The bubble chart doesn't expose opacity in its public api, but this colorCalculator trick sends opacity to zero when count is 0, and invokes the ordinary colorScale on the value otherwise.
I also had to point to correct dc.css URL in order to get selection behavior to work.
<link rel="stylesheet" href="https://unpkg.com/dc/dist/style/dc.css">
Working fork of your codepen

Problem displaying error to the user from AJAX

Am using AJAX code whereby I handle errors form the backend code.. All is working well except that I want to alert the errors individually to the user in a numbered list
Expected Output
1. Please insert a valid phone number
2. Please insert your email
3. Please insert a valid passport number
AJAX code handling errors
error: function(data) {
//Unblock the spinner
$.unblockUI();
var errors = '';
for(datos in data.responseJSON){
errors += data.responseJSON[datos] + '<br>';
}
//Alert each error individually
alert(errors);
}
I would recommended that you should be using a for loop instead of for in. See why here
error: function(data) {
//Unblock the spinner
$.unblockUI();
var errors = '';
for(var i = 0; i < data.responseJSON.length; i++){
// Remove the "(i+1) + '. ' + " if your json response already contains that part.
errors += (i+1) + '. ' + data.responseJSON[i] + '\n'; // <-- Notice how the br tag is changed to a new line
}
alert(errors)
}
I also changed the <br> tag to a \n as alerts don't support html tags.
It is not clear to me from the question, whether you want a
multiline alert message or
multiple alert dialogs as the
output,
but in case 1) is true, you should use newline ("\n") instead of br tag - see New line in JavaScript alert box and the code could look like:
var i = 1,
errors = '';
for(datos in data.responseJSON){
errors += i + '. ' + data.responseJSON[datos] + '\n';
i++;
}
//Alert each error individually
alert(errors);
If 2) is what you need, you should call alert() for each error message

how to update html page only when database changes

JS, which returns the first name:
$.ajax({
url: 'exm1.php',
type: 'get',
dataType: 'json',
success: function(data){
if( t<data.length){
for(var i=0;i<data.length;i++){
$("#output").html(data[i].fn);
}
}
},
error: function() {
// TODO: do error handling here
console.log('An error has occurred while fetching lat/lon.');
}
});
There are two things which I would like to sort out first:
It always overwrites the output div tag. I don't know how I can prevent this
setInterval should only run when there is a change in the database, or maybe when data.length changes, is there any way I could store the previous value of data.length and then compare with new data.length
If #output contains the first name, then you can target and save it into a variable on load
Example:
var firstname = $('#output').html();
And then all you have to do is compare the AJAX output with the variable.
Example:
if ( firstname != data )
$('#output').html(firstname);
To prevent overwriting your div tag, use the following.
$("#output").append(data[i].fn);
I don't understand what you mean by setinterval, please clarify in your code.
You can keep the html inside of the div by using this (vanilla javascript)
var inTheOutPutDiv = document.getElementById("output");
inputTheOutPutDiv.html = inputTheOutPutDiv.html + data; // whatever
// or use inputTheOutPutDiv.html+= data;
but sense you are using Jquery you can use append
$("#output").append(data);
You can instantiate a variable outside of your function that holds the length of your database query (scope). Or you can return a database value that says if the info has been updated (a value of 1 if changed, a value of 0 if the same). Then use a conditional statement to perform an action on the response. You have many options.
Unfortunately you can't call setInterval only when the data changes, but you can run something at a set interval and only update the #output html if the result is different.
The reason #output is getting overwritten is because calling $.html("...") will replace the existing html with the argument. I'd recommend simply putting what you want to remain static on the page in a different div.
<div id='oldOutput'>
Static Text Here: firstName?
<span id='output'></span>
</div>
Now your ajax return will overwrite the element and your static text will remain. However, you still have an issue in that every iteration of your loop will remove the string from before. If you want each loop to render cleanly, i'd recommend something along these lines:
success: function(data){
if( t<data.length){
// if you want to flush the #output each time
$("#output").html("");
for(var i=0;i<data.length;i++){
$("#output").append(data[i].fn);
// or you could put each entry in a div for later use
// $("#output").append("<div id='div_"+ i +"'>" + data[i].fn + "</div>");
}
}
}
In this case (you're flushing the div each time) then if the data is the same you shouldn't notice it update. If you don't flush the div then the data will keep appending on to the end.
If this is what you want, but only when there is new data, then you can count the number of child divs in the #output span - if you wrap each item from the output in a div as I have above, you should be able to compare this to data.length:
success: function(data){
if (t<data.length){
// gets direction descendants of #output that are divs,
// and counts the length of the array returned
var numItems = $("#output > div").length;
if(numItems != data.length){
loop goes here..
}
}
This will sort of work, it will only update when the number of items returned is different to the number of items you already have. However, if your script is returning a set of data and you need to filter it to see what's old and what's new, it's slightly different. You'll need to do include some sort of identifier (other than the data itself) to embed into the to check if it exists later.
if ( $("[data-id=" + data[i].identifier +"]").length > 0 ) {
// already exists, do nothing
} else {
$("#output").append("<div data-id='"+ data[i].identifier +"' etc...
}

dc.js crossfilter without reduce

Is crossfilter manipulating my data?
Background
I have performed all the processing I need server side and just want to graph exactly what comes down the json pipe. So far I've get the graph working exactly how I want it to except for it seems my data is being manipulated.
Here's my crossfilter code:
ndx = crossfilter(rData);
runDimension = ndx.dimension(function (d) { return [+d.series, +d.norm_1]; });
runGroup = runDimension.group();
runGroup.reduceSum(function (d) { return d.value;});
Note: norm_1 is unique
Issues
Basically I'm noticing two issues:
I know for a fact that all my data will be between -1 and 1 (I've run several checks to test this), BUT when graphing it I see it dips down to -1.4 in some places.
My server sends exactly 1000 rows of data, but by breakpointing some of the dc.js code I can see it's only graphing 752 rows.
More Evidence
On my chart I've set the valueAccessor and added some checks to test the values going out of bounds, and I can see very clearly it goes out:
.valueAccessor(function (d) {
if (d.value > 1 || d.value < -1) {
console.log(d);
}
return d.value;
})
The data from the server requires a small amount formatting before going into crossfilter (it comes down as a table and needs to be split into series objects). I used this as an opportunity to test whether the data goes out of bounds, and I can see clearly it stays within bounds:
for (var i = 0; i < $scope.remoteData.rows.length; i++) {
for (var j = 0; j < $scope.remoteData.labels.length; j++) {
var label = $scope.remoteData.labels[j];
var value = $scope.remoteData.rows[i][label];
if (value > 1 || value < -1) {
console.log({
label: label,
i: i,
series: j,
norm_1: $scope.remoteData.rows[i].norm_1,
value: value,
});
}
rData.push({
series: j,
norm_1: $scope.remoteData.rows[i].norm_1,
value: value
})
}
}
Discussion
I suspect my problems have something to do with:
runGroup.reduceSum(function (d) { return d.value;});
Is this function adding together certain data points?
Sounds like you have some rows for which [+d.series, +d.norm_1] is not unique. And yes any rows with the same key will be added with reduceSum.
I'd suggest making your dimension key be something that's really unique.
If you don't have a unique key, with a little more work you could use the array indices themselves as the dimension key. It will mean you have to use both key and value accessors everywhere to look back in the original array.
Something like:
ndx = crossfilter(d3.range(0, rData.length));
runDimension = ndx.dimension(function(d) { return d; })
runGroup = runDimension.group().reduceSum(function(d) {
return rData[d].value;
})
chart.keyAccessor(function(kv) { return rData[kv.key].x; })
.valueAccessor(function(kv) { return rData[kv.key].y; })