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.
Related
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.
I have a page that includes javascript which I only want to run under certain conditions. To do this I have placed the scripts into an asp:placeholder
This actually seems to work but when I run a debug on the page I get the following warning.
Element 'placeholder' is not a known element. This can occur if there is a compilation error in the Web site, or the web.config file is missing.
If I move the placeholders into the body of the page the warning goes, but that means I'm left with scripts in the body which I also want to avoid. Does anyone have any hints on the best practice for this scenario?? thanks
Sub Page_Load(ByVal Sender as Object, ByVal E as EventArgs)
dim lt as new Literal()
lt.text = "<script type='text/javascript' src='scripts/pageLoadAnimations.js'></scr" & "ipt>"
me.Header.Controls.Add(lt)
End Sub
You can include JS file straight from code behind:
If (some condition is true) Then
Page.ClientScript.RegisterClientScriptInclude("jQuery", "jquery-version.js")
End If
A couple of ways which fit your needs are:
Firstly, you could change your <head> tag to <head id="header" runat="server"> then this allows you to dynamically add anything into it, e.g.
dim lt as new Literal()
lt.text = "<script type='text/javascript' src='pathtojavascriptfile'></script>"
me.Header.Controls.Add(lt)
Or you could create a Public string on your page, then stick the javascript in this.
Public _JS as string
Page_Load
_JS = "alert('here');" ' Or what ever your javascript is
ASPX Page
<head>
<script type="text/javascript" src="jquery-version.js"></script>
<script type="text/javascript">
$().ready(function(){
<%=(me._JS) %>
});
</script>
</head>
You might consider looking into the ClientScriptManager. This will allow you to inject scripts into the header properly using whatever conditions you require.
Including Custom Client Script in ASP.NET Pages
ClientScriptManager Class
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
Is it possible to add a new ServiceReference instance to the ScriptManager on the Page during an asynchronous postback so that subsequently I can use the referenced web service through client side script?
I'm trying to do this inside a UserControl that sits inside a Repeater, that's why adding the ScriptReference programmatically during Page_Load does not work here.
EDIT 2: This is the code I call from my UserControl which does not do what I expect (adding the ServiceReference to the ScriptManager during the async postback):
private void RegisterWebservice(Type webserviceType)
{
var scm = ScriptManager.GetCurrent(Page);
if (scm == null)
throw new InvalidOperationException("ScriptManager needed on the Page!");
scm.Services.Add(new ServiceReference("~/" + webserviceType.Name + ".asmx"));
}
My goal is for my my UserControl to be as unobtrusive to the surrounding application as possible; otherwise I would have to statically define the ServiceReference in a ScriptManagerProxy on the containing Page, which is not what I want.
EDIT:
I must have been tired when I wrote this post... because I meant to write ServiceReference not ScriptReference. Updated the text above accordingly.
Now I have:
<asp:ScriptManagerProxy runat="server" ID="scmProxy">
<Services>
<asp:ServiceReference Path="~/UsefulnessWebService.asmx" />
</Services>
</asp:ScriptManagerProxy>
but I want to register the webservice in the CodeBehind.
Try something like this...
if (ScriptManager.GetCurrent(this).IsInAsyncPostBack)
{
ScriptManager.RegisterClientScriptInclude(this, this.GetType(), "script1", "~/js/myjs.js");
}
Edit:
After checking your issue, Here is the reason why it is not working:
When you add ServiceReference to ScriptManager > Services section manually in page. It adds 1 client script include directive.
e.g:
<script src="TestService.asmx/jsdebug" type="text/javascript"></script>
or
<script src="TestService.asmx/js" type="text/javascript"></script>
which provide you to accessibility to your Frontend.Web.YourScriptMethods,
Now when you add ServiceReference in async postback - It is not adding this client script inclue. So you get client script error - method is undefined.
But i figured out a workaround for this; (do not know it is right way to do it)
if (ScriptManager.GetCurrent(this).IsInAsyncPostBack)
{
ScriptManager.RegisterClientScriptInclude(this, this.GetType(), "testservice", "TestService.asmx/js");
}
You can replace the "TestService.asmx" path according to your project/web service.
This way you can achieve what you want.
Hope this helps,
Krunal Mevada
Old Ans:
Use following:
if (ScriptManager.GetCurrent(this).IsInAsyncPostBack)
{
ScriptManager.GetCurrent(this).Services.Add(new ServiceReference("~/Service.asmx"));
}
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.