Scroll to top of page after async post back - asp.net

So I need to scroll to the top of the page after an async post back in an asp.net update panel.
The code I used was this:
Sys.WebForms.PageRequestManager.getInstance().add_endRequest(EndRequestEventHandler);
function EndRequestEventHandler(sender, args)
{
scrollTo(0,0);
}
However, I only want this to be run when I click on a certain button which causes the async postback.
How do I wire this event up in my code behind button event?
Any help would be appreacited, thanks!

My quest for a solution is finally over. This question was part of the help, and the rest I found here.
Had to override ASP.NET Ajax's behaviour of memorizing the scroll position:
<script type="text/javascript">
var manager = Sys.WebForms.PageRequestManager.getInstance();
manager.add_beginRequest(beginRequest);
function beginRequest()
{
manager._scrollPosition = null;
}
</script>
And then use the bit of code in the answer here, on the codebehind of the page I wanted to scroll to the top:
ScriptManager.RegisterStartupScript(this, typeof(MyControl), "someText", "window.scrollTo(0, 0)", true);

I used Farinha's answer (thanks!) and changed it slightly so I could just call the method any place I wanted to scroll to the top, but maintain the scroll position otherwise.
public static void ScrollToTop(int intPosY = 0)
{
string strScript = #"var manager = Sys.WebForms.PageRequestManager.getInstance();
manager.add_beginRequest(beginRequest);
function beginRequest()
{
manager._scrollPosition = null;
}
window.scroll(0," + intPosY.ToString() + ");";
Page pagCurrent = GetCurrentPage();
ScriptManager.RegisterStartupScript(pagCurrent, pagCurrent.GetType(), string.Empty, strScript, true);
return;
}
public static Page GetCurrentPage()
{
return (HttpContext.Current.Handler as Page);
}

Try this:
protected void myButon_Click(object sender, EventArgs e)
{
ScriptManager.RegisterStartupScript(this, typeof(MyControl), "someText", "alert('!');", true);
}

Improving on the answers of #Farinha and #Bradford Scott, the code can be simplified to this:
var script =
"Sys.WebForms.PageRequestManager.getInstance()._scrollPosition = null; " +
"window.scrollTo(0, 0);"
ScriptManager.RegisterStartupScript(this, GetType(), "key", script, true);
I'm actually not even sure why their scripts work since they add the reset of the Sys.WebForms.PageRequestManager's _scrollPosition as an add_beginRequest handler, and here we are actually returning from the request.
Anyway, resetting the _scrollPosition right before making your own scrollTo() call definitely works.

Related

Nested subscription to messages on xamarin forms

I'm new with Xamarin forms and don't know how to deal with this case. I've tryed to implement it in several ways but with no success.
I have a page where when user makes an action (write a text on a text box and send it with enter key) my app must make some checkings. Depending on the result of the checks, it could be necessary to show a modal page with a list of item to select. Ones user makes the selection process must continue with other checks. And here is my problem, because in this next checkings I have to show another page. User must make a selection/enter some date, and then continue to complete the proccess, but this page is not appear.
I'm using the messagingCenter to subscribe to the modal pages. First modal page appears and makes the selection well. Second modal page is never shown and then proccess never complets.
Here is some of my code:
NavigationPage navigationPage = new NavigationPage(new ListItemsPage(products));
Navigation.PushModalAsync(navigationPage);
MessagingCenter.Subscribe<ListItemsPage, Guid?>(this, "Select product", (obj, item) =>
{
try
{
if (item != null)
{
product = products.SingleOrDefault(x => x.Guid == item);
if (product != null) ProcessLine(product);
}
}
catch(Exception ex)
{
throw ex;
}
finally
{
MessagingCenter.Unsubscribe<ListItemsPage, Guid?>(this, "Select product");
}
});
On ListItemsPage I have this code whe item is selected:
private void MenuItem_Clicked(object sender, EventArgs e)
{
// some logic...
Navigation.PopModalAsync();
MessagingCenter.Send(this, "Select product", SelectedGuid);
}
SelectedGuid is a Guid type data and when debbugin is well selected.
Problems comes when goes to ProcessLine method.
private void ProcessLine(Product product) {
// make some logic...
NavigationPage navigationPage = new NavigationPage(new ControlUnitsPage(model));
Navigation.PushModalAsync(navigationPage);
MessagingCenter.Subscribe<ControlUnitsPage, ControlUnits>(this, "Select units, date and lot code", (obj, item) =>
{
try
{
if (item != null)
{
_date = item.Date;
_code = item.Code;
_units = item.Units;
Save(productLine, product, _units, _date,_code);
}
}
catch(Exception ex)
{
throw ex;
}
finally
{
MessagingCenter.Unsubscribe<ControlUnitsPage, ControlUnits>(this, "Select units, date and lot code");
}
});
}
ControlUnitsPage has the same structure as the last one page. First makes a PopModalAsync and then sends the message sending an instance of ControlUnits type.
private void Button_Clicked(object sender, EventArgs e)
{
//some logic...
Item = new ControlUnits() { Date = DateField.Date, Code = CodeField.Text, Units = int.Parse(SelectedUnits.Value.ToString()) };
Navigation.PopModalAsync();
MessagingCenter.Send(this, "Select units, date and lot code", Item);
}
I think problem is in the order of invoking method but dont know what is the properly order because I am not able to understand how pushmodal, popmodal methods work, whether or not I should use await with it if after that comes a subscription. I really don't know and I need help, please.
Thank you so much!
your Send and Subscribe calls both need to use matching parameters
if Subscribe looks like this
MessagingCenter.Subscribe<ControlUnitsPage, ControlUnits>(this, "Select units, date and lot code", (obj, item) => ... );
then Send needs to match
MessagingCenter.Send<ControlUnitsPage, ControlUnits>(this, "Select units, date and lot code", Item);

Show alert after postback

I have a button which calls stored procedure and binds gridview.
I found a code on stackoverflow for top alert bar like this:
function topBar(message) {
var alert = $('<div id="alert">' + message + '</div>');
$(document.body).append(alert);
var $alert = $('#alert');
if ($alert.length) {
var alerttimer = window.setTimeout(function () {
$alert.trigger('click');
}, 10000);
$alert.animate({ height: $alert.css('line-height') || '50px' }, 500).click(function () {
window.clearTimeout(alerttimer);
$alert.animate({ height: '0' }, 200);
});
}
}
Then in my button I try to call this function like this:
Dim script As String = String.Format("topBar({0});", Server.HtmlEncode("Successfully Inserted"))
Response.Write(script) 'Or even like this
ClientScript.RegisterStartupScript(Page.GetType(), "topBar", script, True)
But it simply does not work.
Can you guide me in right direction?
I always sort this type of problems with supplying a Boolean Property whether javascript should fire a piece of script or not. For example :
public bool IsDone { get; set; }
Sorry that the code is in C#
This is a property on code behind file. When I need to fire the javascript method, I simply make this true.
What I do on the aspx page is as follows :
<script>
if(<%= IsDone.ToString().ToLower() %>) {
alert("Done!");
}
</script>

ASP.NET Dynamic User Control with JQuery

Alright...this is a bit of a complex problem so hopefully I can explain it properly.
I have a user control which I am dynamically loading in my page_load event via a method (see below). The user control contains a gridview and a label. A key piece of information has to do with how to get around the convenient feature of gridviews not rendering when their datasource is empty. In my user control I add some hidden rows so that the grids will render and the user can see just the headers (if the situation calls for it).
The nomControl is an asp:Panel on the parent page which will hold the user controls. The dsRefinedProductsNomInfo is a strongly typed dataset.
private void LoadCycleControls()
{
var dsRefinedProductsNomInfo = Session[REFINED_PRODUCT_NOMINATION_INFO] as RefinedProductsNomInfo;
if (dsRefinedProductsNomInfo == null)
{
return;
}
int permittedCycles = dsRefinedProductsNomInfo.NOS_MONTH.Count == 0 ? 0: dsRefinedProductsNomInfo.NOS_MONTH[0].PERMITTED_CYCLES;
for (int cycle = 1; cycle <= permittedCycles; cycle++ )
{
var control = LoadControl("~/CustomControl/RefinedProductNominationCycleControl.ascx");
nomContent.Controls.Add(control);
var nomControl = control as RefinedProductNominationCycleControl;
if (nomControl == null)
{
return;
}
nomControl.CycleNumber = cycle;
nomControl.ID = "control_" + cycle;
nomControl.CycleTitle = "Cycle " + cycle;
nomControl.GridDataSource = dsRefinedProductsNomInfo.REFINED_PRODUCT_NOS_CYCLE_INFO;
}
}
Now when a user adds a row to the grid they click a plus button. In the button javascript click event I make an ajax call to a page method.
var options = {
type: "POST",
url: "RefinedProductNomination.aspx/AddNomCycleLineItem",
data: "{'id':'" + tableRow.attr("id") + "',\
'isPlug':'" + isPlug + "',\
'sequenceNbr':'" + sequenceNbr + "',\
'receiptLocationId':'" + receiptLocationId + "',\
'materialTypeId':'" + materialId + "',\
'shipperId':'" + shipperId + "',\
'tankId':'" + tankId + "',\
'deliveryLocationId':'" + deliveryLocationId + "',\
'volume':'" + volume + "',\
'cycle':'" + cycle + "'}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(response) {
if (response.d != "") {
if (response.d == "-1000") {
var messageContainer = tableRow.parents("div").siblings("div #messageSummary");
messageContainer.empty()
var message = $("<span></span>").append("There has been an issue accepting the row please try again.");
messageContainer.append(message);
message.fadeOut(10000, "linear");
}
else {
ConvertToReadOnlyRow(tableRow, response.d);
}
}
}
};
//Call the PageMethods
$.ajax(options);
The page method then retrieves the dataset from the cache and adds the new row the user created. This all works fine and I can save to the database via an asp:button and handling it's click event.
My issue is after the the user clicks the save button and everything is rendered my grid shows the rows I added to make sure just the headers show up. In my save button click event I am removing these added rows so they don't get persisted and then saving and then added again once we load the user control. Initially this seems like the right place to handle this but after figuring out the order of events it would appear I was wrong.
So my question. Can anyone suggest how I should be handling my events so that my rendered grid is up to date and not showing these hidden rows. I have a feeling I am just doing things in the wrong place/order but this is my first real swim in the deep end of the asp.net pool. If any more information would be helpful let me know.
Thank you in advance for any help.
Well I think I have solved my own problem. Essentially what I have done is this:
1. On parent page_load I reload controls so that they show up on the screen.
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
LoadCycleControls();
return;
}
RetrieveParameters();
LoadRefinedNominationInfo();
LoadLookupLists();
LoadCycleControls();
}
2. On control page_load I check IsPostBack. If it's true I just return.
protected void Page_Load(object sender, EventArgs e)
{
if(IsPostBack)
{
return;
}
BindData();
cycleNumber.Value = _cycleNumber.ToString();
}
3. On parent save button click, which caused the post back, I do my normal save logic. After that is complete I iterate over all the controls I created set their data source to the updated dataset. In my control I exposed a method called BindData() which I then call.
protected void BtnSaveClick(object sender, EventArgs e)
{
SaveRefinedProductNosInfo();
var dataSet = RefinedProductsNomInfoCache;
if (dataSet == null)
{
return;
}
foreach (var nomControl in nomContent.Controls.OfType<RefinedProductNominationCycleControl>())
{
nomControl.GridDataSource = dataSet.REFINED_PRODUCT_NOS_CYCLE_INFO;
nomControl.BindData();
}
}
Now even though I am slightly new at this, it feels a little dirty which probably means I am not doing things quite right still so if someone actually knows whether I am doing this right or not cares to comment that would be great :)

ASP.Net : Need to run javascript on update panel load completed

I need to run a javascript function when the update panel is loaded completely(I want to scroll), and not on initial page load.
Please suggest.
Thanks
This is the way to get the end Event after the update.
<script type="text/javascript">
var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_endRequest(EndRequest);
function EndRequest(sender, args) {
}
</script>
Untested
<script type="text/javascript">
var app = Sys.Application;
app.add_init(ApplicationInit);
function ApplicationInit(sender) {
var prm = Sys.WebForms.PageRequestManager.getInstance();
if (!prm.get_isInAsyncPostBack())
{
prm.add_pageLoaded(PageLoaded);
}
}
function PageLoaded(sender, args) {
//Do something
}
</script>
If you are using AJAX then the only way i have found yet to give an alert to a user on return to the Asynchronous post back is to add an “end request” handler to the PageRequestManager.
In this way you can tell the request manager to run a javascript function on returning from a Asynchronous post back event of AJAX.
Code for doing this is :
function load()
{
Sys.WebForms.PageRequestManager.getInstance().add_endRequest(EndRequestHandler);
}
where “EndRequestHandler” will be the name of your javascript function you want to call.
Call the above function in Onload event of tag:
<body onload=”load()”>
function EndRequestHandler()
{
alert(“You record has been saved successfully”);
}
Now If you want to give a different message based on your logic in server side code (code behind) then you can use a server side Hidden Field:
<input id=”hdnValue” type=”hidden” runat=”server” value=”" />
Set its value in server side code on Asychronous Post Back:
Protected Sub btn_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnCreateSample.Click
If condition Then
hdnValue.value = “do this”
Else
hdnValue.value = “do that”
End If
End Sub
Now you can check the value of this Hidden Field in your Client Side EndRequestHandler function and give a different alert to user based on its value:
function EndRequestHandler()
{
if (document.getElementById(‘<%= hdnValue.ClientID %>’).value == “do this”)
{
alert(“You record has been saved successfully”);
}
else
{
alert(“There is an error”);
}
}
you can use below code with if jquery is used
This is to show saved message and hide that message after 5 seconds after update panel is updated
function pageLoad() {
window.Sys.WebForms.PageRequestManager.getInstance().add_endRequest(EndRequestHandler);
}
function EndRequestHandler()
{
window.setTimeout(function () {
var label = window.$get('<%= lblMsg.ClientID%>');
if (label != null) { label.style.display = 'none'; }
}, 5000);
}

Assyncronous interaction using Sys WebForms PageRequestManager

I'm trying to display a panel to the user when an asynchronous call is made, but only if that happend from a specific call.
using the normal "get control" script I have mine like:
function pageLoad() {
try {
var manager = Sys.WebForms.PageRequestManager.getInstance();
manager.add_endRequest(OnEndRequest);
manager.add_beginRequest(OnBeginRequest);
}
catch (err) { }
}
function OnBeginRequest(sender, args) {
//alert('Start\n\n' + sender + '\n\n' + args);
var p = document.getElementById('ajaxLoadingPanel');
p.style.visibility = 'visible';
p.style.display = 'inline';
}
function OnEndRequest(sender, args) {
//alert('End\n\n' + sender + '\n\n' + args);
var p = document.getElementById('ajaxLoadingPanel');
p.style.visibility = 'hidden';
p.style.display = 'none';
}
but my question is How do I know the methods of sender and args?
I went through the MSDN and they talk nothing about the methods we can use, and there is no intellisence in VS2008 for this part...
any ideas? I want to get a list of methods and properties for both sender and args that I can use of this javascript API.
This documentation is helpful:
http://msdn.microsoft.com/en-us/library/bb398976.aspx
It has a table of all the events on PageRequestManager and what their event args are. Then the event args documents their properties, etc. The sender is always the PageRequestManager.
Debug in ScriptDebugger and find out the contents of sender and args
you can identify that which control has caused the postback
To know which element caused postback, you can use args.get_postBackElement().id.

Resources