I have a form in my content page for which I am doing some client side validations via Javascript. The Javascript behaves as expected if I place the JS code directly in the content page. But if I place the JS code in it's own file and try accessing that from the content/master page (through the script tag's src attribute), I get a run time error when the validation function in JS being called.
To be specific, I get the below error.
Microsoft JScript runtime error: Objected expected/required at this line - document.getElementById('<%=txtemailId.ClientID %>').value
txtemailId is in the content page.
Javascript code is placed in validation.js and accessed via master page.
The reason I guess is that when .net is parsing the files, it is unable to substitute txtemailId.ClientID with the client side value that would be generated later on. So, how should one go about it? Thanks!
The answer to this is quite simple.
Within your content page declare an in-line JScript variable, make sure this is above your tag.
<script>
var emailClientId = <%=txtemailId.ClientID%>;
</script>
Within your include.js file make use of the globally scoped emailClientId variable.
Obviously this is a bit clumsy because not all of the JScript code is contained within the include.js file, which makes it difficult to debug / diagnose as it is not clear specifically where the value is coming from. You should clearly comment / document this within your code to make maintenance of he codebase easier in the future.
You're right, the code <%=txtemailId.ClientID %> will only get replaced with the real client ID by ASP.Net if this code is in an ASP.Net file. So if you put this javascript in a separate .js file, ASP.Net will know nothing about it, and the code will not be parsed.
The easiest way to achieve this is to make the control IDs parameters of your functions. This way you can have the calling javascript code in your .aspx (or .ascx) file, along with the <%=txtemailId.ClientID %> code.
Standalone .js files are not run through the ASPX parser, so your expression is not being evaluated.
To solve the problem, you could set global variables (or function parameters, or something else) in the ASPX files with the IDs of the controls, then use them in the standalone .js file.
Alternatively, you could uses class names (which don't get mangled) instead of IDs. (This is very simple using jQuery)
An approach like this is best suited for something you want to achieve:
validation.js
var Validation = {
EmailId: null,
Validate: function() {
var email = document.getElementById(EmailId).value;
}
}
page.aspx
Validation.EmailId = '<%=txtemailId.ClientID %>'; //initialize
Validation.Validate(); //whenever you want to validate
Related
How to get the web.config elements value in Javascript file?
I need the value of appSettings key's value in javascript file(not in aspx). What approach should I use to get this value?
web.config
On your aspx page you could do something like this.
<script type="text/javascript">
var keyName1 = '<%=ConfigurationManager.AppSettings["KeyName1"]%>';
</script>
Opening your entire web.config file to javascript could be a major security risk if you store things like database connection details or machine keys.
You can't get them directly in a javascript file - you can use server side scripting (ASP.NET) to output them values to javascript variables and pass those to functions that are in a file, but not dynamically in a javascript file.
You could create an HTTP module that will generate a javascript file dynamically - this would have direct access to the web.config and you will be able to insert values from it dynamically as you output javascript.
The least resource intensive would be to use something like filter chains in NAnt (or equiv in MSBuild—if it exists) to write the value to both your JS file and your web.config file.
This would prevent duplication of code (or configuration as it were).
The alternative (though a bit kludgy and more resource intensive) would be to put a script block above the script you need the value rendered dynamically from your aspx page using ConfigurationMangager.GetSection("web.config") in a way like this: http://schleichermann.wordpress.com/2009/01/15/dynamic-script-loading-in-html-head/
You should better get it from code-behind file and pass as a hidden value.
Using an expression builder is a little more flexible than the <%= %> tag, and there's one built in for accessing appsettings. Syntax is:
<%$ AppSettings:MyKey %>
Read more here.
I think I summed up the question in the title. Here is some further elaboration...
I have a web user control that is used in multiple places, sometimes more than once on a given page.
The web user control has a specific set of JavaScript functions (mostly jQuery code) that are containted within *.js files and automatically inserted into page headers.
However, when I want to use the control more than once on a page, the *.js files are included 'n' number of times and, rightly so, the browser gets confused as to which control it's meant to be executing which function on.
What do I need to do in order to resolve this problem? I've been staring at this all day and I'm at a loss.
All comments greatly appreciated.
Jason
If the issue is simply that the same file is being embedded multiple times and causing conflict, look into using RegisterClientScriptInclude. If you use the same identifier for all of your calls to RegisterClientScriptInclude only one instance of that file will be embedded:
http://msdn.microsoft.com/en-us/library/2552td66.aspx
However, if the issue is that your methods are being called but they don't know what controls on the page to operate on then you need to figure out how to provide your JS some context. Define a JavaScript object that represents your control on the client-side, and on the server-side emit the call that will instantiate it with the client IDs of the controls you'll be operating on.
We are using CustomValidator to validate User Control. The control works fine until you drop two instances of the Control on the same page, since they reference the exact same JavaScript functions, only one control works. Work around, we appended JavaScript function name with control id.
Validate_SAPDepartment<% =ControlId %>(oSrc, args) {...}
In codebehind, we assinged ClientValidationFunction
CustomValidator1.ClientValidationFunction = "Validate_SAPDepartment" + this.ControlId
This may not be the right approach but it works.
I've had this situation before. You register a separate JavaScript file with the page using the ScriptManager. You can stream this as a resource file embedded into the dll if you wish.
Then you only call into the functions from your control.
Otherwise a completely separate jquery file may also work.
I have created custom control using asp.net 2.0. The control contains a textbox txtDate. I have also created a javascript file DateMask.js which contains a function maskDate(). I have attached the maskDate() with textbox using -
txtDate.Attributes.Add("onkeypress","maskDate()");
I have also registered the script using ClientScript.RegisterStartupScript.
When I execute the aspx page containing my custom control it is generating script error showing that maskDate() is undefined.
Could anybody tell me what exactly the problem is?
Thanks for your cooperation.
One way to do it would be to place a literal control above your textbox, and assign the script to it in the code behind:
literal1.Text = "<script>function maskDate() {...}</script>";
The benefit to this, is you would not need to have to reference the script file with some tricky relative paths depending on where your usercontrol is used.
Make sure you didn't forget <form runat="server" ID="Form1"></form> at the end of the <head> tag!
As you can read in Using JavaScript Along with ASP.NET 2.0 under "The Difference Between Page.ClientScript.RegisterStartupScript and Page.ClientScript.RegisterClientScriptBlock" they rely on the location of the form tag.
We have shown two different methods
for placing JavaScript functions on an
ASP.NET page—so what is the
difference? The main difference is
that the RegisterStartupScript method
places the JavaScript at the bottom of
the ASP.NET page right before the
closing element. The
RegisterClientScriptBlock method
places the JavaScript directly after
the opening element in the
page. So what difference does this
make? It can make quite a bit of
difference, as we will see.
I am trying to make use of the yahoo exceptional performance rule : avoiding duplicate script
To do so i would like to be able to know whether or not a script was already added to the page before injecting it in the page. It looks like i can't figure what has been added in asp.net code behind unless i have a scriptmanager added to the page. but i would like to avoid using asp.net AJAX. From the description of the rule, it looks like it is something possible in php though.
Assuming that i can't do the check in my code behind, i was considering using jQuery $.getString function but it doesn't check before fetching the script. If i was to choose the javascript file, would i have to parse the whole http response in order to figure out which script was loaded on the page?
If the page is registering the scripts with the ASP.NET Page.ClientScript Register APIs then you can use Page.ClientScript.IsClientScriptIncludeRegistered. On the other hand, if you are using those APIs you don't really need to call it, since it already ensures only one of each is registered.
http://msdn.microsoft.com/en/us/library/system.web.ui.clientscriptmanager.isclientscriptincluderegistered.aspx
If the page just has regular ole script elements statically in the markup, and you need to detect if a script is loaded on the client side, you will have to get all the script elements on the page and look at their .src values. The thing with that is that some browsers automatically resolve that url to a full path, not just the one you declared. So, you can account for that in various ways -- you can just search for the end of the string being the script you want, or you can cause the url you want to compare with to also be resolved by setting it onto a dynamically created script element (which you never add to the DOM but is still resolved for you).
This is just off the top of my head, sorry if I get something wrong:
var s = document.createElement("script");
s.src = "foo.js";
var loaded, scripts = document.getElementsByTagName("script");
for (var i = 0; i < scripts.length; i++) {
if (scripts[i].src === s.src) {
loaded = true;
break;
}
}
if (loaded) {
// this script is already loaded
// assuming you dont have multiple copies in different locations
}
You don't need to use any client-side scripting to do this... you can do this in your code behind using the ClientScriptManager without needing to make use of ASP.NET AJAX (I think you're confusing ClientScriptManager with ScriptManager*) in your control/page just use:
ClientScript.RegisterClientScriptInclude("some-script", "myScript.js");
or from your user controls:
Page.ClientScript.RegisterClientScriptInclude("some-script", "myScript.js");
This will use the key "some-script" & only register one copy of the script on the page.
*To be clear I think the confusion is arrising from the difference between these:
ClientScriptManager if a server-side helper class which is used to manage client side scripts (in other words its whole purpose is to do exactly what you are trying to do). It is accessed via the Page's ClientScript property.
ScriptManager is a Control used to aid client side Ajax scripting in ASP.NET AJAX
(hell I even confused myself & gave the wrong example code initially)
well that wouldn't actually work in a master detail scenario with multiple web user controls.
Then you wouldn't have control over who has to do the script initialization if the web user control is dynamic.
It's easier to link once, but a developer would have to weigh his options between ClientManager and using a script load.
yeah you have to parse the whole response...
why don't you create a javascript file and put all of your javascript there and then import that javascript file in your code??? in this way you can get rid of duplicate script insertion.
I have a bunch of javascript functions which depend on some server-side constants (such as strings from my resources file). While I was developing them I kept the javascript code in the view header, so I could simply used server-side tags inside my javascript code, but now I'd like to move the javascript functions to a separate file.
I can't use a regular js file since that would not be interpreted by the server, making the server tags embedded there useless. I don't want to define variables in the page either since that seems way to awkward and error-prone.
What I've done instead is to create a new aspx file, put the javascript functions there and include that aspx file instead of a regular js file in my master template. It seems a bit unorthodox, but it seems to work fine.
Is there any downside to my approach that I have not taken into account? Or any better (less obscure) method?
Edit Bonus question: Should I use a DOCTYPE inside the included scripts file? After all, the scripts file is included by a script tag already. I tried to mimic regular js files, so I did not specify any DOCTYPE.
The file extension, be it js, aspx, ashx, bla, foo, whatever isn't all that important. If you have server side generated javascript that isn't specific to a page, then creating an ASPX page to render the javascript should be okay.
We'll often use HTTP handlers to generate dynamic javvascript in our systems. We also make sure to set the response headers to text/javascript to let the client browser know that we are sending back javascript.
Using a view, with MVC's templating capabilities is a great way to accomplish this. It is easy to maintain, well understood and gets the job done fast. The only real trick is to get it to serve the correct content-type. Doing something like this:
public ActionResult ConfigurationSettings()
{
Response.ContentType = "text/javascript";
return View(Configuration);
}
Actually gets you text/html content type. The trick is to make sure you get the last word, add this to your controller:
protected override void Execute(System.Web.Routing.RequestContext requestContext)
{
base.Execute(requestContext);
requestContext.HttpContext.Response.ContentType = "text/javascript";
}
And you will get the correct content type; ViewResult seems to force it to go text/html.
We use the ScriptDataBlock control from JsonFx to emit variables into the page itself. It acts like a dictionary where the key is the variable name (e.g. "MyNamespace.myVar") and the value is a normal C# value (including whole objects). The control emits appropriate namespace generation and type conversion to native JavaScript types. So in that sense it ends up not being "awkward" or "error prone":
myDataBlock["MyApp.myVar"] = myObject;
If you are doing an external file, then a generic .ashx handler is probably your best bet. It will be lighter than a whole aspx page and gives you pretty raw control over the output. Things you will want to be sure to do are to set the "Content-Type" response header to "text/javascript" (technically incorrect but most common MIME type) and for Internet Explorer which tends to not respect the Content-Type header, also set the "Content-Disposition" header to "inline;MyScriptName.js" so it knows the extension of the content.
Also, if these really are "constants" rather than runtime calculated data, you will want to set the "Expires" header to some future date to encourage the browser to cache the result. That will further reduce your server requests.
Edit: no DocType if you are creating JavaScript. DocType is only for markup.
You are using the MVC framework (your question is tagged as such) right? If so, you can create an action that returns a JavaScriptResult that will be executed on page when it loads:
public class JSController : Controller {
public ActionResult Headers() {
// create your variables here
return JavaScript("alert('hi');");
}
}
And then you can add it to your aspx/master page:
<script src="/JS/Headers" type="text/javascript"></script>