In my app for google spreadsheet I save some params in localStorage in one function. And in another function I need to retrieve them. Of course, I can create modeless dialog or sidebar, when will be my html code and js, but this second function only refresh current sheet, so I don't need UI. Also I know, that server side doesn't have access to localStorage.
Here is my abstract code:
server.gs:
function menuItemClicked()
{
// when we click on item in addon menu, this called
// and load 'client.html'
}
function refreshCurrentSheet(params)
{
// called by 'client.html'
// do something else with params...
}
client.html:
<script type="text/javascript">
google.script.run.refreshCurrentSheet( localStorage.getItem('var') );
</script>
I didn't find answer in API, how to do that(
Question: how can I load html and execute js without visible UI ?
P.S. Saving these params on server-side in cache is not a solution, because I often use and change them in client
You can use either Properties Service or Cache Service. Both provide localStorage functionality allowing you to store key value pairs (string type only). If you'd like to persist data between function calls, Cache is probably the best option
More on Cache Service
https://developers.google.com/apps-script/reference/cache/
More on Properties Service
https://developers.google.com/apps-script/reference/properties/
Related
Built a website on Google App Script (for ref its on michelmoalem.com).
On page load I populate several vars with verious text blobs read from docs stored on google drive (CV, Biography etc) I use a pair of functions for each blob - on the JS script that - the first one (in this example loadEditor) runs the function getDocContent from the main code page (server side script) and on success feeds the resulting blob to the second function (loadCvData) that populates the var (cvEditing) with the aquired text.
function loadEditor(fetchResults){
google.script.run
.withSuccessHandler(loadCvData)
.getDocContent('16rvULQudFCcdJOb32Qk7qqfOfWmTxJ7MPuQ_fZJhaf4');
}
function (fetchResults2){
cvEditing=fetchResults2;
}
what I was wondering is how to populate the var within the first function eliminating the need for this 2 step solution...?
Perhaps:
function loadEditor(fetchResults){
google.script.run
.withSuccessHandler(function(data){loadCvData(data);let cvEditing=fetchResults;})
.getDocContent('16rvULQudFCcdJOb32Qk7qqfOfWmTxJ7MPuQ_fZJhaf4');
}
Explanation:
You need the success handler in order to handle data coming from server-side via google.script.run and use it client-side, that's how Apps Script works. At most you can use an anonymous function in the success handler, instead of calling another function, but that's it.
I have this network visualized using d3 and angular. Here is the link to the visualization.
I wanted to save the last state of the network so that even if I refresh the page it will show the last state. But don't know how to do that.
I read that it can be done using sessionStorage or localStorage but I can't seem to figure it out for my visualization.
I tried this by setting my JSON data to the sessionStorage and then getting it:
if (sessionStorage) {
sessionStorage.setItem("myKey", myJSON.toString());
}
if (sessionStorage) {
sessionStorage.getItem("myKey"); // {"myKey": "some value"}
}
and I also tried it like this:
localStorage.setItem("networkGraph", networkGraph);
var networkGraph = localStorage.getItem("networkGraph");
but it's not working. Is this the right way to do it?
Any help will be highly appreciated!
Are you sure that you need sessionStorage and not localStorage? In the case of sessionStorage saved data will be deleted when a browser tab with your app becomes closed.
You can write localStorage.setItem('inputLayerHeight', vm.inputLayerHeight); in your onChange handler to remember inputLayerHeight and Number.parseInt(localStorage.getItem('inputLayerHeight')) || 15 to restore the inputLayerHeight at value property of vm.inputLayerHeightSlider object. The same approach can be used for the other values to keep.
Your attempt is almost right. The only thing you need to change is the usage of localStorage. Simply add window or $window (more 'angulary' way to access window variable) variable like so:
$window.localStorage.setItem("networkGraph", JSON.stringify(networkGraph));
Also, I recommend using angular-storage if you're looking for an easy way to work with local storage. It makes things less painful :)
I think the problem might be related to the way you are storing data on your local storage. You are saving data as a string however I think that d3 doesn't recognize strings as valid data options. So instead you should do something like this:
if (sessionStorage) {
// Parse the data to a JavaScript Object
const data = JSON.parse(sessionStorage.getItem("myKey"));
} else {
// Fetch data...
// Set sessionStorage or localStorage
sessionStorage.setItem("myKey", myJSON.toString());
}
You can rearrange the logic as it might suit you but the idea is that in the end you should use JSON.parse() when getting the data from storage.
I am trying to find out what the safest way to store data for use when the user clicks on a button.
I know that you can store data in attributes(either the value attribute or a data- attribute) of the button tag like so:
<button type="button" value="1" data-value="1">Click me!</button>
But the problem with this is that the user(probably really only advanced users) can manipulate the value with firebug or some other app and THEN click the button and send over different data. I fully understand that I need to check the input before I try to do anything with the sent data.
I also found out that I could use jQuery's .data() to attach data to dom elements, which seems a bit more useful. I'm not exactly sure how the data is stored, but I assume its harder to manipulate.
What got me really interested in this question was when I was looking through Soundcloud's code in firebug, I saw that none of the "like" buttons had data attached to the buttons. I tried deleting/manipulating elements/data and the buttons still worked. So it got me thinking that they are probably using a similar process to what jquerys data() is doing.
I just want to know if there is a safer way to store data or a way so that the user can't manipulate the data before clicking the button.
Consider this function:
function setupPrivateData(element) {
var private = 1;
element.setPrivate = function ( d ) { private = d; }
element.getPrivate = function ( ) { return private; }
}
When called with some DOM element it will add two methods to it: .setPrivate(val) and .getPrivate().
These are the only methods that will allow you to access and modify that private variable associated with the element.
The user can always manipulate data. Nothing stops an advanced user to access object properties or call a jquery.data() on their own.
Something you could do in vanilla js would be:
var div = document.getElementById("test");
div.something = "hidden value";
div.addEventListener("click", function() {
alert(this.something);
});
<div id="test">click me</div>
The best way would to be a serverside verification if the sent data is valid or not.
Besides that, you could try to wrap your code in an anonymous function to deny the user access to the object:
(function() {
var data = {};
data.something = "test";
})()
But even that fails as soon as the user manipulates your files and adds for instance a debugger statement.
You can obfuscate your javascript but the only validation has to be done on your server. For example, I tried to get the weather from theweathernetwork. They have hidden their API call using multiple files and callbacks. In my opinion, it's just more challenging (funnier) if you want to reverse-engineer their site.
Javascript can't be secure. Never trust user input
If you are logging button clicks, the safest way to keep track is to save and validate on the server side.
For example, when you click a like button on Soundcloud, it makes an HTTP request to Soundcloud's server, records that you clicked the button, and marks it as a favorite. This way, if the same user clicks the button anytime in the future, it can check before incrementing the number of favorites.
The number displayed in the button is also pulled in from the database when the view is rendered.
This is a huge topic, and you have a lot to learn, far too much for a comment here. Anything "stored" in an attribute in the HTML source is absolutely not secure, it can be changed very very easily.
The most common way of dealing with this would be to use a cookie, but even with some effort these can be manipulated.
If security is important, find some way of identifying your users (possibly by IP, but even that isn't fool proof!) and keep the data on your server, linked to a user ID which can be retrieved after the button is clicked.
I have a file called index.php. With script tags, it references index.js.
I also have a file called payment.php. With script tags, it references payment.js.
I need to set a variable called seatSelected in index.js and then use it in payment.js. However, I do not want to reference index.js in payment.php.
I have tried to make a file called globals.js, reference it in index.php before index.js containing the following:
var selectedSeat;
function setSelectedSeat(seat){
selectedSeat = seat;
}
function getSelectedSeat(){
return selectedSeat;
}
And setting the value in index.js with:
setSelectedSeat("test");
Receiving it in payment.js with (referencing globals.ks in payment.php above payment.js):
alert(getSelectedSeat());
But it alerts 'undefined'. Am I doing something wrong? How can I reference this variable without referencing the file it is changed in?
You cannot access variables created from another page.
You could use localStorage with cookies as fallback.
function setSelectedSeat(seat){
if(localStorage) {
localStorage['selectedSeat'] = JSON.stringify(seat);
}
else {
//add code to store seat in cookie
}
}
function getSelectedSeat(){
if(localStorage) {
return JSON.parse(localStorage['selectedSeat']);
}
else {
//add code to retrive seat in cookie
}
}
You are trying to persist the state of variables while transitioning from one page to another and your application seems to have data that would require session expiry, I suggest you use sessionstorage. With help of polyfills you can give sessionstorage support till IE6 browser.
Benefit of using SessionStorage over LocalStorage
Session Storage persists the data only for a particular tab/window and the data is lost when the tab/window is closed.
As the data gets expired automatically you don't need to worry about session expiring.
You can expire your session at your will as well.
The data persists on page refreshes.
But Remember with sessionstorage you can only store strings key-value pattern. And you need to use JSON.stringify and JSON.parse method to store your complex objects in browser memory.
Here you can find a list of polyfills that you can use to provide the support of sessionstorage in non supporting browsers : https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-Browser-Polyfills#web-storage-localstorage-and-sessionstorage
Also you can read the following article to understand sessionstorage and localstorage in a better way: http://diveintohtml5.info/storage.html
I was hoping to save all open MS Access documents via a JScript run from the Windows Script Host.
So far I was able to obtain the MS Access object by calling:
var objAccess = GetObject('', "Access.Application");
But now I'm stumped. If it was MS Word, I'd enumerate all open documents in the .Documents property and call Documents.Item(n).SaveAs() method on each of them.
But how do you save-as all open documents in MS Access?
After you have your object variable set to an Access application instance with GetObject, use its Quit method with the acQuitSaveAll option (value = 1). Not sure about JScript; in VBScript, I can do it like this.
Dim objAccess
Set objAccess = GetObject(,"Access.Application")
WScript.Echo objAccess.CurrentDb.Name
objAccess.Quit(1) ' acQuitSaveAll
Set objAccess = Nothing
Note, when I used GetObject as in your example, objAccess was a new Access application instance rather than a reference to the instance which was running previously. So, with the GetObject line like this ...
Set objAccess = GetObject('', "Access.Application")
... the WScript.Echo line threw an error with CurrentDb.Name (because there was not a database open in that Access application instance.
This approach will save any changes to database objects (tables, forms, reports, etc.) which were in design mode but not saved. However if a user has any unsaved changes to data in a form, those changes will be discarded despite the acQuitSaveAll option. It seems that option only applies to objects, not data.
Edit: If that approach is not satisfactory, you can do something more sophisticated with VBA in your Access applications, as #Remou mentioned in his comment. An example is KickEmOff from Arvin Meyer. He also offers a sample database which demonstrates that code in action.
Edit2: Remou's comment got me thinking acQuitSaveNone (value = 2) should be safer than acQuitSaveAll ... the unsaved object changes would be discarded, but at least you would be less likely to save an object in a non-functional state.