3

My entire website is an Ajax website, so all of my views (apart from Layout) can either be loaded normally or via an ajax actionlink. If I put the Javascipt files in with the partial views then all of the code works as expected, but the scripts get loaded multiple times (thus making the user download more scripts, all of them aren't being cached for some reason either).

If I put the script files in my Layout, then they only get loaded once but if a partial view gets loaded then the JS code for that partial view doesn't work obviously, because the scripts were already loaded when the partial view wasn't rendered.

My question is, how can I make the scripts get loaded only once, but also somehow have them affect partial views?

Index view:

<script src="/Scripts/Build/module.min.js"></script>
<script src="/Scripts/Build/upload-index.min.js"></script>

Layout:

<li>
    @Ajax.ActionLink("Upload", "Index", "Upload", new {Area = "Music"}, new AjaxOptions {HttpMethod = "GET", UpdateTargetId = "body-wrapper", InsertionMode = InsertionMode.Replace, OnSuccess = "updateHistory", AllowCache = true }, new {@class = "nav-link"})
</li>

You can see the scripts getting loaded multiple times if they are in the partial view: enter image description here

Martin Dawson
  • 7,455
  • 6
  • 49
  • 92
  • 2
    Do not put scripts in partial views. If your dynamically loading a partial after the page has been rendered, then you need to use event delegation (using `.on()` to handle events from elements in the partial) –  Mar 15 '16 at 22:16
  • What do you mean "affect partial views"? – Balde Mar 15 '16 at 22:16
  • @StephenMuecke I can't use `.on()`. I am using dropzone plugin in my view and it gets bound as soon as it loads. I need another way. – Martin Dawson Mar 15 '16 at 22:48
  • Then you just need to attach the plugin to the relevant element after the partial has been added. –  Mar 15 '16 at 22:54
  • @StephenMuecke I'm trying to use `.on()` like this `$(document).on("ready", "otherElement", function () { debugger; init(".dropzone.sounds"); }); ` It works if I use on click, but I need it to be ready when that other element loads and not on click, how do I do this? – Martin Dawson Mar 15 '16 at 23:22
  • 2
    As I noted in my previous comment. In the success callback, after you have added the partial to the DOM, then attach the plugin. You have not shown anything relating to the partial, but it would be something like `$(someElementYouJustAdded).dropzone({ .... });` –  Mar 15 '16 at 23:26
  • @StephenMuecke Ah yes. Thanks alot. – Martin Dawson Mar 15 '16 at 23:31
  • 2
    Just make sure your not reattaching the plugin to existing elements - e.g. if the elements has `class="dropzone"`, then use `$('.dropone:last').dropzone();` –  Mar 15 '16 at 23:40

1 Answers1

5

Scripts should not be in partial views, only the main view or its layout. Not only do you have the duplicate issue you have identified your self, but it can lead to other issues such as invalidating existing scripts.

If you need to handle events associated with dynamically added items then use event delegation using the .on() function. For example

$.(container).on('click', '.someclass', function() { .... }

will handle the click event of elements with class="someclass" that have been added as a child element of container even if they are added after the DOM has been initially loaded.

If you need to attach a plugin to dynamically added elements, then attach it after the element has been added to the DOM, for example

$.get(url, function(html) {
    $(container).append(html); // append the partial view
    $(container).find('someclass:last')..dropzone({ .... }); // attach plugin
});