Retrieving variables outside of Modernizr.load() complete scope - javascript

i am using Modernizr to load ressources to construct a jQuery layout.
The problem is that i cannot retrieve my $('body').layout() variable since it is inside one of the loaded resources (in script/webframe.js). I tried :
var myLayout;
function loadDefaultLayout() {
Modernizr.load([{
load: ['stylesheets/jquery.layout.css',
'script/jquery.layout.min.js',
'script/webframe.js'],
complete: function () {
myLayout = onDesktopWebFrameLoadComplete();
}
}]);
alert(myLayout.options.west.resizable);
}
Where onDesktopWebFrameLoadComplete is in script/webframe.js and returns the layout.
I tried moving alert(myLayout.options.west.resizable); just after onDesktopWebFrameLoadComplete and the alert was showing true. But when I move it out of the load() scope, I have an undefined error (for myLayout variable).
My question is :
I would like to know if it is possible to retrieve a variable outside of Modernizr.load() complete function scope.

My problem was only that I did not define my global variable in the right html file that called the function from the JavaScript file.
So in summary. Define your variable this way before everything else :
window.myLayout;
Then add your resource that will change your variable (that contains the load() function)
Change your variable in this resource : window.myLayout = "something-else";
You can now use it in the html file that included your resource.

Related

Google Chrome Extension: Expose variable from injected script via chrome.tabs.executeScript to another script injected the same way

Hopefully, the title is self-explanatory. Basically I'm injecting two scripts on my popup.js and I want to expose a variable defined on one of them so the other script can use it.
This is the way I'm injecting the scripts:
let sortFunction = function (goSortParam) {
if (goSortParam) {
chrome.tabs.executeScript(
null,
{ code: 'var goSortParam=true;' },
function () {
chrome.tabs.executeScript(null, { file: 'scripts/ajaxCalls.js' });
chrome.tabs.executeScript(null, { file: 'scripts/frontEndDev.js' });
}
);
} else {
chrome.tabs.executeScript(
null,
{ code: 'var goSortParam=false;' },
function () {
chrome.tabs.executeScript(null, { file: 'scripts/frontEndDev.js' });
}
);
}
};
This is the ajaxCalls.js:
const CONFIG_URL = chrome.extension.getURL('./data/config.json');
const promise = fetch(CONFIG_URL);
promise
.then(function (response) {
const processingPromise = response.json();
return processingPromise;
})
.then(function (processedResponse) {
const configData = processedResponse;
console.log(configData.tags);
});
The variable I want to expose is "configData" so "frontEndDev.js" can use it. Any ideas will be very welcome.
Safe approach
Use a special dedicated global variable, which you must define in a common script that runs first, for example:
chrome.tabs.executeScript({ code: 'var globalData = {foo: true}' });
chrome.tabs.executeScript({ file: 'scripts/ajaxCalls.js' });
chrome.tabs.executeScript({ file: 'scripts/frontEndDev.js' });
Then use globalData.whatever to access the data and globalData.whatever = 'anything' to set it. Since this is a standard JS object you can set a key inside even if it wasn't defined initially.
To make it even safer you can use the built-in function that converts objects into proper strings: 'var globalData = ' + JSON.stringify({ foo: true })
Unsafe approach
Share foo as window.foo = 'anything' then use it literally as foo or window.foo - both are the same, but the first one may require you to pacify your linting tool e.g. /* global foo */ in eslint.
It's unsafe in a content script because a web page can have an element with an id attribute containing the exact name of that variable, which historically creates an implicit global variable accessible both in the page context and in the isolated world of content scripts. Some pages may accidentally or intentionally break extensions by adding such an id and if they do it on the <html> element the variable will be created even for content scripts running at document_start.
The first approach was safe because it explicitly defined a global variable before running any dependent code (using a hardcoded name when defining, accessing, writing) thus overriding a possible implicit variable generated for a DOM element.
Some trivia
Such shared data can be used only by code that runs later in time (not simply the one that's "outside" the callback, more info)
All content scripts for the given page or frame run in the special "isolated world" of content scripts of this extension so they share globals like window or globalThis or any variables declared in the global scope of any script via var, let, const, class. For example, goSortParam in your code is a global variable so it's available in all content scripts directly. The isolated world is basically a standard JavaScript environment like that of any web page, but it's separate/isolated so variables (or DOM expandos) defined in one environment aren't visible in the other one. Every extension is assigned its own isolated world on every page/frame where its content scripts run.

call javascript page function inside ajaxed html

I have a page where i use jQuery to load some content into a div element
<div id="contents-box-in"></div>
jQuery code in page
$(document).ready(function() {
$("#contents-box-in").load("new-01.php", function() {
$('#contents-box-in').fadeIn(120);
});
var updateBoxData = function(data) {
$('#contents-box-in').fadeOut(100, function() {
$('#contents-box-in').html(data).fadeIn(130);
});
}
});
the content that i load is a form that needs to load a new page sending collected data from form
$('#form-buttons-next').click(function(e) {
var formData = new FormData($(this)[0]);
var formS = $.ajax({
url : 'new-02.php',
type : 'POST',
data : formData,
async : false,
cache : false,
processData : false,
contentType : false
});
formS.done(function(data) {
if (data != null) {
updateBoxData(data);
}
});
formS.fail(function(jqXHR, textStatus) {
alert("error");
});
});
since i do this in different step i would like to use a shared function contained in page that is loading the ajax content but i get updateBoxData is undefined
I guess that ajaxed content can't see parent container function
The easy way would be to load a different .js file containing shared function, i was wondering if is possible to access the updateBoxData from ajaxed contents
...i would like to use a shared function contained in page that is loading the ajax content but i get updateBoxData is undefined
I guess that ajaxed content can't see parent container function
No, that's not why. Your updateBoxData variable is scoped to the function it's declared in (your ready) callback. If you want it accessible globally, you'll need to make it global instead.
The problem is, though, the global namespace is already incredibly crowded. So if you put all of your useful functions there as globals, you're going to run into conflicts sooner or later.
For that reason, for now until browsers support ES2015 modules (which will take a while), I suggest giving yourself just one global symbol, something unlikely to conflict with other things, and assigning an object to it with properties for your various utility functions. E.g.:
var MyNiftyUtils = {
updateBoxData: function() {
// ...
}
};
Then you call that via MyNiftyUtils.updateBoxData. If the verbosity bothers you, no worries, just use a scoping function and assign it to a local:
(function() {
var u = MyNiftyUtils;
// ....
u.updateBoxData(/*...*/);
})();
(There are about 18 variations on that theme, this is just one of them.)
The function updateBoxData is defined inside a callback function you passed to .ready and hence its scope is limited to that function. Let us call this callback function Fx.
The click handler (the function passed to .click in the second part), which we call it Fy is defined outside of Fx and as a result does not have access to the variables defined in Fx (remember updateBoxData is a variable inside Fx).
That is why your code does not work. To get it working simply take updateBoxData out of the callback in .ready function:
$(document).ready(function() {
$("#contents-box-in").load("new-01.php", function() {
$('#contents-box-in').fadeIn(120);
});
});
function updateBoxData(data) {
$('#contents-box-in').fadeOut(100, function() {
$('#contents-box-in').html(data).fadeIn(130);
});
}
...
The rest is the same.

JavaScript Variable Passing between different .js

I am trying to pass 4 variables from one js file to another.
I read here that you must write:
window.myVar = "foo";
to make your variable "super"-global.
In the first js file, I have
window.signJoueur1 = string1.charAt(7);
window.signJoueur2 = string2.charAt(7);
window.valeurJoueur1 = random1;
window.valeurJoueur2 = random2;
In the second js file, I did
console.log(window.signJoueur1);
console.log(window.signJoueur2);
console.log(window.valeurJoueur1);
console.log(window.valeurJoueur2);
function trouveCombinaison(signJoueur1, signJoueur2, valeurJoueur1, valeurJoueur2)
{
console.log(signJoueur1);
console.log(signJoueur2);
console.log(valeurJoueur1);
console.log(valeurJoueur2);
}
It should work, but all console.log return `undefined'.
If you want more informations here are the full codes:
first .js http://pastebin.com/0zJKFNem
second .js http://pastebin.com/TsWc7TxL
the html http://pastebin.com/t3SzwZSC
So, my question is, how can I actually pass through the variables?
You are trying to use the values before they exist.
The code that assigns the values to the variables are inside a function, and that function isn't called until you click a button. The code that tries to show the values is executed when the page loads, so it uses the variables before they have been assigned any values.
Actually i just had to put window. in the second console.log group.
Such as :
function trouveCombinaison()
{
console.log(window.signJoueur1);
console.log(window.signJoueur2);
console.log(window.valeurJoueur1);
console.log(window.valeurJoueur2);
}
The fact that the console.log out of the function don't work is that it's executed when the page loads, as explained by #Guffa.
Now it works.

Javascript scope issue, inside an anonymous function

Sorry I couldn't be anymore specific with the title.
I'm building a web-site (personal), which displays different content to the user depending on the query string that is used in the url.
e.g. page=home.html would display home.html
The websites Javascript is wrapped inside an object, with each value containing different data, some pseudo code:
(function(){
var wrapper = {
init: function(){
//Runs on document ready
this.foo();
this.nav.render();
},
foo: function(){
//Some functionality goes here for the website, e.g. Display something from an API
},
nav: {
//Functionality to handle the navigation, has different properties
config: {
//Contains the config for nav, e.g. page names + locations
dir: '/directory/to/content/',
pages: {
page_name: wrapper.nav.config.dir + 'page_value'
}
},
render: function(){
//some code
},
routes: function(){
//some code}
}
}
};
$(function(){
wrapper.init();
});
})();
My problem is that I'm trying to prepend the dir value to each of the page values (inside the object where the pages are defined), expecting to get the output of (in this pseudo code case) of directory/to/content/page_value, but instead dir is undefined when I'm trying to access it, I've tried the following to achieve what I want:
wrapper.nav.config.dir + 'page_value'
I've been playing around with the last 30 minutes trying to find out what I'm doing wrong, and even thought about hard-coding the URL in for each page.
The reasoning for wanting to do this is that my local development server and web host have different directory structures, so I don't want to re-write the URL's each time I want to develop + publish. As for why everything is wrapped inside an object, I thought it would be easier to maintain this way.
Hopefully the answer is simple and it's just an amateur mistake / lack of understanding.
The issue is that you can't refer to a variable that is being defined in that very definition.
So, inside the definition of wrapper, you can't refer to wrapper. And, inside the definition of config, you can't refer to config either and so on.
The usual design pattern for solving this is to initialize as much as you can in the declaration of your data structure and then do the rest in .init() when you can freely access all of it.
Change the first two lines to:
var wrapper = null;
(function(){
wrapper = {
Otherwise, the wrapper is a local variable to your anonymous function.
The problem is that you're still busy defining the wrapper when you ask for its value, which is why it's still undefined.
The code below fails too:
var x = {
y:"1",
z:x.y
}
Why not:
//...
init: function(){
//Runs on document ready
this.foo();
var config = this.nav.config;
for (var page in config.pages) {
config.pages[page] = config.dir + config.pages[page];
}
},
//...

Variable not accessible when initialized outside function

When I use code like this, it works fine:
function removeWarning() {
var systemStatus = document.getElementById("system-status");
systemStatus.innerHTML = "";
}
function indicateInvalidUsername() {
var systemStatus = document.getElementById("system-status");
systemStatus.innerHTML = "Invalid username";
}
However, when I then want to move the systemStatus to be a global variable, it doesn't work:
var systemStatus = document.getElementById("system-status");
function removeWarning() {
systemStatus.innerHTML = "";
}
function indicateInvalidUsername() {
systemStatus.innerHTML = "Invalid username";
}
What am I supposed to be doing here?
It really depends on where your JavaScript code is located.
The problem is probably caused by the DOM not being loaded when the line
var systemStatus = document.getElementById("system-status");
is executed. You could try calling this in an onload event, or ideally use a DOM ready type event from a JavaScript framework.
Make sure you declare the variable on "root" level, outside any code blocks.
You could also remove the var altogether, although that is not recommended and will throw a "strict" warning.
According to the documentation at MDC, you can set global variables using window.variablename.
My guess is that the system-status element is declared after the variable declaration is run. Thus, at the time the variable is declared, it is actually being set to null?
You should declare it only, then assign its value from an onLoad handler instead, because then you will be sure that it has properly initialized (loaded) the element in question.
You could also try putting the script at the bottom of the page (or at least somewhere after the system-status element is declared) but it's not guaranteed to always work.
Declare systemStatus in an outer scope and assign it in an onload handler.
systemStatus = null;
function onloadHandler(evt) {
systemStatus = document.getElementById("....");
}
Or if you don't want the onload handler, put your script tag at the bottom of your HTML.
A global variable would be best expressed in an external JavaScript file:
var system_status;
Make sure that this has not been used anywhere else. Then to access the variable on your page, just reference it as such. Say, for example, you wanted to fill in the results on a textbox,
document.getElementById("textbox1").value = system_status;
To ensure that the object exists, use the document ready feature of jQuery.
Example:
$(function() {
$("#textbox1")[0].value = system_status;
});
To define a global variable which is based off a DOM element a few things must be checked. First, if the code is in the <head> section, then the DOM will not loaded on execution. In this case, an event handler must be placed in order to set the variable after the DOM has been loaded, like this:
var systemStatus;
window.onload = function(){ systemStatus = document.getElementById("system_status"); };
However, if this script is inline in the page as the DOM loads, then it can be done as long as the DOM element in question has loaded above where the script is located. This is because javascript executes synchronously. This would be valid:
<div id="system_status"></div>
<script type="text/javascript">
var systemStatus = document.getElementById("system_status");
</script>
As a result of the latter example, most pages which run scripts in the body save them until the very end of the document. This will allow the page to load, and then the javascript to execute which in most cases causes a visually faster rendering of the DOM.

Categories