JavaScript question - asp.net

calling a js function using onclick...
onclick="SubmitAge(66, 'ctl00_MainContent_arTo_upAgeRange')"
function just calls an updatePanel from the client... but its saying object expected at the onclick= part!!!
here is the function, is there anything wrong with the code?
function SubmitAge(age, UpdatePanelID) {
$get('HiddenAge').value = age;
__doPostBack(UpdatePanelID);
}
EDIT: THE SUBMITAGE FUNCTION IS INSIDE A .JS FILE (AGERANGE.JS) AND ONLY WHEN MOVED HERE DOES IT STOP WORKING: HERE IS THE LINKING METHOD/HEADERS FROM THE ASCX USERCONTROL INWHICH IT IS ALL CONTAINED...
%# Control Language="VB" ClassName="AgeRange" %
%# Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="AjaxCT" %
script src="AgeRange.js" type="text/javascript" /script
(arrow tags removed here as it wont display, hint: stackoverflow!!!)
im printing it like this from the server...
Public Sub AppendToSB(ByRef sb As StringBuilder, ByVal CurNo As Byte, Optional ByVal clickedNo As Byte = 0)
Dim sConfirmClick = ""
If clickedNo = CurNo Then ' maybe dont make it clickable...
sConfirmClick = "return confirm('The number " & CurNo.ToString & " is already selected, are you sure you want to select it again?');"
End If
sb.Append("<a href=""#"" onclick=""" & sConfirmClick & "SubmitAge(" & CurNo.ToString & ", '" & upAgeRange.ClientID &
"')"" runat=""server"">" & CurNo.ToString & "</a>")
End Sub

Complete rewrite of my post after several clarifications:
The problem is that the ASPX page is referencing an ASCX user control that is located in a different folder. That ASCX control has an HTML <script> tag that is using a relative path to the JS file.
The solution is to correctly resolve the URL to the JS file by using some extra code:
<script src="<%= ResolveClientUrl("MyScriptLibrary.js") %>" type="text/javascript">
</script>
To prevent the script file from being referenced multiple times I recommend using the approaches specified in this other post:
ASP.NET dynamically insert code into head
Here's what it looks like in the user control's code:
// Register a script reference:
Page.ClientScript.RegisterClientScriptInclude(GetType(), "myLibraryScript", "~/Scripts/MyScriptLibrary.js");

here is how i decided to do it, ResolveClientURL is important, static link will not always work, also the if check will prevent the script being added several times in one page if you use the control multiple times on same page...
If Not Page.ClientScript.IsClientScriptIncludeRegistered("AgeRangeJS") Then ' no point in registering it twice!
' AND its registered in the header, where it should be, not two copies in the body :)
Page.ClientScript.RegisterClientScriptInclude("AgeRangeJS", ResolveClientUrl("AgeRange.js")) ' ResolveClientUrl("AgeRange.js")
End If

Related

Getting asp.net user control to emit SCRIPT block only once if needed

I'm seeking advice on how to best encapsulate this HTML markup and behavior for extensive reuse.
I've developed a working version of some "context sensitive" help on a given .aspx page that uses the qTip2 plugin for jQuery ("squeezed up" here for completeness for the question):
$('a.myMore[title]').qtip({
content: { title: { button: true } }
, style: { classes: 'qtip-youtube myCustomClass' }
, position: { target: 'mouse', adjust: { x: 5, y: 5} }
, show: { effect: function() { $(this).fadeTo(500, 1); } }
, events:{hide:function(event, api) {if (event.originalEvent.type !== 'click') return false;}}
});
Here is a sample of the the markup operated upon by the plugin above that I'd like to encapsulate:
<a class="myMore" href="#" title='Text here will be displayed by a jQuery plugin called qTip2'>
<img src='../images/icon/info1.png' alt='?' />
</a>
This is in an older environment of Visual Studio 2008 webforms using VB.Net. One thread on SO expressed my need very well - see MVC3 Razor views - but the only encapsulation approach I can think of is writing an ASP.Net web user control (.ascx) to dump out the HTML I need. I envision being able to sprinkle something like this throughout my .aspx pages:
<qTipH:qTipHelper Title="Here is some content for the qTip." runat="server" />
Am I on the right track given the "old-ish" environment in which I have to work?
I started in on writing this control and immediately noticed there is no title attribute for any of these server controls - <asp:HyperLink nor <asp:ImageButton nor <asp:LinkButton. I don't think the code-behind of the user control can inject the title attribute text into a standard HTML <a> tag.
I think I know what I need rendered but I'm looking for advice on the best approach. Thanks.
EDIT - UPDATE:
So here is my .ascx file I came up with:
<%# Control Language="vb" AutoEventWireup="false"
CodeBehind="qTipHelper.ascx.vb"
Inherits="myProjectName.qTipHelper" %>
<asp:HyperLink ID="HyperLink1" runat="server" CssClass="myMore"></asp:HyperLink>
I discovered that any "missing" attributes like "title" can be handled by the following code-behind which adds to the Attributes collection of the control:
Public Partial Class qTipHelper
Inherits System.Web.UI.UserControl
Public Title As String = Nothing
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Title Is Nothing OrElse Title = "" Then
Visible = False
Else
Dim encodedTitle As String = Server.HtmlEncode(Title)
HyperLink1.Attributes.Add("title", encodedTitle)
HyperLink1.Attributes.Add("href", "#")
HyperLink1.ImageUrl = "../images/icon/info1.png"
End If
End Sub
End Class
On my invoking page(s), I added this:
<%# Register TagPrefix="qTip" TagName="qTipHelper" Src="~/UserControls/qTipHelper.ascx" %>
and then to spit out the HTML, I added this:
<qTip:qTipHelper runat="server" title="grist for the mill courtesy of qTip" >
</qTip:qTipHelper>
Is there a coding technique that could be added to the user control that would emit one Javascript script block at the bottom of the page (assuming that one or more tags for qTipHelper were present in the HTML above)?
In retrospect, this is weird question (I think because I never had to do anything like this before)...
Anyway, I simply collected all my current uses of qtip in a single Javascript file which I reference at the bottom of each .aspx page that uses it like this:
<script type="text/javascript" src="<%= ResolveClientUrl("~/js/qTipCode.js") %>"></script>
So, this boils down to:
1. writing a single user control
2. registering the user control on .aspx content pages that will need it
3. sprinkling the .aspx content page with the user control tag whereever it is needed
4. adding the script tag to point to the qtip Javascript file
5. ensuring that the selectors in the jQuery "match up" with the HTML markup on the page
I hope this helps someone else. I have learned alot about new stuff trying this.

Create javaScript variable in code behind of asp.net

How do I register a Javascript variable on the server side (backend) and access it on the client side (Javascript file), without a hidden field, Literal, etc.?
You can use the RegisterClientScriptBlock-Function from the Page's ClientScriptManager.
Page.ClientScript.RegisterClientScriptBlock(Page.GetType, "initMyClientVariable", "var myClientVariable=null;", True)
EDIT: according to your new informations, that you want to register a client array, use ClientScriptManager's RegisterArrayDeclaration Method.
VB.Net example:
Dim myArrayValue As String = """1"", ""2"", ""text"""
Page.ClientScript.RegisterArrayDeclaration("myClientArray", myArrayValue)
According to the new information in my comments that you need access to that variable from an external js-file: you should pass the js-array as argument to the function in the js-file. For example:
callFunctionInJsFile(checkBoxes);
You can put the following code in .aspx file ...
<script type="text/javascript" >
var date1 = "<%: DateTime.Now %>";
var date2 = "<%= DateTime.Now %>";
</script>
<%: %> works under ASP.NET 4
You can put a literal in the xml portion of the code and assign that literal some text:
myLiteral.Text = "<script language=\"javascript\">var myVar = 24;</script>";
This makes myVar globally available on the client side once it's rendered. You can also use the ClientScriptManager object to use Asp.Net to inject scripts and variables.
First place an <asp:Literal ID="Literal1" runat="server"></asp:Literal> tag in the <head> of your .aspx file. Then in the server side code in your .aspx.cs file, do something like Literal1.Text = "<script type=\"text/javascript\">var timer = 3600</script>" and you've got yout javascript variable called timer.
That's it. Have fun!

inject code into masterpage / html head from a user control

I am struggling with something that I guess should be standard practice really. I have a number of user controls that use some JQuery plugins. I do not really want to link to the extra CSS and JS files from my main masterpage as this would cause extra load to the user the first time they hit the site, (admittedly it would only be the once), so I was just putting them links into the top of the user control. Then I looked at my source HTML, not nice! Even worse for controls that repeat multiple times on a page.
So I was thinking is there a way of injecting them into the Head of the page when they are needed from the User Control. For that matter is there a way of doing it to the footer for JS stuff?
To dynamically register a script (and ensure that duplicates are merged) in ASP.NET you can call:
Page.ClientScript.RegisterClientScriptInclude(
"mykey", "~/scripts/jquery-1.3.2.js");
And read the full details on this method on MSDN.
To add CSS dynamically you can do something like this:
HtmlLink cssLink = new HtmlLink();
cssLink.Href = "path to CSS";
cssLink.Attributes["some attr1"] = "some value1";
cssLink.Attributes["some attr2"] = "some value2";
Page.Header.Controls.Add(cssLink);
This example of injecting CSS will not merge duplicate entries. To avoid duplication you'll have to keep track of duplicates yourself. One place you can store a list of scripts you've already registered is in HttpContext.Items. Stick a HashSet in there that keeps a list of all registered scripts so that you don't register the same CSS file twice (which is generally harmless, but something to avoid anyway).
I followed a similar approach, but I use CSS directly in the user control so I don't have to import a CSS file. The following is code entirely from a sample user control:
<style id="style1" type="text/css" visible="false" runat="server">
td { font-family: Tahoma; font-size: 8pt; }
</style>
In code-behind:
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
HtmlGenericControl style = new HtmlGenericControl("style");
style.Attributes.Add("type", "text/css");
style.InnerHtml = style1.InnerHtml;
Page.Header.Controls.Add(style);
}
You'll notice that the CSS is rendered in the head tag and not inside the body tag.
You can use ClientScript.RegisterClientScriptInclude() for the JavaScript.
For the CSS, one trick is to include them in your Master page, but with Visible="false", so that they aren't rendered into the markup by default.
Then, in your user controls, set a flag in the Items collection, from an early event, such as OnLoad(). For example, this.Context.Items["mycss"] = true;
Finally, in your Master page, from a later event, such as OnPreRender(), check to see if those flags are set. If they are, then set the Visible property to true for the corresponding CSS.
This also allows you to use the control with Master pages that don't use the CSS, since the Items entries could simply be ignored. If you have many Master pages that need the same behavior, you could put this code in a base class or use nested Master pages.
I assume you're using Asp.NET.
Try putting a content placeholder in the of the MasterPage...
<head>
<asp:ContentPlaceHolder ID="AdditionalPageHeader" />
</head>
If you're working in an aspx file or an ascx you need only define a content control...
<asp:Content ContentPlaceHolderID="AdditionalPageHeader" />
If you're working on a code-behind only type of server control, you can can get a pointer to that content place holder:
this.Page.Master.FindControl("AdditionalPageHeader")
... and manipulate it's contents programatically.
To add stylesheets or javascript (inline or not) dynamical I wrote these three functions:
Public Function addScript(ByVal path2js As String) As System.Web.UI.Control
Dim si As New HtmlGenericControl
si.TagName = "script"
si.Attributes.Add("type", "text/javascript")
si.Attributes.Add("src", path2js)
Return si
End Function
Public Function addScript_inline(ByVal js As String) As System.Web.UI.Control
Dim si As New HtmlGenericControl
si.TagName = "script"
si.Attributes.Add("type", "text/javascript")
si.InnerHtml = js
Return si
End Function
Public Function addStyle(ByVal path2css As String) As System.Web.UI.Control
Dim css As New HtmlLink
css.Href = path2css
css.Attributes.Add("rel", "stylesheet")
css.Attributes.Add("type", "text/css")
css.Attributes.Add("media", "all")
Return css
End Function
I call them in page_load on my masterpage, like this:
Me.Page.Header.Controls.Add(modGlobal.addScript("script/json/json2.js"))
or
Me.Page.Header.Controls.Add(modGlobal.addStyle("style/flexigrid/flexigrid.css"))
Regards

ASP.NET which control could wrap JS block and extractable so I could render it back to header

As title, basically I have a user control placed inside a page and then the page is placed inside the master page. I want to extract a block of javascript and put it back to the page head. When I try to wrap the code inside any block control (e.g. a div runat server) and access divID.InnerText then ASP.NET bust off with
Cannot get inner content of startup_script because the contents are not literal.
I dont want to extract JS inside cs file, thats awfully ugly approach (all sort of escapes and people wont even notice you have JS written unless they drill your CS file), what can I do?
You could store the javascript in a separate file, and then add it to the page using Page.RegisterClientScriptBlock()
Add the javascript you want to a .js file and add the .js file to your project.
Alter the properties of the .js file so that it is an Embedded Resource.
Then use code like this somewhere in your UserControl (maybe the Page_Load) to pull the code from the file and drop it into the page:
string javaScript = "";
// the javascript is in a separate file which is an 'embedded resource' of the dll
using (StreamReader reader =
new StreamReader((typeof(ThisClass).Assembly.GetManifestResourceStream(typeof(ThisClass), "NameOfJavaScriptFile.js"))))
{
javaScript = String.Format("<script language='javascript' type='text/javascript' >\r\n{0}\r\n</script>", reader.ReadToEnd());
}
Page.RegisterClientScriptBlock("MyScriptBlock", javaScript);
Note that RegisterClientScriptBlock() will put the script near the top of the page, but apparently not in the page header.
(edited bit about header after comment)
<%# Page Language="C#"%>
<script runat=server>
protected override void OnLoad(EventArgs e)
{
string scriptText = someID.InnerHtml;
//if you really want it in the header...
//Page.Header.Controls.Add( new LiteralControl(String.Format( "<scr" + "ipt language=\"javascript\">{0}</scri" + "pt>\\n", scriptText )));
//doesnt add to header and requires form runat=server
Page.ClientScript.RegisterStartupScript(this.GetType(), "SomeScript", scriptText, true);
base.OnLoad(e);
}
</script>
<head runat=server></head>
<form runat=server>
<div id="someID" runat=server>alert('hi');</div>
</form>
Okay, I've probably done this in a horrible, horrible way, but I wanted to add a script to the head element in a recent project from a user control. This script didn't require any data from my server, but I only wanted it on specific pages, so I put the script in a .js-file, and added it to the head like this:
HtmlGenericControl script = new HtmlGenericControl("script"); // Creates a new script-element
script.Attributes.Add("type","text/javascript");
script.Attributes.Add("src","src/to/js-file.js");
Page.Master.FindControl("head").Controls.Add(script); // Finds the element with ID "head" on the pages master page.
Not entirely sure if the code works as I think it does as the code I wrote for the project is on another machine, but you get the idea, right?
Edit:
After googling your error message for a bit, I think this might be a solution to your problem:
using System.IO;
StringWriter sw = new StringWriter();
HtmlTextWriter htw = new HtmlTextWriter(sw);
yourDivID.RenderControl(h);
String str = sw.GetStringBuilder().ToString();
If you combine the two examples, you should be able to get the result you want. I haven't tested this, but it works in my head.

Programmatically adding Javascript File to User Control in .net

How do you add Javascript file programmatically to the user control?
I want the user control to be a complete package - ie I don't want to have to add javascript that's related to the user control on the page where it's used, when I can do it inside the control itself.
Since there is no Page object in the user control, how would you do it?
In the Page_Load method of control.ascx.cs file:
LiteralControl jsResource = new LiteralControl();
jsResource.Text = "<script type=\"text/javascript\" src=\"js/mini-template-control.js\"></script>";
Page.Header.Controls.Add(jsResource);
HtmlLink stylesLink = new HtmlLink();
stylesLink.Attributes["rel"] = "stylesheet";
stylesLink.Attributes["type"] = "text/css";
stylesLink.Href = "css/mini-template-control.css";
Page.Header.Controls.Add(stylesLink);
This will load css and Javascript into the head tag of the main page, just make sure that the head has runat="server".
You can register client script includes using the ClientScriptManager.
Page is accessible through the Control.Page property.
Page.ClientScript.RegisterClientScriptInclude (
typeof ( MyControl ), "includeme.js", "js/includeme.js" );
EDIT: Sorry, for a total "complete package", its possible using scripts as Embedded Resources,
and aquire dynamic URL's through the WebResource.axd handler.
If this is not considered totally complete, then i guess it could be put in App_LocalResources, but it never gonna be just one file,
unless the code and script is inline.
The same as gnomixa's response, only a bit cleaner:
HtmlGenericControl js = new HtmlGenericControl("script");
js.Attributes["type"] = "text/javascript";
js.Attributes["src"] = "jscript/formfunctions.js";
Page.Header.Controls.Add(js);
from http://www.aspdotnetfaq.com/Faq/How-to-Programmatically-add-JavaScript-File-to-Asp-Net-page.aspx
In my site I Place all needed scripts and styles to placeHolder
<asp:placeHolder runat="Server" ID="phHead">
<script src="/header/widget/script.js" type="text/javascript"></script>
<link href="/header/widget/style.css" rel="stylesheet" type="text/css" />
</asp:placeHolder>
and
Private Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Page.Header.Controls.Add(phHead)
End Sub
Good question!
A UserControl should be a single package without any dependency on a JavaScript or a CSS file. You will need to make the JS and CSS files as embedded resources. Right click properties and set build action to embedded resources. Then you need to inject the JavaScript and CSS files as WebResources.
Here is one article that I wrote yesterday which talks about the same scenario:
http://highoncoding.com/Articles/502_Creating_RadioButton_Validation_Using_Custom_Validator.aspx
I generally do it when rendering the HTML for the control and depending on whether it's a library injection or an instance injection I use the Items collection to specify whether or not I have already produced the code for a control of this type during the current request using a unique identifier.
Something to the effect of:
protected override void Render(HtmlTextWriter writer)
{
base.Render(writer);
//Check if the Object Script has already been rendered during this request.
if (!Context.Items.Contains("xxx"))
{
//Specify that the Object Script has been rendered during this request.
Context.Items.Add("xxx", string.Empty);
//Write the script to the page via the control
writer.Write([libraryinjection]);
}
//Write the script that instantiates a new instance for this control
writer.Write([instanceinjection]);
}
If you have the text of the actual javascript in your .CS file, you can call Page.ClientScript.RegisterClientScriptBlock.
The following assumes that "GetScript()" returns the actual javascript you want added to the rendered control.
Page.ClientScript.RegisterClientScriptBlock(GetType(), "controlScriptName", GetScript());
I found this to be a more elegant way to fix-link to your javascript.
In your .ascx, link to your script files the following way:
<script src='<%= ResolveClientUrl("~/Scripts/jquery-1.7.1.min.js") %>' type="text/javascript"></script>
<script src='<%= ResolveClientUrl("~/Scripts/jquery.maskedinput-1.3.min.js") %>' type="text/javascript"></script>
That way, no matter which subfolder/page you add your user control to, the link to your scripts will always be correctly resolved.

Resources