I have a reusable component implemented as an MVC3 PartialView. The component includes jquery-ui widgets which need javascript initialization code to run. The following is a simplified example:
==== MySimplifiedPartialView.cshtml ====
<div id="myTabs">
<ul>
<li><a href="#myTabs-tab1">Tab 1</a></li>
<li><a href="#myTabs-tab2">Tab 2</a></li>
<li><a href="#myTabs-tab3">Tab 3</a></li>
<li><a href="#myTabs-tab4">Tab 4</a></li>
</ul>
<div id="myTabs-tab1">
...content
</div>
<div id="myTabs-tab2">
... content
</div>
... etc ...
</div>
<script type="text/javascript">
$(document).ready(function () {
$("#myTabs").tabs();
});
</script>
When this PartialView is loaded into a page normally, the initialization code in $(document).ready
is run and the widgets are initialized properly (in this case as jquery-ui tabs).
However I also want to be able to load this PartialView into the DOM dynamically, e.g. as the result of an AJAX request. What is the usual way to ensure the initialization code is run in this case? In ASP.NET WebForms apps, I would use an UpdatePanel
, and achieve this by handling the load event, e.g.:
Sys.Application.add_load(function () {
$("#myTabs").tabs();
});
What is the equivalent in an MVC3 applications?
You have a couple of options. Easiest is often to include the script in the partial view:
<div id="#partial_view">Here is content in my partial view</div>
<script type="text/javascript">
(function($) {
$('#partial_view #myTabs').tabs();
} (jQuery));
</script>
tsegay also shows that you can do it during your ajax success event.
As a variation on the second option, since you are worried about encapsulation, is to initialize the javascript behaviors unobtrusively. For example:
<div data-tabs="true">Here is content in my partial view</div>
You can then encapsulate the initialization into a common object like so:
<script type="text/javascript">
(function($) {
$.myApp = {
obtruders: {}
};
// apply obtrusive behaviors
$.myApp.obtrude = function (selector, obtruders) {
var obtruder;
obtruders = obtruders || $.myApp.obtruders;
for (obtruder in obtruders) { // execute every registered obtruder
if (obtruders.hasOwnProperty(obtruder)) { // skip any inherited members
// apply an unobtrusive behavior
if (typeof obtruders[obtruder] === 'function') {
obtruders[obtruder].apply(this,
Array.prototype.slice.call(arguments, 0, 1) || document);
}
// apply all unobtrusive behaviors in set
if (typeof obtruders[obtruder] === 'object') {
$.myApp.obtrude(selector, obtruders[obtruder]);
}
}
}
};
// apply tabs behavior
$.extend($.myApp.obtruders, {
tabs: function (selector) {
$(selector).find('[data-tabs=true]').tabs();
}
});
$(function() {
// initialize unobtrusive behaviors
$.myApp.obtrude(document);
);
} (jQuery));
</script>
There is some initial setup in the code above, but ultimately you can do this during your ajax success event:
success: function(html) {
$('#partial_placeholder').html(html);
$.myApp.obtrude($('#partial_placeholder'));
}
The view doesn't need to know that it has to call .tabs() on anything in the partial view, just that the partial has some unobtrusive UX behaviors. You can do the same thing with unobtrusive datepickers or other things that need initialized. All you would need is another $.extend section in the $.myApp object:
// apply datepickers
$.extend($.myApp.obtruders, {
datepickers: function(selector) {
$(selector).find('[data-datepicker=true]').datepicker();
}
});
Another advantage of this is that you don't need to do any initialization on your normal (non-partial) views. The $(function(){..}); at the end of the big script above takes care of that for you by calling $myApp.obtrude(document) when the script first loads into the browser.
One option is you can load the jquery-ui tabs after the ajax call ends
If you are using jquery to make an ajax call
$.get('..',{},function(){
$("#myTabs").tabs(); //this will load the jquery-ui tabs
});