I'm building a basic game with NSEW navigation.
Each NSEW button changes the current location's number, 1,2,3,etc.
Each location has an object that's intended to be associated with it, named loc1,loc2,loc3,etc.
Each object has a description that needs to be displayed, loc1.desc, loc2.desc, etc.
My display function is working, as is my navigation, BUT...
I'm TRYING to pass the loc#.desc value corresponding to the correct current location into the function. (This is Javascript, btw). Currently, it looks like this:
function nextLoc(dir) {
var newLoc = nav[currentLoc][dir];
currentLoc=newLoc;
displayMessage(loc[currentLoc].desc);}
I want it to input the current location's number and pass that to the displayMessage function. I've tried it a ton of different ways, but it still does NOT print the description. If I hard code the number (loc2.desc) or just pass currentLoc, it works, returning the correct object description or the currentLoc number. I've also tried:
loc+[currentLoc]+.desc
Is there a way to do this? I've searched and tried all the different ways to find this but I can't find this specific issue and, at this point, I'm just lost! Any help is greatly appreciated!!
In answer to comments, here's the whole js file:
//Location prototype
function Location(id, desc){
this.id = id;
this.desc = desc;}
//Location objects
var loc2 = new Location(2, "Circus");
var loc1 = new Location (1, "Zoo");
var loc0 = new Location (0,"You entered the park here");
var currentLoc = 0;
var EAST = 0;
var WEST = 1;
var NORTH = 2;
var nav = [ // E,W,N,S
/*Current Location*/
/* 0 */ [2,1,4,-1],
/* 1 */ [0,-1,3,-1],
/* 2 */ [-1,0,5-1],
/* 3 */ [4,-1,-1,1],
/* 4 */ [5,3,-1,0],
/* 5 */ [-1,4,-1,2],
];
// Directional Button Event Handlers
function btnEast_click() {nextLoc(EAST);}
function btnWest_click() {nextLoc(WEST);}
function btnNorth_click() {nextLoc(NORTH);}
function nextLoc(dir) {
var newLoc = nav[currentLoc][dir];
currentLoc=newLoc;
displayMessage(loc[currentLoc].desc);}
// Utility Function(s)
function displayMessage(msg) {
var target = document.getElementById("taMain");
target.value = msg + "\n\n" + target.value;
}
You were quite close to being able to do named-lookups in a map object. Rather than creating a bunch of independent locations (which in a browser, end up as properties of the window object, so there was an avenue that I've chosen not to pursue that would've let you use them.
What I'm doing below is creating an object for the static locations. Another approach would be to use notation like this, which would actually result in the same behavior but might be easier to understand what's going on:
var locations = [];
locations['loc2'] = new Location(2, "Circus");
locations['loc1'] = new Location(1, "Zoo");
locations['loc0'] = new Location(0, "You entered the park here.");
Also workable would be removing the 'loc' prefix on your keys, then you could write things like this:
var locations = [];
locations.add = function(id, desc){ locations[id] = new Location(id, desc)}
locations.add(0, "You entered the park here.")
// and your navigation method looks like this then
function nextLoc(dir){
var newLoc = nav[currentLoc][dir];
currentLoc=newLoc;
displayMessage(locations[currentLoc].desc);
}
Another form which resembles what you've done so far
var locations = {
loc2 : new Location(2, "Circus"),
loc1 : new Location (1, "Zoo"),
loc0 : new Location (0,"You entered the park here")
};
function nextLoc(dir) {
var newLoc = nav[currentLoc][dir];
currentLoc="loc"+newLoc;
displayMessage(locations[currentLoc].desc);}
Related
So, three small parts:
1) a MaxMind geo IP lookup that gets us the country code via the IP address:
var onSuccess = function(x){
var ip = x.traits.ip_address;
document.getElementById('ip_address').value = ip;
var country_code = x.country.iso_code;
document.getElementById('ip_country_code').value = country_code;
…
};
2) an array of country references with tax percent decimals:
// Array of values for tax rates
var tax_rates= new Array();
tax_rates["noteu"]=0.0;
tax_rates["ES"]=21.0;
tax_rates["AU"]=20.5;
tax_rates["BE"]=21.7;
…
3) a TaxPrice function that takes one of those decimals to calculating tax and then total payable in a subscription form. Notice the XXXXX:
function TaxPrice()
{
var taxprice=0;
XXXXX
return taxprice;
}
The document.getElementById bit in 1) can obviously update a hidden field or some other HTML element.
I know what to do with XXXXX if it's a manual drop down the user has to select.
But how do I get the tax decimal out of the array and into the TaxPrice function based on the IP address country code? (i.e. within the javascript, not updating an HTML element).
Happy New Year to all.
UPDATE: Just to be clear, I don't need to know how to get it into a drop down, I can do that already and in this use case, the user should not be allowed to choose his own tax country, it should be set automatically based on the IP address. So the non-code wording would go something like:
taxprice EQUALS tax_rate.value ACCORDING TO ip_address_code
Are you looking for something like element properties?
Mydiv.tax=taxvalue;
Properties of Elements are an elegant way of communicating between different functions.
You can assign any value to any element.
You can retrieve the value from any function in JavaScript as long as the Basic element lives.
One way you can do it is to set a global selectedCountryCode variable inside your success callback, and reference tax_rates[selectedCountryCode] in your TaxPrice array (which should be an object, as nnnnnn pointed out)
(function () {
var selectedCountryCode = "";
var onSuccess = function(x) {
var ip = x.traits.ip_address;
document.getElementById('ip_address').value = ip;
selectedCountryCode = x.country.iso_code; // <-- Set selectedCountryCode for later use
document.getElementById('ip_country_code').value = selectedCountryCode; // <-- Set dropdown value
};
document.getElementById("ip_country_code").addEventListener("change", function() {
selectedCountryCode = this.value;
console.log(TaxPrice());
});
// Object of values for tax rates
var tax_rates = {};
tax_rates["noteu"] = 0.0;
tax_rates["ES"] = 21.0;
tax_rates["AU"] = 20.5;
tax_rates["BE"] = 21.7;
function TaxPrice() {
var taxprice = 0;
taxprice = tax_rates[selectedCountryCode];
return taxprice;
}
})();
Change Me: <select id="ip_country_code">
<option value="noteu">noteu</option>
<option value="ES">ES</option>
<option value="AU">AU</option>
<option value="BE">BE</option>
</select>
So, thanks for your suggestions. Not sure if I understand how this is working exactly, but after some poking around, it now is. Compared to the code in the original question, I had to:
1) Add a global variable at the top, above everything else, unrelated to the IP lookup code (i.e. there is now no reference to country_tax within the IP onSuccess variable):
var country_tax;
2) Replace XXXXX in the TaxPrice function with:
var country_tax = document.getElementById("ip_country_code").value;
var taxprice = taxes_from_database[country_tax];
So the full TaxPrice function ends up as:
function TaxPrice()
{
var taxprice = 0;
var country_tax = document.getElementById("ip_country_code").value;
var taxprice = tax_rates[country_tax];
return taxprice;
}
No need, it seems, for nested functions or closures or anything very complicated. It doesn't matter (to the code) if the tax_rates are set up as an array or an object, the outcome is the same, although I would like to understand why you recommend an object over an array in this case.
And—given TaxPrice gets the value from the form field and not from within the IP onSuccess function—I don't know why I need the global variable declaration at the top, if anyone wants to have a go at explaining that…
I currently have an app that creates an array of markers. But it is not useful, because I would like to see a group of markers and a custom property summed based on the distance between markers (depending on the zoom level).
I've said that maybe with MarkerClusterPlus I could accomplish something like this:
This even shows a custom icon, I don't need that, I only need the number over the cluster.
But I don't know where to start. Could someone place an example or a link?
You must define a custom property on the Marker object, so you can override the Calculator function in markercluster.js
MarkerClusterer.CALCULATOR = function (markers, numStyles) {
var index = 0;
var title = "";
var count = markers.length.toString();
var valueToSum=0;
for(var m=0;m<markers.length;m++){
//This is the custom property called MyValue
valueToSum+=Number(markers[m].MyValue);
}
var dv = val;
while (dv !== 0) {
dv = parseInt(dv / 10, 10); //you could define your own rules
index++;
}
index = Math.min(index, numStyles);
return {
text: valueToSum,
index: index,
title: title
};
};
I have a working script that upon form submit, specific rows move from one sheet to another. One of the fields I'm pushing is a url.
On the second sheet, the link is listed and it is hyperlinked, but it's really ugly and I really want to format it so that it shows "Edit" with a hyperlink. I've tried a number of ways, but my knowledge is limited so all I get are errors. I'm hoping someone can point me in the right direction.
Here is my code. I'm very new at this so the script is not at all sophisticated. Any help/suggestions would be appreciated!
function copyAdHoc(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sh = SpreadsheetApp.setActiveSheet(ss.getSheetByName("Form Responses 1"));
var data = sh.getRange(2, 1, sh.getLastRow() - 1, sh.getLastColumn()).getValues();
// Grab the Headers from master sheet
var headers = sh.getRange(1,1,1,sh.getLastColumn()).getValues();
var date = headers[0].indexOf('Effective Date');
var name = headers[0].indexOf('Employee Name');
var loc = headers[0].indexOf('Location');
var issue = headers[0].indexOf('Description/Question/Issue');
var add = headers[0].indexOf('Additional Information');
var change = headers[0].indexOf('Is this a Qualifying Life Event?');
var url = headers[0].indexOf('Form URL');
var category = headers[0].indexOf('Primary Category');
var status = headers[0].indexOf('Current Status');
var users = headers[0].indexOf('Users');
// Grab only the relevant columns
for(n = 0; n < data.length; ++n ) { // iterate in the array, row by row
if (data[n][change] !== "Yes" & data[n][category] !== "Employee Relations" & data[n][date] !== "") { // if condition is true copy the whole row to target
var arr = [];
arr.push(data[n][url]);
arr.push(data[n][users]);
arr.push(data[n][date]);
arr.push(data[n][loc]);
arr.push(data[n][name]);
arr.push(data[n][category]);
arr.push(data[n][issue] + ". " + data[n][add]);
arr.push(data[n][status]);
var sh2 = SpreadsheetApp.setActiveSheet(ss.getSheetByName("Ad Hoc")); //second sheet of your spreadsheet
sh2.getRange(sh2.getLastRow()+1,2,1,arr.length).setValues([arr]); // paste the selected values in the 2cond sheet in one batch write
}
}
}
It's a bit messy but the only way I know to achieve what you're trying to do would be to insert a column to the left of the hyperlink with the word Edit right justified and then remove the borders between the two.
From your description I am assuming you want the word "Edit" to be Hyperlinked. To do so, try this:
function getHyperlink(url)
{
return "=HYPERLINK(\""+url+"\","+"\"Edit\""+")";
}
function mainFunct()
{
//Do necessary steps
var tarLink = "https://www.google.com";
var tarRng = tarSheet.getRange(rowNum, colNum).setValue(getHyperlink(tarLink));
//perform other steps
}
EDIT:
Forgot to mention, since you're pushing your values to the array... you can do it in a similar way by either just storing the hyperlink in a variable or directly pushing it to the array like all the other values. Or if you're dealing with a hyperlink that has a static and dynamic part, For example: https://stackoverflow.com/questions/post_id, where post_id keeps changing but most of the URL is static, you can easily handle it by just passing the post_id to the getHyperlink function and getting the required Hyperlink in return. Hope this helps.
What I am trying to do is rewrite content on the page depending on which object I have selected. I have some objects like so:
function floorPlan(name,rev,sqft,bedrm,bthrm) {
this.name = name;
this.rev = rev;
this.sqft = sqft;
this.bedrm = bedrm;
this.bthrm = bthrm;
}
// 1BR Plans
var a1 = new floorPlan('A1',false,557,1,1);
var a2 = new floorPlan('A2',false,652,1,1);
var a3 = new floorPlan('A3',false,654,1,1);
var a4 = new floorPlan('A4',false,705,1,1);
var a5 = new floorPlan('A5',false,788,1,1);
// The Selected plan
var currentPlan = floorPlan.a1;
I am having the user control this via a .click() function in a menu:
$('.sideNav li').click(function() {
// Define the currentPlan
var current = $(this).attr('id');
var currentPlan = floorPlan.current;
});
The problem is that currentPlan keeps coming back as undefined and I have no idea why. Should I be defining currentPlan differently? I can't seem to find any resources to help me find the answer.
UPDATED:
I switched out a few parts per your suggestions:
// The Selected plan
var currentPlan = a1;
and....
// Define the currentPlan
var current = $(this).attr('id');
currentPlan = current;
However, everything is still returning undefined in the click function (not initially though).
First of all $('this') should be $(this)
Secondly you're trying to use a read ID from your LI as a variable name. That doesn't work. If you store your plans in an array you can use the ID to search in that array:
var plans=Array();
plans["a1"]=new floorPlan('A1',false,557,1,1);
plans["a2"]=new floorPlan('A2',false,652,1,1);
Then your jQuery code should be altered to this:
$('.sideNav li').click(function() {
// Define the currentPlan
var current = $(this).attr('id');
var currentPlan = plans[current];
alert(currentPlan);
});
I created a JSFiddle for this. Is this what you were looking for?
Use as floorPlan.currentPlan = a1;
instead of var currentPlan = floorPlan.a1;
Please create a plunker and will correct if any issue.
I spot two errors.
When you write var inside a function, that variable is only accessible with that function. Right now you are creating a new variable in your anonymous function that is "hiding" the global variable with the same name.
So, first remove the var keyword from the assignment in the anonymous function (the one you call on "click").
Secondly I think you mean to assign floorPlan[current].
The final line should read:
currentPlan = floorPlan[current];
I am experementing with javascript objects for the first time and need some help. I want to store generated user input in objects, push them into an array and later on reuse them. So far I have come to this:
function changeColors() {
//get the numbers from the html
var rd = parseInt(document.getElementById("red").value);
var gr = parseInt(document.getElementById("green").value);
var bl = parseInt(document.getElementById("blue").value);
var op = parseFloat(document.getElementById("opacity").value);
//convert the decimal into hexadecimal
var rdhex = (rd < 16) ? "0" + rd.toString(16) : rd.toString(16);
var grhex = (gr < 16) ? "0" + gr.toString(16) : gr.toString(16);
var blhex = (bl < 16) ? "0" + bl.toString(16) : bl.toString(16);
//concatenate all hex to generate a color
var hexcode = "#" + rdhex + grhex + blhex;
//view the change in the browser
document.getElementById("div").style.backgroundColor = hexcode;
document.getElementById("colordisplay").innerHTML = hexcode;
//change opacity
document.getElementById("div").style.opacity = op;
Here I get all the input that I need to store and in the next function I am trying to store it in an object and array:
function Save(){
var colors = {};
var nextColor = []
colors.nextColor = nextColor;
console.log(colors);
var rgb = document.getElementById("colordisplay").innerHTML;
var opacity = document.getElementById("div").style.opacity;
var name = document.getElementById("name").value;
var nextColor = {
"name": name,
"rgb": rgb,
"opacity": opacity
}
colors.nextColor.push(nextColor);
console.log(colors);
}
My question is: is how wrong is that and how it can be corrected?
Thank you!
I am unsure what your question exactly is, but looking at your code for Save I assume you're inquiring how to best store data in the context of an application. Looking at the Save-method body:
var colors = {};
var nextColor = [];
These variables are only available in the scope of the Save function. As such the "colors"-Object will only ever contain one single color Object, i.e. the "nextColor" Object created in the Save function. On top of this, the "colors"-Object is not accessible outside of the Save function, rendering it... well, useless.
Ideally you hold the contents of the "colors"-Object in a global variable (or reference it in another Object available to your application, i.e. a "Model") and fill the colors Object with the return of the Save-method, i.e.:
function Save() {
var rgb = document.getElementById("colordisplay").innerHTML;
var opacity = document.getElementById("div").style.opacity;
var name = document.getElementById("name").value;
var nextColor = {
"name": name,
"rgb": rgb,
"opacity": opacity
};
return nextColor;
}
// assume an event handler invoked after a form is submitted, this
// creates a nextColor and pushes it into the existing colors Object
function someEventHandler( e ) {
colors.nextColor.push( Save() );
}
This implies that the Save-methods sole function is to gather the values entered in the HTML document, and translate it into a new value Object. The Save-method now has no business knowing about any remaining data belonging to your application. (i.e. the creation of the "colors" Object and its "nextColor"-Array should be left to another function, ideally executed when your application launches).
I guess what I'm saying is you're on the right track, but you can get a lot of mileage by investing some time into creating separate functions to handle your data layer. After all, that's all JSON is, data.
If for instance you want to enter validation in your Save()-method (let's say to make sure that the "name" Input element actually contains a valid String), you just modify it there in that one function. If you additionally wish to make sure that the same color isn't added to the "nextColor"-Array twice, you can make another function that checks whether a color with the same values is already present in the data Object and either removes it or prevents pushing the duplicate value into the Array. This is logic that shouldn't be in the Save()-method, as such you can structure your program to organize your data neatly.
I hope this is the answer you were looking for.
Try this:
var colors = {
"nextColor": []
};
function Save() {
colors.nextColor.push({
"name": document.getElementById("name").value,
"rgb": document.getElementById("colordisplay").innerHTML,
"opacity": document.getElementById("div").style.opacity
});
console.log(colors);
}
Notice that the colors variable should be outside the scope of the function in order to retain the variable beyond individual runs of the Save() function.
I've also simplified the code quite a bit.