I have defined a variable in what I think is global scope. I want to modify the same variable inside a function that lives in a class, then use it later to export as json data.
The function is called by the xataface api, so I'm not sure I can mess with the function signature to do something like passing by reference. I've thought I might access the instance of this action class in the javascript embedded php, but I don't know how to ask the api for it, nor am I confident of its lifetime. It seems like a global variable may be the way to go. In any case, I want to know:
Why is not the global instance of $dataset1 the one being modified inside the function?
Why doesn't the call to array_push put anything on either array?
<?php
//non-dynamic data delcared in global scope. This is picked up later
//in a php block embedded into javascript
$dataset1 = array(array("label"=>"c120","data"=>"1"),
array("label"=>"c150","data"=>"10"),
array("label"=>"camp","data"=>"7"));
class actions_time_in_type
{
function handle(&$params)
{
$this->app =& Dataface_Application::getInstance();
//The Query
$result = mysql_query("SELECT typeDes, total
FROM myTable", $this->app->db());
//reserch leads me to believe that this *should* make all subsequent
//references to $dataset1 use the global instance
global $dataset1;
//experimenting with appending more non-dynamic data
//for some reason, this syntax does not seem to touch $dataset1
array_push($dataset1, array("label"=>"dv20","data"=>"1"));
//This syntax is working, but $dataset1 is not the same as the global
//$dataset1. Prepending "global" here seems to crash the script
$dataset1[] = array("label"=>"pa18","data"=>"5");
while($row = mysql_fetch_assoc($result))
{
//append data to the array, again, this is not hitting
//the global instance of $dataset1
$dataset1[] = array("label"=>$row['typedes'],"data"=>$row['total']);
}
mysql_free_result($result); //Frees the result after finished using it
//diagnostic dump to see what we've got
//This shows that we've constructed the dynamic data set, but it
//seems to be scoped only to this function and does not make it into
//javascript.
var_dump($dataset1);
}
}
?>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js" ></script>
<script type="text/javascript">
$(function () {
//This is getting only what was done original init of $dataset1, nothing that
//happened in the function made a difference
var dataset1 = <?php echo json_encode($dataset1); ?>;
});
</script>
It appears this is indeed a problem with execution order. Since the manipulation of the data happens within a class definition which in turn is called by the api, there appears to be no assurance that the global definition of the data will be in scope when it is time to manipulate the data, or that it will have been manipulated when the data is re-used further down.
For the interested reader, I was able to get the api developer to demonstrate the proper way of integrating javascript with the api calling the in-class function:
https://groups.google.com/forum/#!topic/xataface/l6qBzxF1vrc
Related
My code is...
<script type="text/javascript">
function changeval() {
$total = parseInt($("#small").val()) + parseInt($("#medium").val());
}
</script>
How can I pass '$total' to another js file, say main.js.
Call changeval function from another file, save/use returned value.
function changeval() {
return parseInt($("#small").val()) + parseInt($("#medium").val());
}
Or have one global variable save value inside the same variable and access it from another file.
Make sure that $total is assigned to the global scope and make sure the script where you want to use it is below the script where you assign it. Be careful about polluting the global scope too much because it can make code that is very tricky to debug and can cause strange errors if you overwrite a native global variable.
I am just starting to get into JavaScript and couldn't find an exact scenario like this yet on SO, so I'm going to try my luck. I have two functions in an external JS file which create video feeds on our website:
function getVideos() {
//gets a list of videos
}
//callback function automatically called by getVideos()
function response(jsonData) { //can't change this line
var resp = document.getElementById("resp"); //can change this line and any subsequent lines
//parses data and populates resp
}
Then, from the HTML side, we just call getVideos() and the video feed will be created and populated.
However, I want to be able to pass any element ID I want into response() so that we can create multiple video feeds in different places on the same page. The thing is I can't change the function declaration of response() to include another parameter. Or at least I'm not led to believe I can by the company hosting our videos.
I've tried wrapping response() with getVideos() and passing an element ID from there, but then response() doesn't get called, and the only solution I can think of is resorting to storing an element ID in a global variable, which I know is a no-no in general in JavaScript.
My question is: Do I just bite the bullet and use a global variable, or is there another way?
For more info, here is our JS code as it stands now (with the closure): http://www.thebearrocks.com/Other/js/videoFeed/createVideoFeed.js
And here is the tutorial on response() we're following from the host of our videos: http://support.brightcove.com/en/video-cloud/docs/making-media-api-calls-dynamic-script-tags
may be you can use arguments? like so:
function response(jsonData) { //callback function automatically called by getVideos()
var elemId = arguments.length<2 ? "resp" : arguments[1]+"";
var resp = document.getElementById(elemId);
//parses data and populates resp
}
or, declare second argument what has default value like this:
function response(jsonData, elemId) {
elemId = elemId || "resp";
var resp = document.getElementById(elemId);
//parses data and populates resp
}
in this case function can be called as with one or two arguments
I've tried wrapping response() with getVideos() and passing an element ID from there, but then response() doesn't get called, and the only solution I can think of is resorting to storing an element ID in a global variable, which I know is a no-no in general in JavaScript.
My question is: Do I just bite the bullet and use a global variable, or is there another way?
No. Not the id variable needs to become global, but your local response function needs to for getting called back from the JSONP script - you're going to create a closure.
You can "export" it by calling
window.response = mylocalResponseFunction; // you did name that local var "response"
I want to pass the name of a function "testMath" as a string into a wrapper function called "runTest" as a parameter. Then inside 'runTest' I would call the function that was passed. The reason I'm doing this is because we have a set of generic data that will populate into variables regardless of the test, then a specific test can be called, based on whatever the user wants to test. I am trying to do this using javascript/jquery. In reality the function is much more complex including some ajax calls, but this scenario highlights the basic challenge.
//This is the wrapper that will trigger all the tests to be ran
function performMytests(){
runTest("testMath"); //This is the area that I'm not sure is possible
runTest("someOtherTestFunction");
runTest("someOtherTestFunctionA");
runTest("someOtherTestFunctionB");
}
//This is the reusable function that will load generic data and call the function
function runTest(myFunction){
var testQuery = "ABC";
var testResult = "EFG";
myFunction(testQuery, testResult); //This is the area that I'm not sure is possible
}
//each project will have unique tests that they can configure using the standardized data
function testMath(strTestA, strTestB){
//perform some test
}
Do you need the function names as string? If not, you can just pass the function like this:
runTheTest(yourFunction);
function runTheTest(f)
{
f();
}
Otherwise, you can call
window[f]();
This works, because everything in the 'global' scope is actually part of the window object.
Inside runTests, use something like this:
window[functionName]();
Make sure testMath in the global scope, though.
I preffer to use apply/call approach when passing params:
...
myFunction.call(this, testQuery, testResult);
...
More info here.
I have a pretty specific question. I am trying to implement an onclick and cross domain tracking within a block of text, but it looks like it may need to be put directly into a .js document. I don't have a lot of JS experience. Basically, the current code looks like:
// JavaScript Document
function popup_no_status(loc)
{
var windowW=1000
var windowH=700
s = "width="+windowW+",height="+windowH+",status=yes, resizable=yes, scrollbars=yes";
mywin = window.open(loc ,'CBE', s);
mywin.focus();
}
What I want to add to this is:
onclick="pageTracker._trackEvent('Button', 'Click', 'QuickSearchWidget'); pageTracker._link(this.href); return false;
Can I just add it to the end of the document before the closing bracket? Any Ideas?
Much appreciated!
As long as the object pageTracker is defined and instantiated, you can call its methods like any other function:
function popup_no_status(loc) {
var s = "width=700,height=1000,status=yes, resizable=yes, scrollbars=yes";
var mywin = window.open(loc ,'CBE', s);
mywin.focus();
pageTracker._trackEvent('Button', 'Click', 'QuickSearchWidget');
pageTracker._link(this.href);
}
Also, the variables windowW and windowH are pointless in your example code - there is no need to store the string values in a variable if all you're going to do is concatenate them into another string. Further, unless you intend the mywin and s variables to be global, you should use the var keyword before defining them - that restricts the variables to the function scope instead of the global scope (all variables declared in a function without the var keyword are considered global).
If the code above gives an error like ReferenceError: pageTracker is not defined, that means that the code in which the pageTracker object is defined is either not included on the page, or it has not been instantiated.
Now... as for onClick, I am not clear what you're after here. Do you want this function to run when someone clicks the document? That would get pretty annoying!
I am writing a simple counter, and I would like to make installation of this counter very simple for users. One of the simplest counter code (for users who install it) I ever see was Google Analytics Code
So I would like to store main code in a file and user who will install my counter will need just to set websiteID like this:
<html><head><title></title></head><body>
<script type="text/javascript" src="http://counterhost.lan/tm.js">
var websiteId = 'XXXXX';
</script>
</body></html>
Here is my code:
<script type="text/javascript" src="http://counterhost.lan/tm.js">
var page = _gat.init('new');
</script>
and this is my JS file:
(function() {
var z = '_gat';
var aa = function init(data) { alert(data); alert(z);};
function na() {
return new z.aa();
}
na();
})();
I tried to understand Google Analytics javascript code but I failed to do this. Can anyone suggest how can I specify variable between tags and then read it in anonymous function which is located in a javascript file ?
Thanks.
In your example, websiteId is a global variable. So it is accessible everywhere including anonymous functions unless there is a local variable with the same name
<script> var websiteId = "something"; </script>
Later in the page or included js file...
(function() {
alert(websiteId); //this should work
})();
Can anyone suggest how can I specify variable between tags and then read it [...]
Not if your tag has both a SRC attribute and JS content.
<script type="text/javascript" src="http:/x.com/x.js"></script>
.. is different from,
<script type="text/javascript">
var x = 1;
</script>
One framework that optionally adds JS variables to SCRIPT tags is Dojo. So if you're using Dojo you can add variables to the global djConfig hash by writing,
<script type="text/javascript" src="mxclientsystem/dojo/dojo.js"
djConfig="
usePlainJson: true,
parseOnLoad: true
">
</script>
Dojo does this by running through the SCRIPT tags and evaluating the custom djConfig attribute.
This does not, however solve your problem.
You do really want two SCRIPT tags. One saying,
<script type="text/javascript">
var websiteId = '123456';
</script>
which will set a global variable websiteId and a second one,
<script type="text/javascript" src="http:/x.com/myreporter.js"></script>
which can load from anywhere and read out the websiteId variable and, I assume, report it back.
You can pass variables to an anonymous function like so:
(function(arg1, arg2, arg3) {
alert(arg1);
alert(arg2);
alert(arg3);
})("let's", "go", "redsox");
// will alert "let's", then "go", then "redsox" :)
I'm not entirely clear about what you're asking, but...
You can tag any HTML element with an id attribute, then use
document.getEntityById() to retrieve that specific element.
You can also give any HTML element user-defined attributes having names of your own choosing, then get and set them for that element within Javascript.
I think you've got a bit confused with how JS objects are called.
z is a String, '_gat'. You can't call aa() on it because a String has no member called aa. aa is a standalone function stored in a local variable. Even if you did call aa(), it doesn't return anything, so using the new operator on its results is meaningless. new can only be called on constructor-functions.
I guess you mean something like:
var _gat= function() {
// Private variable
//
var data= null;
// Object to put in window._gat
//
return {
// Set the private variable
//
init: function(d) {
data= d;
}
};
}();
Then calling _gat.init('foo') as in your second example would set the variable to website ID 'foo'. This works because the _gat object is the return {init: function() {...}} object defined inside the anonymous function, keeping a reference (a ‘closure’) on the hidden data variable.
If you specify a src attribute as part of a script element, any code within the script element tags themselves will not be executed. However, you can add this functionality with the following code. I got this technique from Crockford (I believe it was him), where he uses it in of his talks on the unrelated topic of rendering performance and asynchronously loading scripts into a page to that end.
JavaScript:
(function() {
// Using inner class example from bobince's answer
var _gat = (function() {
var data= null;
return {
init: function(d) {
console.info("Configuration data: ", d);
data = d;
}
}
})();
// Method 1: Extract configuration by ID (SEE FOOT NOTE)
var config = document.getElementById("my-counter-apps-unique-and-long-to-avoid-collision-id").innerHTML;
// Method 2: search all script tags for the script with the expected name
var scripts = document.getElementsByTagName("script");
for ( var i=0, l=scripts.length; i<l; ++i ) {
if ( scripts[i].src = "some-script.js" ) {
config = scripts[i].innerHTML;
break;
}
}
_gat.init( eval("(" +config+ ")") );
})();
HTML:
<script type="text/javascript" src="some-script.js" id="my-counter-apps-unique-and-long-to-avoid-collision-id">
{some: "foo", config: "bar", settings: 123}
</script>
Both methods have their draw backs:
Using a unique and non-colliding ID will make determining the proper script element more precise and faster; however, this is not valid HTML4/XHTML markup. In HTML5, you can define arbitrary attributes, so it wont be an issue at that time
This method is valid HTML markup; however, the simple comparison that I have shown can be easily broken if your url is subject to change (e.g.: http vs https) and a more robust comparison method may be in order
A note on eval
Both methods make use of eval. The typical mantra concerning this feature is that "eval is evil." However, that goes with say that using eval without knowing the dangers of eval is evil.
In this case, AFAIK, the data contained within the script tags is not subject to inject attack since the eval'ing script (the code shown) is executed as soon as that element is reached when parsing the HTML into the DOM. Scripts that may have been defined previously are unable to access the data contained within the counter's script tags as that node does not exist in the DOM tree at the point when they are executed.
It may be the case that a well timed setTimeout executed from a previously included script may be able to run at the time between the counter's script's inclusion and the time of the eval; however, this may or may not be the case, and if possible, may not be so consistently depending on CPU load, etc.
Moral of the story, if you're worried about it, include a non-eval'ing JSON parser and use that instead.