I need to pass 4 arguments (3 strings and one comma separated list) from an ASP.NET page to another ASP.NET page using jQuery. The destination page ought to be launched as a separate window, which works fine with the following jQuery snippet:
$('#sourcePageBtn').click(function(){
window.open("destinationPage.aspx");
return false;
});
How can I pass the arguments to the destination page? I am trying to avoid the query string to pass the arguments because:
I don't want to show the url arguments (which can also be very long) in the destination window.
There are some special characters like ',/,\, & etc. in the string arguments.
Please suggest.
Edit:
I'm trying to access the arguments in the script section of the aspx file i.e.
<script language="C#" runat="server">
protected void Page_Load ( object src, EventArgs e)
{
//Creating dynamic asp controls here
}
</script>
My specific need for the arguments in the Page_Load of the script section stems from the fact that I am creating a few dynamic Chart controls in the Page_Load which depend on these arguments.
cheers
Initial Thoughts (before solution created)
Use POST for large data instead of GET. With POST no querystring will be used for data and therefore URL length restriction isn't a concern. (The max URL length differs between browsers so you're right to stay away from it when large data is moving).
Special URL characters can be encoded to be passed in the query string so that shouldn't be an issue.
Alternatively you might store the data on the server side from the first page, and have the second page pick it up from the server side. But this is overkill. And it makes you do unneeded server programming.
Passing state via HTTP calls is standard practice. You shouldn't try to circumvent it. Work with it. All the facilities are built in for you. Now it's just up to jQuery to provide us some help...
Note: Be careful using jQuery for main app features in case JavaScript is disabled in the browser. In most cases your web application should be usable at a basic level even when JavaScript is disabled. After that's working, layer on JavaScript/jQuery to make the experience even better, even awesome.
Edit: Solution (with ASP.NET processing)
Key resources for solution implementation are:
How use POST from jQuery - initiates the request, passes arguments, gets response
jQuery context argument - this is how the popup window DOM is accessed/affected from the main window
How it works: From a main page, a POST occurs and results are displayed in a popup window. It happens in this order:
The main script opens a popup window (if it doesn't already exist)
main script waits for popup window to fully initialize
main script POSTs (using AJAX) arguments to another page (sends a request)
main script receives response and displays it in the popup window.
Effectively we have posted data to a popup window and passed arguments to the processing.
Three pages follow and they constitute the complete solution. I had all 3 sitting on my desktop and it works in Google Chrome stable version 3.0.195.38. Other browsers untested. You'll also need jquery-1.3.2.js sitting in the same folder.
main_page.html
This is the expansion of the logic you provided. Sample uses a link instead of a form button, but it has the same id=sourcePageBtn.
This sample passes two key/value pairs when the POST occurs (just for example). You will pass key/value pairs of your choice in this place.
<html>
<head>
<script type="text/javascript" src="jquery-1.3.2.js"></script>
</head>
<body>
<a id="sourcePageBtn" href="javascript:void(0);">click to launch popup window</a>
<script>
$(function() {
$('#sourcePageBtn').click( function() {
// Open popup window if not already open, and store its handle into jQuery data.
($(window).data('popup') && !$(window).data('popup').closed)
|| $(window).data('popup', window.open('popup.html','MyPopupWin'));
// Reference the popup window handle.
var wndPop = $(window).data('popup');
// Waits until popup is loaded and ready, then starts using it
(waitAndPost = function() {
// If popup not loaded, Wait for 200 more milliseconds before retrying
if (!wndPop || !wndPop['ready'])
setTimeout(waitAndPost, 200);
else {
// Logic to post (pass args) and display result in popup window...
// POST args name=John, time=2pm to the process.aspx page...
$.post('process.aspx', { name: "John", time: "2pm" }, function(data) {
// and display the response in the popup window <P> element.
$('p',wndPop.document).html(data);
});
}
})(); //First call to the waitAndPost() function.
});
});
</script>
</body>
</html>
popup.html
This is the popup window that is targeted from the main page. You'll see a reference to popup.html in the jQuery script back in the main page.
There's a "trick" here to set window['ready'] = true when the popup window DOM is finally loaded. The main script keeps checking and waiting until this popup is ready.
<html>
<head>
<script type="text/javascript" src="jquery-1.3.2.js"></script>
</head>
<body>
<!-- The example P element to display HTTP response inside -->
<p>page is loaded</p>
</body>
<script>
$(function() {
window['ready'] = true;
});
</script>
</html>
process.aspx.cs (C# - ASP.NET process.aspx page)
The dynamic server page the arguments are POSTed to by the main page script.
The AJAX arguments arrive in the Page.Request collection.
The output is delivered back as plain text for this example, but you can customize the response for your apps requirements.
public partial class process : System.Web.UI.Page {
protected void Page_Load(object sender, EventArgs e) {
// Access "name" argument.
string strName = Request["name"] ?? "(no name)";
// Access "time" argument.
string strTime = Request["time"] ?? "(no time)";
Response.ContentType = "text/plain";
Response.Write(string.Format("{0} arrives at {1}", strName, strTime));
}
protected override void Render(System.Web.UI.HtmlTextWriter writer) {
// Just to suppress Page from outputting extraneous HTML tags.
//base.Render(writer); //don't run.
}
}
Results of this are displayed into the popup window by the original/main page.
So the contents of the popup window are overwritten with "[name] arrives at [time]"
Main References: HTTP Made Really Easy, jQuery Ajax members and examples.
If you keep a reference to the new window when you open it, ie var destWin = window.open(...) then you can access the variables and methods on the destWin window object. Alternatively you can "reach back" from the destination window with window.opener.
Related
I am in the process of putting a new site together which will make use of AJAX to pull through page content should the user have javascript enabled.
So, I am in the situation whereby every Action Method requires a check to see if the request was through AJAX or not, which is straightforward. If the request was through AJAX then I can return a partialview, if not then a full view can be returned.
With this pattern though, I'll need to create a View and a PartialView for every page on the site. The only real difference between them is going to the inclusion of the masterpage.
Am I missing a trick here is is this doubling up of views the only way to go?
Thanks
EDIT - a bit more info
Lets say I had a page that could get accessed through /site/test. Somewhere in my JS I would add a hash to the url like so #/site/test. JS would then watch for any hash changes and load the partial views as needed. If JS was not available though, an entire view would need to be returned.
So for each page I would need the view, which would then include a call to RenderPartial which would load up the partial view which would actually contain the page content. So, for every page there are two files. It just seems there should be a cleaner way of doing this.
Sergio, yes you are missing a trick!!
You should organise your page so that the static content in it is just that - static. This static page then calls the partial(s) that give the dynamic content. this would typically be used in the main page as such (i'm using jquery as per microsofts adopted stance on ajax now):
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>My Header</h2>
<%--lots of stuff omitted--%>
<div id="dynamicList"><%Html.RenderPartial("List"); %></div>
<%--also lots missed out here--%>
<input type="button" id="btnRefresh" value="refresh" />
</asp:Content>
this means that the partial would always be rendered in the initial request. subsequent refreshes would call the partial method in the controller and repopulate the 'dynmaicList' div along the lines of:
<script type="text/javascript">
// you might have a click or similar here to invoke the partial refresh
$(function() {
//click event (or some other 'change' event)
$('#btnRefresh').click(function() {
dynamicList();
});
});
function dynamicList() {
// where action/controller retruns a partialview result
var url = '<%= Url.Action("List", "MyController") %>';
// this is merely a wrapper method around jquery $ajax
SendAjax(url, formParams(), beforedynamicListQuery, dynamicListResponse);
}
function beforedynamicListQuery() {
$("#dynamicList").fadeTo('slow', 0.5);
}
function dynamicListResponse(data) {
if (data.length != 0) {
if (data.indexOf("ERROR:") >= 0) {
$("#dynamicList_errmsg").html(data);
}
else {
var selector = "#dynamicList";
$(selector).fadeTo('slow', 1, function() {
$(this).html(data);
});
}
}
}
</script>
anyway, that's my take on it!! ;)
On an ASP.NET page with a tabstrip, I'm using the hash code in the URL to keep track of what tab I'm on (using the BBQ jQuery plugin). For example:
http://mysite.com/foo/home#tab=budget
Unfortunately, I've just realized that there are a couple of places on the page where I'm using an old-fashioned ASP.NET postback to do stuff, and when the postback is complete, the hash is gone:
http://mysite.com/foo/home
... so I'm whisked away to a different tab. No good.
This is a webforms site (not MVC) using .NET 4.0. As you can see, though, I am using URL routing.
Is there a way to tell ASP.NET to keep the hash in the URL following a postback?
The problem is that the postback goes to the url of the current page, which is set in the action of the form on the page. By default this url is without #hash in asp.net, and its automatically set by asp.net, you have no control over it.
You could add the #hash to the forms action attribute with javascript:
document.getElementById("aspnetForm").action += location.hash
or, if updating an action with a hash already in it:
var form = document.getElementById("aspnetForm");
form.action = form.action.split('#')[0] + location.hash
just make sure you execute this code on window.load and you target the right ID
I tried to put the code from Willem's answer into a JS function that got called everytime a new tab was activated. This didn't work because it kept appending an additional #hash part to the URL every time I switched tabs.
My URL ended up looking like http://myurl.example.com/home#tab1#tab2#tab3#tab2 (etc.)
I modified the code slightly to remove any existing #hash component from the URL in the <form> element's action attribute, before appending on the new one. It also uses jQuery to find the element.
$('.nav-tabs a').on('shown', function (e) {
// ensure the browser URL properly reflects the active Tab
window.location.hash = e.target.hash;
// ensure ASP.NET postback comes back to correct tab
var aspnetForm = $('#aspnetForm')[0];
if (aspnetForm.action.indexOf('#') >= 0) {
aspnetForm.action = aspnetForm.action.substr(0, aspnetForm.action.indexOf('#'));
}
aspnetForm.action += e.target.hash;
});
Hope this helps someone!
I have another solution, implemented and tested with chrome, IE and safari.
I am using the "localStorage" object and it suppose to work all the browsers which support localStorage.
On the click event of tab, I am storing the currentTab value to local storage.
$(document).ready(function() {
jQuery('.ctabs .ctab-links a').on('click', function(e) {
var currentAttrValue = jQuery(this).attr('href');
localStorage["currentTab"] = currentAttrValue;
// Show/Hide Tabs
jQuery('.ctabs ' + currentAttrValue).show().siblings().hide();
// Change/remove current tab to active
jQuery(this).parent('li').addClass('active').siblings().removeClass('active');
e.preventDefault();
});
if (localStorage["currentTab"]) {
// Show/Hide Tabs
jQuery('.ctabs ' + localStorage["currentTab"]).show().siblings().hide();
// Change/remove current tab to active
jQuery('.ctabs .ctab-links a[href$="' + localStorage["currentTab"] + '"]').parent('li').addClass('active').siblings().removeClass('active');
}
});
I have this code in some of my ASCX files:
<%=Html.ActionLink(Resources.Localize.Routes_WidgetsEdit, "Edit", "Widget",
new { contentType = Model.ContentType, widgetSlug = Model.Slug, modal=true},
new
{
rel = "shadowbox;height=600;width=700",
title = Resources.Localize.Routes_WidgetsEdit,
#class = "editWidget"
})%>
Take note of that rel="shadowbox..." there. This is to wire up ShadowBox Lightbox clone for this ActionLink.
This works fine when user requests a page containing this User Control thru normal browser request. But I also render/build those View User controls trough AJAX requests. For instance, I would make request to /Widget/RenderToString/... using jQuery .ajax() method and it would return HTML code for that control. This works fine and it renders the code fine. I would then insert (append) the result to a DIV in a page from where the AJAX request was made. This also works fine and the returned HTML gets appended. The only problem is - ShadowBox is not wired up. Even though the code for it gets rendered.
It seems it requires page reload (F5) every time to wire ShadowBox up. Since I am doing AJAX GET and instant append to get rid of having to make a server roundtrip, I would also want ShadowBox to wire up without doing refresh.
Can someone help me with that? Thank you
UPDATE:
Yes, I have this in my Site.Master head:
<script src="<%=Url.Content("~/Scripts/shadowbox-build-3.0rc1/shadowbox.js") %>" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function() {
// insert functions calls here that provide some default behaviour
externalLinks();
});
Shadowbox.init({
language: "en",
players: ["img", "html", "iframe"],
onClose: function() { location.reload(true) }
});
</script>
How do I init the Shadowbox again after AJAX call?
There are many shadowbox plugins... which one are you using? (I can't give you exact code without it.) In any case I imagine you have something in your $(document).ready(function () { ... }); that tells shadowbox plungin to bind itself. You need to call that again after the AJAX call.
Just found the solution here
// call this after adding the new HTML to the page
// set up all anchor elements with a "editWidget" class to work with Shadowbox
Shadowbox.setup("a.editWidget", {});
I have an ASP.NET user control (.ascx file). In this user control I want to use a .js file.
So I include <script src="file.js" type"text/javascript"></script> on the page.
However, sometimes I use this user control in a webpage where this same script has already been loaded.
How can I add a <script /> declaration that will render on the page only if the page doesn't already contain another <script /> tag for the same script?
As you are using asp.net, it makes sense to do the check server-side as that will be where you choose to add the reference to the javascript file. From your .ascx file you could register with the following:
this.Page.ClientScript.RegisterClientScriptInclude("GlobalUnqiueKey", UrlOfJavascriptFile);
... from your page you just call the ClientScript object directly:
ClientScript.RegisterClientScriptInclude("GlobalUnqiueKey", UrlOfJavascriptFile);
The 'GlobalUniqueKey' can be any string (I use the url of the javascript file for this too)
If you try to register a script with the same key string, it doesn't do anything. So if you call this in your page, your control or anywhere else, you'll end up with only one reference in your page. The benefit of this is that you can have multiple instances of a control on a page and even though they all try to register the same script, it is only ever done a maximum of one time. And none of them need to worry about the script being already registered.
There is a 'IsClientScriptIncludeRegistered(stringkey)' method which you can use to see if a script has already been included under that key but it seems pretty redundant to do that check before registering as multiple attempts to register do not throw exceptions or cause any other errors.
Doing the check client-side means that, assuming the multiple javascript references are cached by the browser (they may not be), you still have multiple tags and the over head of each one causing some javascript to run. If you had 20 instances of your control on a page, you could get serious issues.
You can do one of two things client side...
Check the dom for the script tag corresponding to the javascript file your want to check
Test a variable or function you know has/will be defined within the javascript file for undefined.
Here's a quick JS function which uses JQuery to do what you need:
function requireOnce(url) {
if (!$("script[src='" + url + "']").length) {
$('head').append("<script type='text/javascript' src='" + url + "'></script>");
}
}
use something like the following:
if(typeof myObjectOrFunctionDecalredInThisScript != 'undefined') {
// code goes here
var myObjectOrFunctionDecalredInThisScript = { };
}
This tests if your object or function already exists and thus prevents redeclaration.
var storePath = [];
function include(path){
if(!storePath[path]){
storePath[path]= true;
var e = document.createElement("script");
e.src = path;
e.type = "text/javascript";
document.getElementsByTagName("head")[0].appendChild(e);
return false;
} }
use this in your main page and call function include with argument javascript file name
As you want to include javascript on one page of your site only.
If you use Asp.net(4.0) then it is very easy.
Just include following code
<script type="text/javascript" scr="filepath and name here"></script>
in ContentPlaceHolder of content page.
#Shimmy I am coming across this after a long while but maybe it might still be useful or at least help other coming from behind. To check if jquery is already loaded do this
<script>window.jQuery || document.write('<script src="js/libs/jquery-1.x.x.min.js"><\/script>')</script>
Don't miss the escape character in the closing script tag in document.write statement.
#mysomic, why did I not think of that. thumbs up
PS: I would have loved to write this right under the line where #Shimmy wrote that jQuery itself is the script he wants to load. But dont know how to write it there. cant see a reply or anything similar link. This may sound dumb but maybe I'm missing something. Pls point it out, anybody?
If you need it from server side, and Page.ClientScript.RegisterClientScriptInclude won't work for you in case script was included by some other way other then Page.ClientScript.RegisterClientScript (for example page.Header.Controls.Add(..), you can use something like this:
static public void AddJsFileToHeadIfNotExists(Page page, string jsRelativePath)
{
foreach (Control ctrl in page.Header.Controls)
{
if (ctrl is HtmlLink htmlLink)
{
if (htmlLink.Href.ToLower().Contains(jsRelativePath.ToLower())) return;
}
if (ctrl is ITextControl textControl
&& (textControl is LiteralControl || textControl is Literal))
{
if (textControl.Text.ToLower().Contains(jsRelativePath.ToLower())) return;
}
if (ctrl is HtmlControl htmlControl)
{
if (htmlControl.Attributes["src"]?.ToUpper()
.Contains(jsRelativePath.ToUpper())) return;
}
}
HtmlGenericControl Include = new HtmlGenericControl("script");
Include.Attributes.Add("type", "text/javascript");
Include.Attributes.Add("src", page.ResolveUrl(jsRelativePath));
page.Header.Controls.Add(Include);
}
I have a JavaScript method that I need to run on one of my pages, in particular, the onresize event.
However, I don't see how I can set that event from my content page. I wish I could just put it on my master page, but I don't have the need for the method to be called on all pages that use that master page.
Any help would be appreciated.
Place the following in your content page:
<script type="text/javascript">
// here is a cross-browser compatible way of connecting
// handlers to events, in case you don't have one
function attachEventHandler(element, eventToHandle, eventHandler) {
if(element.attachEvent) {
element.attachEvent(eventToHandle, eventHandler);
} else if(element.addEventListener) {
element.addEventListener(eventToHandle.replace("on", ""), eventHandler, false);
} else {
element[eventToHandle] = eventHandler;
}
}
attachEventHandler(window, "onresize", function() {
// the code you want to run when the browser is resized
});
</script>
That code should give you the basic idea of what you need to do. Hopefully you are using a library that already has code to help you write up event handlers and such.
I had the same problem and have come across this post :
IE Resize Bug Revisited
The above code works but IE has a problem where the onresize is triggered when the body tag changes shape. This blog gives an alternate method which works well
How about use code like the following in your Content Page (C#)?
Page.ClientScript.RegisterStartupScript(this.GetType(), "resizeMyPage", "window.onresize=function(){ resizeMyPage();}", true);
Thus, you could have a resizeMyPage function defined somewhere in the Javascript and it would be run whenever the browser is resized!