Question

Given this structure for a websinte

<html>
  <head>
    <!-- CSS at the beginning-->
    <link/>
  </head>
  <body>
    <div id="mainContainer">
      <div id="side"></div>
      <div id="content">
         <!-- DHTML awesomeness happens here -->
      </div>
    </div>
    <!-- Scripts at the end -->
    <script/>
    <script>
         /* code that attach the JS logic to the HTML items */
    </script>
  </body>
</html>

Using normal web navigation, the page renders totally in HTML, and following the progressive enhancement approach, at the end I look for some specific ids or classes, and I give them dynamic behavior using javascript and specially jQuery. This enhancement code happens at the very end of the body, after the external scripts has been downloaded.

In #content, lot of jQuery AJAX interactions happens, some of them get other partial views from the server and insert them in the page, but then I have to look for those ids and classes again and attach javascript objects to this new elements.

It could be very cumbersome, since you don't want to reapply controllers, event handlers or whatever to objects that already have them.

So far, the only solution that I found is put in my partial views:

@if(Request.IsAjaxRequest())
{
   <script> 
       /* code that attach the JS controllers to the HTML items of this view */
   </script>
}

I think that a similar problem happens for example when you want $('input.date').datepicker() , and you add new <input type="text" class="date"/> elements dynamically, the new ones have no date picker unless you rexecute the jQuery sentence.

For example, considering that in #content I have an <input type="text" class="date"/>:

  1. In order to make the jQuery datepicer work the first time, I have to call $('input.date').datepicker() at the end of the <body>, after the external <script> declarations.

  2. If the page download partial views where are new <input type="text" class="date"/> elements, I have to put the initialization call in the view for ajax calls.

So I end with repeated code, something that I don't want specially in JS where I cannot refactor the code as easily as in C#.

This is something that is driving me nuts in the last week, wondering if there is a better way to accomplish this? A better technique, or other whole approach?

How do you structure your web applications?

Kind regards.

PS: Would be nice to have something like .live() or .delegate() but not only related with events, wouldn't it? Is not there any event that jQuery/browser raises everytime that something is added to the DOM?

Was it helpful?

Solution

This may only be a partial answer to your question, if I understand it correctly.

Regarding your example with <input type="text" class="date" />, we experienced a similar issue with our partial form views that use jQuery unobtrusive validation. When loading them in the browser, we had to call $.validator.unobtrusive.parse('a form selector'); in order to get the validation rules to apply during the next form submission.

If your goal is to avoid repeated code, you could make your js actions unobtrusive, using a pattern like in the jq unobtrusive validation lib. So you would end up with HTML that looks more like this:

<input type="text" class="date" data-datepicker="true" />

You can then put the initialization logic in an unobtrusive parse method.

parse: function(selector) {
    $(selector).find(':input[data-datepicker=true]').each(function() {
        $(this).datepicker();
    }
};

}

This solves your problem of having one place to refactor the code. You can make it start up automatically when the page first loads, and when you load new content via ajax, you can apply the rule to all matching elements by just calling myAppNamespace.unobtrusive.parse('selector for the partial view content');

Update

Take a look at the jquery.validate.unobtrusive.js file in your scripts folder. It really is pretty smart, and if you're not actually extending another jquery plugin (like validate), your code would end up a lot slimmer. If you're looking for full separation of HTML and script, using the HTML5 unobtrusive data- attributes is a good solution imo.

OTHER TIPS

I have marked the @olivehour response as correct, since it states a good solution for the problem.

What I have finally done, is move the jquery file to the head, and just the jquery file, the rest like "jquery-ui", or custom js files are still in the bottom.

The reason is being able to use $(document).ready or $(function(){}), since using that on the view, the code executes on "onload" or straightaway if the "onload" has been raised already, what is perfect for what I want.

Cheers.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top