Reputation: 4440
I am coding in ASP.NET MVC
5.2, and using jQuery
as my primary script library. I am having a bit of a problem though, with the disparity between _Layout
and views that use that layout.
Essentially, it goes like this
_Layout
has some script that needs to run (initial wiring, progress bar, splash screen, etc)_Layout
has additional scripts that need to run after the view's unique scripts.I have been trying a lot of ways to solve this, but it is actually proving to be a big problem. I have been frequently told that I should not create objects on the global namespace, so I am wondering if there are any other options to creating a script object that I can access in both views that isn't as damaging as global objects.
I have tried promises, and that is getting frustrating. I have tried events, and that doesn't really help because I cannot figure out what to attach the events to. I am told not to attach them to $(document)
, but that is really one of the only things that will be shared between the view and the layout.
I understand that global objects are not considered good in javascript, but at this point I'm not sure what other options I have to make sure things execute in the right order.
The issue is more about "tooling" than it is about run time. It is true that when the actual view loads and runs, it is all pressed into one big happy page, and would work just fine. The issue is mostly that I have to split up the logic in the tooling (Visual Studio) to keep it from throwing errors and getting confused.
So I suppose it is more accurate to say it is a pseudo-problem.
I have attempted to split up the logic like this, but I think this is just another way of declaring a global object. I got the idea from the Q.js
library.
(function(definition) {
// assign the task system
tasks = definition();
})(function() {
var list = [];
function tasks() {
};
tasks.start = start;
tasks.enqueue = enqueue;
/*
* start the task queue.
*/
function start() {
// make sure to raise a started event for things that need
// to monitor it.
$(this).trigger("started");
};
function enqueue(f) {
// add the potential function to the queue to be processed later.
list.push(f);
$(this).trigger("enqueue", { item: f });
};
return tasks;
});
$(function(){
$(tasks).on("started", function(){
console.log("event called");
});
console.log("tasks", tasks);
tasks.start();
});
Upvotes: 3
Views: 159
Reputation: 156524
There are a number of ways you could go about this:
Use RequireJs to define Tasks as a module, then:
require(['tasks'], function(tasks){
$(tasks).on("started", function(){
console.log("event called");
});
console.log("tasks", tasks);
tasks.start();
});
Use a global object, but namespace it:
Ciel = Ciel || {};
Ciel.tasks = Ciel.tasks || function(){
var list = [];
...
};
Tie your data to a specific dom element:
<div class="ciel-tasks"></div>
...
$(function() { $('.ciel-tasks').each(function() {
var tasks = $(this);
...
});
Upvotes: 1
Reputation: 218847
It's not really clear what you're describing. From JavaScript's perspective there's no such thing as "_Layout" and "Inheriting View." There's only the resulting DOM delivered to the browser. Any JavaScript code within that DOM can operate on anything else in that DOM. So I'm not sure what any of this has to do with global namespace, events, $(document)
, etc. Perhaps you're overcomplicating the issue by assuming disparity between your views when, client side, no such disparity exists?
_Layout has additional scripts that need to run after the view's unique scripts.
This sounds like it's just a matter of providing callbacks for operations so that they internally execute in the correct order. For example, if the desired order is:
initializeLayout()
initializeView()
completeLayout()
Then you can pass these to one another as callbacks and the functions can internally execute those callbacks. So in your Layout you might have something like this at the very top (such as in the header, as long as it's before the view is rendered):
<script type="text/javascript">
function initializeView(){} // placeholder for view-specific initialization
</script>
Then at the bottom with the rest of your scripts:
initializeLayout();
initializeView(completeLayout);
What this does is provide your views with an opportunity to overwrite that initializeView
function. If the view defines its own function called initializeView
then that one will be executed instead of the placeholder one defined in the layout (remembering that the layout and the view are all one page to JavaScript).
(This also assumes you've elsewhere defined a completeLayout
function, since that's what you want to execute after the view is initialized.)
Then in your view you can define that overwriting function:
function initializeView(callback) {
// do some stuff...
if (typeof callback == 'function') {
callback();
}
}
That will execute your view initialization code and then when it's complete will invoke the callback which was provided by the layout, so the layout will then execute its post-view-initialization code. (Naturally, if any of this "initialization" code is asynchronous, you'll want to invoke callbacks in response to those asynchronous callbacks, etc.)
Upvotes: 1