1

In an attempt to respect the principle of not

"polluting the global namespace"

and for other reasons I saw that global variables are "generally" a bad idea, I switched in my code from global variables:

stBgAsset15_src = $image.attr('src');

to what, as a beginner I thought the most relevant, that is to say to create Object Image() with a "src" attribute/method.

var stBgAsset15 = new Image();
stBgAsset15.src = $image.attr('src');

But I can't access it outside the 'for' loop. I need to be able to access it inside the outer function of the loop and inside a function called ClickOnButton() that is referenced at the bottom of the main outer function.

I am getting the following error message:

Uncaught ReferenceError: stBgAsset15 is not defined

Also, and this is optional as it is not required today (but might be in the future), I wonder if it would be possible to also acces it from a totally different function called anotherFunctionTotallyUnrelated()

Full Demo on Jsfiddle: https://jsfiddle.net/nm4t1nob/

I have put console.log hints in each place I would need to be able to access the variables.

The loop here is not functional but just to allow the dissussion on scopes and best way to achieve this.

Code :

preloadFirstPriorityStAssets();

var $image = $('#intro').find('#Asset-15');

function preloadFirstPriorityStAssets() {

   // Variables
    var i,
        s;    
    var rawDataArray = [ 
          'https://example.com/image9',
          'https://example.com/image10',
          'https://example.com/image11'],
    len = rawDataArray.length;

    var $image = $('#intro').find('#Asset-15');

    for (i=0; i<len; ++i) {
      (function(index) {
        var s = rawDataArray[index];  

        //send to img shell the first raw data-src
        //which *automatically* generates src for img via Cloudinary responsive 
        $image.attr('data-src', s);

        //fire off a request to Cl. server to get the correct SRC
        //(asynchronous by default)
        $.cloudinary.responsive($image);

        var stBgAsset{a dynamic variable-injected by my backend on each loop occurence"} == new Image();
        stBgAsset{a dynamic variable-injected by my backend on each loop occurence"}.src = $image.attr('src');
       //if we take as assumption one of the  dynamic variable  
       //injected by my  backend on each loop occurence" is 15
       stBgAsset15.src = $image.attr('src');
      })(i);       
    };

 //if we take as assumption one of the  dynamic variable-injected by     
 //my  backend on each loop occurence" is 15
    console.log('stBgAsset15 value: '+stBgAsset15);
    console.log('stBgAsset15.src value: '+stBgAsset15.src);

    afterClickOnStThrobber();
  };

function afterClickOnStThrobber() {
  console.log('stBgAsset15 value: '+stBgAsset15);
  console.log('stBgAsset15.src value: '+stBgAsset15.src);
}

I am not very good with scopes as javascript beginner and wonder how to make this work.

I can't really use Arrays because, even if in this example I only have stBgAsse15, actually I will have in the actual code adynamic variable

stBgAsset+<id form database that will change on each loop>

So I really need for them to have a EXPLICIT name I can call when they are outputted form the loop. In an array, the values would all be in the array but it would be too complex to know which one is which. I need them have a name, a variable or sth they can be called on.

EDIT I need to add an important info following this answer "Just define stBgAsset15 outside of your for loop. This variable will still not be global as it will be scoped inside of your preloadFirstPriorityStAssets function. Then you need to pass stBgAsset15 as an argument to afterClickOnStThrobber."

The thing is I can't because I added somùe details: the src is set inside the loop as it changes for each value of the DataArray. It's a feature where I inject a dat-src then Cloudinary analyze each data-src and generate a different src. so i can't move it outside the loop. It needs to be processed by the loop.

Lajos Arpad
  • 64,414
  • 37
  • 100
  • 175
Mathieu
  • 4,587
  • 11
  • 57
  • 112
  • 1
    Possible duplicate of [Accessing variables from other functions without using global variables](https://stackoverflow.com/questions/407048/accessing-variables-from-other-functions-without-using-global-variables) – bgfvdu3w Oct 04 '17 at 09:41
  • 2
    This makes no sense. Given `var stBgAsset15` is declared in your loop, you might have multiple images or even none if `len` is `0`. If you want to access it from outside the loop, which of them do you want? – Bergi Oct 04 '17 at 09:57
  • *The thing is I can't because I added somùe details: the src is set inside the loop as it changes for each value of the DataArray* so you want to loop it but also use it as though it's not being looped. @Bergi is correct what your asking makes no sense. My advice. Take a deep breath and have a good think about what you actually want as I feel your getting yourself horribly confused here. – Liam Oct 04 '17 at 10:00
  • @Liam I know it is not clear but this is what I want to do: I edited my code: stSrc is not set to 15. it will be multiple values sent by my (ruby on rails) backend. so on each loop occurence/round, it will set a different value: for exmaple i will end up with stSrc17, stSrc78, stSrc105, then I juust want to know how to access them afterwards outside the loop. sorry for being first unclear it is just that i could not add the backend/ruby stuff in this javascript question so i oversimplified to saying there was only one stSrc value. – Mathieu Oct 04 '17 at 10:02
  • "*a dynamic variable-injected by my backend on each loop occurence*" makes no sense either. You still have a loop there, and only one loop. You cannot dynamically inject different values for each loop iteration, as the iteration happens on the client. I suggest you actually inject all the data as a JSON object or array, and then use that data structure (inside the loop as well as outside of it, accessing individual elements by name or index). – Bergi Oct 04 '17 at 10:10

3 Answers3

1

You can store assets in array and pass that array to other functions:

preloadFirstPriorityStAssets();

function preloadFirstPriorityStAssets() {

   // Variables
    var i,
        s;    
    var rawDataArray = [ 
          'https://example.com/image9' ],
    len = rawDataArray.length;
    
    var $image = $('#Intro').find('#Asset-15');
    
    var bgAssets = []; // create array for images
    
    for (i=0; i<len; ++i) {
      (function(index) {
        var s = rawDataArray[index];  
             
        var stBgAsset15 = new Image();
        stBgAsset15.src = $image.attr('src');
        bgAssets.push(stBgAsset15); // put image in array
   
      })(i);       
    };
    console.log('assets: '+bgAssets);

    afterClickOnStThrobber(bgAssets); // pass array to another function
  };
  
function afterClickOnStThrobber(data) {
  console.log('assets: '+data); // another operation with array
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="intro">
  <img    
      class="example"
      id="Asset-15"
      src="https://media-cdn.tripadvisor.com/media/photo-s/08/cd/99/1a/hard-rock-hotel-ibiza.jpg">  

</div>
Artem Kolodko
  • 410
  • 2
  • 10
  • Thanks. btw i just added some info and edited my code. I'd rather not use Array because afterwards I need to be able to EXPLCITLY call each value. For example I'll need to call stBgAsset15 , then stBgAsset14, or stBgAsset18 (this will depend on the values created for more than only the stBgAsset15). So in an array I won't be able to access them like this. I really need for them to have a name i can call when they are outputted form the loop. – Mathieu Oct 04 '17 at 09:52
  • I understand. You can create an object with key and value and then iterate this object. Like this: let assets = { stBgAsset15: Image, stBgAsset16: Image, ... } – Artem Kolodko Oct 04 '17 at 09:54
  • I could but it would force me after to parse this json or thing and on my backend(ruby) parsing this is slow. I would just like them has a specific "name" i can call. StBgAsset15, stBgAsset16... the problem is i don't know how to access them after outside the loop... – Mathieu Oct 04 '17 at 09:56
  • Ok, to access object after loop you can remove function call inside loop, because this anonymous function has another context that outer function (preloadFirstPriorityStAssets). – Artem Kolodko Oct 04 '17 at 10:02
  • could you show me in your answer's code. sorry beginner here! – Mathieu Oct 04 '17 at 10:05
  • Ok! In your example to have access object, created in loop, we should remove function inside. Replace loop in your original script: `for (i=0; i – Artem Kolodko Oct 04 '17 at 10:11
  • I removed the function(index) as you suggested. Great, it (partially) worked for the first 2 console.log but for the 2 inside afterClickOnStThrobber, I am getting Uncaught ReferenceError: stBgAsset15 is not defined – Mathieu Oct 04 '17 at 10:14
  • Yes, because you should pass object to another function (stBgAsset15 not in global scope). To pass it, define function like `afterClickOnStThrobber(data)` and call `afterClickOnStThrobber(stBgAsset15)`. In `data` will be our object. – Artem Kolodko Oct 04 '17 at 10:17
1

You will need to create stBgAsset as an empty object before the loop starts:

var stBgAsset = {};

Then, inside the loop you will need to initiate its elements with a code like:

stBgAsset["stBgAsset15"] = {}; //Your value

This way you will have the names you need and you will be able to find them on server-side. You will also be able to reach any such members after the for, therefore outside the cycle.

Before you complain that JSON.stringify-ing, sending things to the server and parsing them will be too slow I kindly ask you to try it out, I would bet that you will be surprised by the result. If not and it is slow indeed, then I would like to know which line is slow, how slow it is and what is the size of data you are parsing and sending.

Lajos Arpad
  • 64,414
  • 37
  • 100
  • 175
  • @Mathieu you are welcome. If this answer solved your problem, then you might consider accepting it as the correct answer. – Lajos Arpad Oct 04 '17 at 10:24
  • 1
    thanks very much. I am still testing Artem Kolodko's answer as well. I'll have to really try them on the real code, and I'll vote for the most relevant answer. I won't forget. – Mathieu Oct 04 '17 at 10:25
0

Just define stBgAsset15 outside of your for loop. This variable will still not be global as it will be scoped inside of your preloadFirstPriorityStAssets function. Then you need to pass stBgAsset15 as an argument to afterClickOnStThrobber.

Axnyff
  • 9,213
  • 4
  • 33
  • 37
  • I just edited my question. I had not put a piece of code, trying to simplify the problem but in fact I was indeed avoiding an important info: I can't put it outside the loop (to my understanding) – Mathieu Oct 04 '17 at 09:49