1

I like to include my javascript in each page that needs it (more general js files go in the document head):

-- item.html --
<div id="item">
<script type="text/javascript" src="item.js"></script>
 ...
</div>

so in my script file I can now grab the container and use it to find things:

-- item.js --
var container = $('scripts').last().parent();
var f = container.find('form');

however, if the work needs to be done after the page loads:

$().ready(function() {
    var f = container.find('form');
});

I have a problem because container scopes across files. consider:

-- index.html --
<div id="item">
<script type="text/javascript" src="item.js"></script>
 ...
</div>
<div id="link">
<script type="text/javascript" src="link.js"></script>
 ...
</div>
<div id="part">
<script type="text/javascript" src="part.js"></script>
 ...
</div>

where the item.js fails because it picks up the last value container was assigned, instead of the one it was assigned at the time that it was declared such that it in essence performs:

$('#part').find('form');

instead of what I want:

$('#item').find('form');

so my question: how do I make the scope of container local to the file where it's declared?

alternatively, how could I do this differently?

ekkis
  • 9,804
  • 13
  • 55
  • 105
  • 1
    You'd have to change their name. Something like `link.container` or `fileName.container` seems a logical choice imo. – twentylemon Jun 13 '15 at 22:14
  • the reason for this setup is that I don't want to have to know what module I'm in. whichever module is executing, I want to just do `container.find()` and have it use the right container, so I just need to figure out how to keep the value I collected – ekkis Jun 13 '15 at 22:22
  • Could you explain what you're trying to do with different scripts for different elements and how it can't be abstracted into a similar behavior to be handled from within a single script? Other than that, I don't think you can really apply the term "scope" like that. Possible solution would be hard code the `id` of each element in the script it's enclosing. – Marko Gresak Jun 13 '15 at 22:32
  • @MarkoGrešak, the app is written in MVC so I have a Razor page that's responsible for a package of functionality (which explains why it includes its own Js files, since if the page is never called I need never include the Js). in certain cases I want to include multiple pages into a single page (think carousel) and in those cases I run into collisions – ekkis Jun 13 '15 at 22:39

3 Answers3

3

Please look into modularizing your code using something like AMD to solve this. This is exactly what AMD was designed to solve.

There are several possible libraries for this. Since you are using jQuery, RequireJS might make the most sense, however there are other solutions as well, such as

therealklanni
  • 652
  • 1
  • 5
  • 15
  • I marked Norman's answer because it answers the main question very clearly, but your answer is good and addresses my second question. than you. +1 – ekkis Jun 13 '15 at 22:33
  • and incidentally, yes, I need to face the issue of modularisation soon. I will look into the alternatives you provided – ekkis Jun 13 '15 at 22:34
  • Yes this is very interesting. I've been hearing a lot about AMD (and CommonJS) modules, but I yet to look into it. Looks like that is where my evening is going to get spent. – Norman Breau Jun 13 '15 at 22:43
  • haha. my evenings are all taken up for the foreseeable future until this project's done. but I will definitely check out AMD – ekkis Jun 13 '15 at 22:45
0

I don't a environment to test this on, but would this small alteration work?

var container = $('script[src="item.js"]').parent();

You would have to specify the filename for each scope, but that doesn't seem like much of a burden.

kim3er
  • 6,306
  • 4
  • 41
  • 69
  • it would work but if I'm going through this trouble it's precisely because I don't want to have to hard-code the name of the container – ekkis Jun 13 '15 at 22:47
  • @ekkis But surely you're only echoing the filename of the file you're currently editing? Or have I misunderstood the question? – kim3er Jun 13 '15 at 22:49
-2

JavaScript in the browser is functional scope. Which means variables declared (using the var keyword) belongs to the top most function, or the global scope if there is no function.

So to answer your question, in every file, you can do:

(function() {
    var someVariable = 1;
    //...
})();

What this does, is first evaluates and creates the anonymous function, and then immediately executes it with no arguments.

Since you are executing a function, any variables that you declare (as long as you use var), will be scoped to the function, and won't be available globally.

Norman Breau
  • 2,132
  • 16
  • 35
  • but that means the code will execute after the page loads, correct? which means that `$('script').last()` will no longer reflect the script currently running. btw, I didn't -1. I don't know why someone would have – ekkis Jun 13 '15 at 22:24
  • 2
    OP is asking about DOM element "scope". So how to get a parent DOM element of where script was declared. – Marko Gresak Jun 13 '15 at 22:24
  • I am confused by the first sentence. – user2864740 Jun 13 '15 at 22:24
  • @ekkis, I'll run some tests for you. I think `last()` will still work.. but not 100% sure. – Norman Breau Jun 13 '15 at 22:29
  • you're right. it will work. +1 and marked as the answer. thanks so much! – ekkis Jun 13 '15 at 22:31
  • 1
    @ekkis can you explain how does this work for you? I clearly do not understand your question or you have stated it terribly wrong. – Marko Gresak Jun 13 '15 at 22:34
  • This answer clearly did not ultimately solve OP's issue and should not be marked as answer... – Derek 朕會功夫 Jun 13 '15 at 22:36
  • Javascript files are loaded and executed synchronously. That is why it is usually best practice to have script includes at the end of your HTML page. That means, my solution will **not** work if you decide to load your javascript asynchronously using the **async** attribute, as then you can't guarentee load order. – Norman Breau Jun 13 '15 at 22:37
  • 1
    @MarkoGrešak the OP wants to treat each file as its own separate module. He also wants to use a variable named `container` in every module, without every other script file overwriting each other. – Norman Breau Jun 13 '15 at 22:41
  • this answer works because it makes it so that the value of `container` doesn't bleed across files. this means that when I set it (to the currently executing script's parent) and later reference it (after the page has loaded), I get the value I expect – ekkis Jun 13 '15 at 22:42
  • @NormanBreau, yes, I'm well aware of the issues surrounding asynchronous loading. in the context of my question, your answer will work just fine – ekkis Jun 13 '15 at 22:43
  • Oh that, then I've understood it wrongly. I thought the problem was that DOMReady event executes after scripts are loaded and the `.last` will find the last script loaded. In this case this would probably work. Although having a same variable for different elements means a high chance of copied code, which seems like a bad design. – Marko Gresak Jun 13 '15 at 22:44
  • @MarkoGrešak, the `.last()` correctly gets the values. the problem is they're not used util the page loads, which means the value got overwritten many times and is no longer of value. so the point is that although it's the same variable name, it's not the same variable. it's a variable whose value specifically references a context appropriate for the script – ekkis Jun 13 '15 at 22:50
  • I said I thought that was the problem and it seemed to strange to me that it would be, I thought it was more complex that it really is. If you google *js file scope* you get the answer on first hit so I can't really understand why does this have to be a new question. – Marko Gresak Jun 13 '15 at 22:53
  • @MarkoGrešak, the first hit answers the opposite question (which isn't actually a problem): how to make a variable scope across files (the answer is it does that automatically). my question is the opposite, how *not* to scope across files – ekkis Jun 13 '15 at 23:04
  • @ekkis how is [this](http://stackoverflow.com/a/4022619/1276128) answer (it's first hit for me) any different than your accepted answer? – Marko Gresak Jun 13 '15 at 23:06
  • yes, that is the question I saw too but it's the opposite of what I'm asking. the last answer in that question makes a reference to the opposite and would answer my question but not that of the poster – ekkis Jun 15 '15 at 03:33