This project is read-only.

installation problem - javascript error

Aug 17, 2014 at 3:40 AM
Edited Aug 17, 2014 at 7:25 AM
I installed Mvc3ControlsToolkit via Nuget into my MVC5 project and now I have a javascript problem which didn't exist before the installation.

Partial view:
@{
   <script type="text/javascript">
      $(document).ready(function () {
         $("#Username").val("Enter email address");
      });
      function ClickLoginUsername() {
         $("#Username").val("");
      }
   </script>
}
<div>
   @using (Html.BeginForm("Login", "Account", FormMethod.Post, new { enctype = "multipart/form-data" })) {
      <div style="padding-top:3px">
         @Html.TextBox("Username", null, new { style = "width:132px", onclick = "ClickLoginUsername();" })
      </div>
   }
</div>
The purpose of this script is to default the username textbox to "Enter email address" and when the user clicks on the textbox, the value is cleared. After installing the toolkit, when I launch the application the default value is properly replaced (confirming that jquery is preset), but the mouse click cannot find the function any longer:

JavaScript runtime error: 'ClickLoginUsername' is undefined

The layout view includes:
<script src="~/Scripts/jquery-2.1.1.js" type="text/javascript"></script>

View source shows the script section rendered at the bottom of the page.

Workaround:
If I comment out the line GlobalFilters PlaceJavascriptAttribute in MySuperPackage, installed by Nuget automatically in App_Start, then everything works, errors disappear, and view source shows the script is rendered at the top of the page rather than at the bottom.

What do I need to understand from this? Documentation seems to suggest that I can comment out this line without upsetting things.
Coordinator
Aug 17, 2014 at 7:55 PM
Give a look to the last item of the migration guide.
The PlaceJavascriptAttribute parses the html and moves all javascript at the end of the html body. This improves the browser rendering time. It wraps also all javascript within a (function($){....})(jQuery) wrapper to prevent global names collisions(js best practice). Accordingly, your ClickLoginUsername function becomes local and is no more accessible globally....that is why you experience your problem.

Possible solutions are:

1) Application re-enginerig that avoids global names outside of any namespace, that is, define some namespaces in a javascript file and add all you functions and variable to these namespaces. In your case, for instance, define something like var application = {} in a js file and then in your script application.ClickLoginUsername=function(...){..... If possible, and if there are not too many changes to be made, this is the best solution, since it improves the quality of your code.

2) Define global names through the windows object. In your case: window.ClickLoginUsername=function(...){...}.

3) Prevent the use of the (function($){....})(jQuery) wrapper, by setting the NoWrapper property of the PlaceJavascriptAttribute.

The above should solve your problem. If you still continue having problem, then probably the move of all javascript code at the end of the Html nody breaks your code (this shouldn't be the case if you observe javascript best practices). In this case the only solution is the removal of the PlaceJavascriptAttribute. However in this case you will not benefit of an higher browser rendering speed....The whole toolkit will continue working properly...however, so you can do it.
Aug 18, 2014 at 12:35 AM

Thank you

Aug 18, 2014 at 10:59 AM

Frank,

I'm going crazy trying to understand Javascript. I have an ajax function which I may or may not want to run as the view is loaded, but I can't stop it from running. I've set a variable to false for testing, but it is ignored. When I understand why, then I'll try and pass a value from the view model to set true/false - whether or not to call the ajax function. Where should I go for help? Robert

$(document).ready(function () {

var url = '@Url.Action("PostMethod", "Nav")';

$("#divLoading").show();

var doit = false;

if (doit) {

$.post(url, null,

function (data) {

$("#PID")[0].innerHTML = data;

$("#divLoading").hide();

});

}

});

Coordinator
Aug 20, 2014 at 7:17 AM
Edited Aug 20, 2014 at 7:18 AM
You should reason on what happens on the server sise and what happens in the browser. If the decision onf if to execute or not the ajax call depends on only on a flag that is contained in the MVC ViewModel then the "if" should be added on the server side...ie a Razor @if: @if(Model.DoIt){ <script...> $(document).ready(function () {

var url = '@Url.Action("PostMethod", "Nav")';

$("#divLoading").show();

$.post(url, null,

function (data) {

$("#PID")[0].innerHTML = data;

$("#divLoading").hide();

)};

}

});
</script>
}
Aug 20, 2014 at 7:26 AM

Thank you again. I posted the issue on StackFlow and then realised that there was an error in my code. What you say is also interesting and I will examine it. Regards, Robert