I have a web-app (GAS) where once the user has logged in (through Firebase/Google Auth), i am able catch his uID. Since i need this uID on server-sided functions later, once i catch it i run a function via google.script.run that will update an already declared global variable so that to store it on the other side. This variable is declared outside any function as empty like this var fbuserIDkey = ""; when the app is loaded . So this variable, once the user has logged in, should have been updated with the uID.
My problem is that later i need this variable in a function triggered by a click on a button, but the function server side seems to use an old version of the variable if that is possible, like it has not been updated.
Here are the bits of code involved:
declaring variable:
var fbuserIDkey = "";
passing the value when user is logged and updating server-side variable :
onAuthStateChanged{
...
const userIDkey = user.uid;
...
google.script.run.logUser(userIDkey);
} //console.log(userIDkey); = correct value
the function that updates global variable server-side:
function logUser(userIDkey){
fbuserIDkey = userIDkey;
Logger.log("ID is " + fbuserIDkey);//returns correct value on server-side too
}
So the variable has been updated.
But later, when the button is clicked on client-side and it triggers the function that should use the variable on server-side, it is still empty. Using Logger.log(fbuserIDkey) returns ""
It looks like the variable has been updated but the function that actually needs it has the old version of it (""). How is that possible? I precise that the click on the button always happens far after everything is loaded. I guess there might be some trick due to server/client communication but i don't understand where exactly and how to correct it.
EDIT
So as suggested i add more context, trying to paste as much code as possible.
fbuserIDkey is declared on the file (.gs) that contains the doGet() function if it adds any relevant detail.
var fbuserIDkey = "";
function doGet(e) {
...}
below is the function triggered by button that uses the variable:
function TransferPicks(picks){
Logger.log("ID is" + fbuserIDkey);//returns ""
...}
the eventlister is:
document.getElementById("savepicks").addEventListener("click", StartSaving);
StartSaving is a function that does several stuff (not related) and in the end triggers TransferPicks
Just answering the question since it is now solved if that can help anybody.
The trick as advised by the comments was indeed to get (again) the user.uID right at the moment I (re)need it, instead of trying to store it once and use it later. So, when document.getElementById("savepicks").addEventListener("click", StartSaving); happens, i get user info with onAuthStateChanged((user) => {if (user) {...}} and create one object with all the data I need from the client side. Then I pass it through google.script.run to the server side function and it works just fine!
Thanks to all who commented, I was just forcing it the wrong way.
Related
Basically what the title says. I'm making a game and most of it is in js. My concern is that the player stats are all just variables in its object and they are easy to change in the browser console(e.g. player.hitpoints = 1000;).
Is there any way to hide certain objects/variables from being editable in the browser console?
JavaScript is clients side scripting language, that means that it is interpreter on the client's computer and he can do or change whatever he wants. You can uglify and minimize your code for obfuscation the code, but it won't prevent the user from changing it.
I just google "obfuscation javascript code online" and I found this link with a good example of before and after the obfuscation process - here
The other answers have already explained obfuscation and the inherent limitations of client side JavaScript. They are correct and relevant, but don't directly address the question.
To make it impossible¹ to access a variable through the browser console, you need to make it into a local variable inside a function. For example, instead of:
var player = {hitpoints: 100};
// game logic here
You would do:
(function() {
var player = {hitpoints: 100};
// game logic here
})();
This creates an anonymous function, and then immediately calls it, the so-called IIFE. Now player is no longer global (i.e. a property on the window object), but exists only within this function.
¹ It can still be done through the debugger, but it's a lot harder than just copying and pasting some commands.
You can use JWT to make immutable data that don't change very often. For your case, I would recommend storing the state on the server.
You can minify/uglify your code to make it trickier for someone to modify it, but the most important part would be to validate everything server-side. If their hitpoints equal 10 one second and 10000 the next, obviously something would be fishy and the server could prevent itself from broadcasting that out to the other players -- essentially isolating the ne'er-do-well to their own PC.
Identifiers declared with let and const do have block scope. So if your variables are not declared with var then use a block statement.
Example:
code:{
//your code...
}
code: {
let hitpoint = 12;
let kill = function() {
hitpoint -= 12;
}
//function kill(){} is accessible from outside
//let kill = function(){} is not accessible from outside
console.log("From inside:", hitpoint)
}
try {
console.log("From outside:", hitpoint)
} catch (err) {
console.log("From outside:", "It gives an error. So you can't access it from the console or anywhere outside the code")
}
I tried to access the my C# method in my JavaScript, but this method is not accepting the local parameters and saying, the parameter does not exist in the current context.
var typeofServiceNumber = $("#serviceType").val();
#MyStaticClass.StringEncoding(Convert.ToString(typeofServiceNumber));
The above typeofServiceNumber is not recognized by the method
Razor code is executed server side before the HTML is returned in the response stream.
Javascript is executed client side within the resultant HTML.
Therefore you cannot pass a Javascript variable through to a Razor method, and you receive the message that typeOfServiceNumber is not recognized.
To be recognized, it would either need to be handled server side via data being passed to the View (ViewBag, Model etc), or it would need to be declared and assigned to within Razor tags on the page itself.
EDIT: to clarify the last point:
var typeofServiceNumber = $("#serviceType").val();
#MyStaticClass.StringEncoding(Convert.ToString(typeofServiceNumber))
The first line you have here is all happening in the browser of the end user.
The second line is all happening on the server. You see the error message because you are trying to pass "typeofServiceNumber" to your method, and the variable isn't even declared at that point.
Without knowing exactly what you're trying to achieve it's hard for me to give a precise answer as to how to solve your problem. But here are two possibilities:
1) You know what $("#serviceType").val() is going to be before you serve the web page to the end user because that value is being set server side.
Controller:
public ActionResult MysteryController()
{
...your code here to work out what the service type is...
ViewBag.serviceType = serviceType;
return View();
}
View:
...lots of lovely html and such...
<script>
#MyStaticClass.StringEncoding(Convert.ToString(ViewBag["serviceType"]));
</script>
I can't see what the output of #MyStaticClass.StringEncoding() is but I have to assume at this point that it is doing whatever it is supposed to do.
Although the logic is split between the controller and the view, all of this is happening server side.
The second half of my point "or it would need to be declared and assigned to within Razor tags on the page itself." refers to the fact that one variation of this method could involve manipulating data in the View itself by enclosing it in a Razor code block like this:
#{
var typeofServiceNumber = #MyStaticClass.StringEncoding(Convert.ToString(ViewBag["serviceType"]));
}
The alternative, which I did not really address originally is:
2) You don't know what the value of $("#serviceType").val() is going to be before the page is loaded because it is being set by the end user and your function needs to be used before the data is submitted to the server:
If that's the case then #MyStaticClass.StringEncoding(Convert.ToString(typeofServiceNumber)) is no good to you, you will have to replicate the function in JavaScript and include it in the webpage itself.
Sorry for the badly worded title, and I would also like to apologize in advance if my explanation is lackluster. My knowledge of JavaScript and Ajax stuff isn't really that great.
Anyway, so, what I am trying to do is display a list of items using PHP, and then when an item is clicked, a popup will be displayed basically asking if the users want to add the items to the DB (it's essentially importing from one DB to another). Part of the popup is a drop down list that contains possible parents for the imported items. (So, if you are importing a project called Vista, you might place it in the parent category 'OS').
In order to make the drop down, an ajax request must be made, and the back end PHP replies with a JSON object which contains all elements that need to be included in the drop down.
So, as a test to see if the AJAX connection works, I just arbitrarily place a button on the window like so:
<div align="center" onclick="test()">TEST BUTTON </div>
and have a JS function called test:
function test(){
var url = "index.php?module=getlist";
//Code to send post request with a callback to function test2();
}
and a function test2():
function test2(data){
if (data){
alert(data.Project[0].id);
}
else {
alert("ERROR");
}
}
Note: The PHP code returns a JSON object and one of the sub-object thingies is called Project which is an associate array with fields like id and name.
The above works. The alert box shows a number that corresponds to a project id.
But, we want to have a popup that contains the list! So, we get some html like this:
<td align="center" onclick="collection('Random_Name', 'Random_Description')">Project 1</td>
Note: I am passing the values for the item Name and Description to a JS function called collection.
function collection(name, description){
test();
//Stuff that creates the popup, creates a form in the popup, and populates the form with default values(name and description).
// Following Stuff is used to make the drop down.
var tempdata = new Array(new Array());
tempdata[0]['name'] = json.Project[0].name;
tempdata[0]['value'] = json.Project[0].id;
//This function creates the Select list, it requires a name, default value, and
//a multi-dimensional array like the one defined above.
var pacolist = createSelect("collection_list",'',tempdata)
//Append the elements together and add a save button.
}
To try and get this to work, I declared a global variable called json at the top of the page. I changed the alert(data.Project[0].id); in test2() to json = data;
But, it didn't work.
I get an Uncaught TypeError: Cannot read property 'Project' of undefined error when I click to open the popup.
I changed the test2() method to be like this instead:
function test2(data){
if(data){
return data
}
else{
//Code from the original test() function to send post request to PHP with
//a callback to test2.
}
and in the collection() function, I added this: var json = test2,(No global json) but that did not work either.
Sorry for the long winded question, but basically, I open a function, the function needs to call another function that sends a post request and the data received by the request needs to be used by the original function. How do I do this?
I think this is just a time issue. As in the request takes a while, and in the mean time, the original function has already moved on.
EDIT: Found a solution. I think it was a timing issue. In order to fix it. I made the page html call a function that stored the name and description as global variables. This function then made the post request with a callback to a different function. This different function then used the data (the JSON object) it received and passed it along with the global name and description to the collection() function mentioned earlier.
You have to parse the data before you use it.
//For IE6/IE7
var data = eval('(' + json + ')');
//For IE8+/Chrome/Firefox...
var data = JSON.parse(json);
I need to send data in a HTML page to a script file that is loaded in that page. The simplest way i can think of is to use a global variable which is defined in the page and accessed in the script file.
We all know global state is bad, so i started thinking about the options available for passing data from HTML page to script file without using global state. I cant find (or think of) any.
I am curious whether this is possible. Any ideas?
It really depends what you're doing. In general, I wouldn't advise this methodology, but it's something to consider depending on your circumstances. For the sake of this example, I'll assume you're using jQuery (if not, replace the document.ready with whatever you want to use for onDOMReadyStateChange monitoring).
In the HTML:
<script type='text/json-data' id='some_data_set'>
{ 'foo': 'bar', 'baz': 1 }
</script>
In the JavaScript:
$(function() {
var myData = JSON.parse($('script#some_data_set').html());
// YOUR CODE GOES HERE
});
Nope. All the javascript scope starts from a global level, therefore you must have at least one global reference to your data.
Let's say you wanted to store a list of products and events:
var myGlobalData = { "products":<products>, "events":<events> };
Where <products> and <events> are two different data blocks.
If you're paranoid on global objects, you can simply delete the reference point (thus it's contents) after you finished using it, as follows:
delete window.myGlobalData;
One option is to scope your data. For example, in JS file you can define an object like:
var processor = {
function setData(o) { // do stuff
}
};
Then in your HTML you know that the data is scoped to the processor. So you can do something like:
processor.setData({someData});
I have a database that stores events in it and a page with a calendar object on it. When rendering the days it looks through the months events and if any match the current day being rendered it creates a linkbutton to represent the event in the day on the calendar and adds it to that cell. I add some javascript to the linkbutton to change the window.location to a page to view event details passing EventID in the querystring ( I tried setting the postbackurl of the newly created linkbutton but it wasnt causing a postback... no luck). I need to set a Session variable ie. Session("EditMode") = "Edit" So the new page will know it is to get an existing event info rather than prepare to create a new event? Any SUGGESTIONS?
Your session vars are controlled by the server,
JS runs client side, and as such cannot modify the vars directly.
You need to make server requests using POST or GET and hidden
iframes, or XMLHTTPRequest() calls to send data from the JS to
the server, and then have your server side code handle the vars.
Add another query string variable that the page can use to trigger existing vs new.
Add another query string variable that the page can use to trigger existing vs new.
If you are using something like Struts2, you can have a hidden variable in your jsp
<s:hidden id="EditModeId" value="%{#session.EditMode}"/>
And within javascript simply access this variable
alert(document.getElementById('EditModeId').value);
You definitely need to add a variable to the target page. But I take it that you are doing a popup scenario, so you should be able to create a javascript function OpenWindow() and fire it off when the user clicks the link.
<script>
function OpenWindow(eventId, editMode)
{
var window = window.open("popup.aspx?eventId=" + eventId + "&editMode=" + editMode);
}
</script>
On the server side you need to build the call to the OpenWindow function. For example:
onclick="OpenWindow(eventId=" + row["eventId"].ToString() + "&editMode=" + editMode.ToString() + ");"
So in other words, prep everything on the serverside to set your javascript to post all variables to the new page. Hope this helps.
var page1 = document.getElementById("textbox").value;
sessionStorage.setItem("page1content", page1);
in other page use this value as like session variable
document.getElementById("textbox2").value=sessionStorage.getItem("page1content");