Colin
Colin

Reputation: 309

Reporting Services auto scroll to an anchor when expanding

Reporting Services appears to believe it is being "helpful" by auto-scrolling the web page whenever a user expands a row group by clicking the plus sign. Short of hacking a Microsoft DLL, does anyone know a way to stop this behavior?

Searching around the net, I've found this years-old thread discussing the same issue, but no answer. I was hoping my friends at SO might be a little more knowledgeable.

Upvotes: 0

Views: 3938

Answers (4)

Rodrigo Matos
Rodrigo Matos

Reputation: 11

Just overright the reportviewer js native ScrollToTarget function into ReportViewerWebForm.aspx:

$(document).ready(function () { 
  Microsoft.Reporting.WebFormsClient._ReportArea.prototype.ScrollToTarget = function(){};
}); 

Upvotes: 1

demp
demp

Reputation: 12813

Worked for me when using with ReportViewer control 10.0.30319.1. Not very pretty as it touches the _ReportArea which is supposed to be private and eliminates ScrollToTarget function at all which may be needed in some scenarios. Alternative way is to access this function and \ or NavigationId property of the ReportPage via getting access to controls, but you need to know exact control id - in my case it is reportViewerDivId_ctl09, which is built from the client-side ID of the rsweb:ReportViewer Asp.Net control. See second example

Example 1:

$(window).load(function () {

    if (Microsoft && Microsoft.Reporting && Microsoft.Reporting.WebFormsClient) {
        var rpp = Microsoft.Reporting.WebFormsClient._ReportArea;
        if (rpp && rpp.prototype) {
            rpp.prototype.ScrollToTarget = function () { };
        } 
    }
});

Example 2:

/* DOESN'T WORK!*/
var rp = $get('reportViewerDivId_ctl09_ReportControl'); /*  rp.control is ReportPage */
rp[0].control.NavigationId = null; 
/*THE BELOW WORKED*/
var ra = $('#reportViewerDivId_ctl09'); /*ra[0].control is ReportArea*/
if (ra[0] && ra[0].control && ra[0].control.ScrollToTarget) {
    ra[0].control.ScrollToTarget = function () { }; /*overriding the function so that anoying scroll on Sort doesn't happen */
}

Upvotes: 0

Graeme Foster
Graeme Foster

Reputation: 151

I've just hit the same issue and put a dirty fix in place! I'm showing reports in my own custom ASP.Net page using the report viewer control. That helps me because I can put some additional script in my outer host page. Here's what I did:

I switched on MaintainScrollPositionOnPostback on my page as I'm lazy and just hijack their function to work out the scroll-bars y position.

I set an interval to capture the scroll-bars Y location every 50ms.

I attach an event handler to the load event of the SSRS IFrame which will set the scroll bar back to where it previously was.

When SSRS posts back the iframe load event occurs. At this point SSRS has annoyingly adjusted the scroll bar. My event handler kicks in and puts it back! It's pretty disgusting but does the job.

Code:

<script language="javascript">


    $(document).ready(function() {

        $('iframe').load(function() {
            resetScrollbar();
        });

    });

    var lastGoodScrollY = 0;
    var interval = window.setInterval(getScrollY, 50);

    function getScrollY() {
        lastGoodScrollY = WebForm_GetScrollY();
    }

    function resetScrollbar() {
        window.scrollTo(0, lastGoodScrollY);
    }

</script>

Upvotes: 1

Grzegorz Smulko
Grzegorz Smulko

Reputation: 2803

The clear solution is quite simple, if you know how to do it. ;)

All what you have to do is adding following code:

<script type="text/javascript" language="javascript">

    $(document).ready(function() {
        $('.A0').get(0).ClientController.CustomOnReportLoaded = function() {
            this.m_reportObject.m_navigationId = null;
        };
    });

</script>

where "A0" from $('.A0') is css class name assigned to ReportViewer control.

For reference I'm pasting method initializing ReportViewer control:

    protected void InitializeReportViewer(string ID)
    {
        string reportsPath = ConfigGetter.GetReportsPath();
        string reportingServerUrl = ConfigGetter.GetReportingServerUrl();

        Instance = new ReportViewer();
        Instance.ID = ID;
        Instance.CssClass += ID;
        Instance.ProcessingMode = ProcessingMode.Remote;
        Instance.ServerReport.ReportServerUrl = new Uri(reportingServerUrl);
        Instance.ServerReport.ReportPath = reportsPath + Config.Filename;
        Instance.Enabled = true;
        Instance.InternalBorderStyle = BorderStyle.None;
        Instance.EnableViewState = true;
        if (Config.AutomaticSize)
        {
            Instance.AsyncRendering = false;
            Instance.SizeToReportContent = true;
        }
        else
        {
            Instance.Width = Config.Width;
            Instance.Height = Config.Height;
        }


        Instance.ShowParameterPrompts = false;
        Instance.ShowToolBar = false;

        SetParameters();
    }

which is invoked for above example like:

    InitializeReportViewer("A0");

Below explanation, why it works:

ReportViewer control generates a lot of javascript code, which contains between others following:

function OnLoadReport(reloadDocMap)
{
    this.m_clientController.OnReportLoaded(this, reloadDocMap);

    if (null != this.m_navigationId && this.m_navigationId != "")
        window.location.replace("#" + this.m_navigationId);

    if (this.m_autoRefreshAction != null)
        setTimeout(this.m_autoRefreshAction, this.m_autoRefreshInterval);
}
RSReport.prototype.OnLoadReport = OnLoadReport;


function OnReportLoaded(reportObject, reloadDocMap)
{
    this.m_reportObject = reportObject;
    this.CurrentPage = reportObject.m_pageNumber;
    this.TotalPages = reportObject.m_totalPages;
    this.m_searchStartPage = reportObject.m_searchStartPage;

    // Update the client side page number so that it is available to the server object
    // if it was changed asynchronously.
    var clientCurrentPage = GetControl(this.m_clientCurrentPageID);
    if (clientCurrentPage != null)
        clientCurrentPage.value = this.CurrentPage;

    // If there is a document map, display it
    if (this.HasDocumentMap())
    {
        // This method is called each time the report loads.  This happens
        // for page navigations and report actions.  For many of these cases,
        // the doc map didn't change, so don't reload it.
        if (reloadDocMap)
        {
            if (this.CanDisplayBuiltInDocMap() && this.m_docMapUrl != "")
            {
                var docMapReportFrame = frames[this.m_docMapReportFrameID];
                docMapReportFrame.frames["docmap"].location.replace(this.m_docMapUrl);
            }

            this.CustomOnReloadDocMap();
        }

        if (this.m_docMapVisible && this.CanDisplayBuiltInDocMap())
            this.SetDocMapVisibility(true);
    }

    this.CustomOnReportLoaded();
}

Annoying scrolling is because of this part of code:

    if (null != this.m_navigationId && this.m_navigationId != "")
        window.location.replace("#" + this.m_navigationId);

So we need to set this.m_navigationId to null. Where?

Before this part of code this.m_clientController.OnReportLoaded method is invoked, and on it's end is invokation of method CustomOnReportLoaded(), so we just need to set null for m_navigationId in this method. And we are doing it. Voila!

Upvotes: 0

Related Questions