Monday, 30 December 2013

ASP.Net Textbox - Adding Decimal Validation via JQuery

Technology:
 
ASP.Net Framework 4.0
JQuery
 
Its pretty frustrating that ASP.Net does not have built in 'decimal only' validation for texboxes. I attempted to create my own using simple Javascript, but my requirement was too complex. I needed to implement the following restrictions:
 
  • allow positive AND negative numbers (therefore numbers with a single '-' at the beginning, or with a single decimal point are allowed)
  • Validation independant of cursor location - if a number has been entered and the cursor is moved to the beginning the user may enter a negative symbol
  • No flash of invalid characters on keypress (so simple Javascript 'find & replace' won't work)
  • Allow backspace, enter, left/right arrows and other non character keypress events
 
I eventually stumbled across a neat solution at http://brianjaeger.com/process.php

To implement it, I added the jquery.limitkeypress.js file to my solution. Any textbox which required this validation was assigned the class 'decimal.' In my master page's javascript file, I had the following code to apply the jQuery to any textbox with a class of 'decimal' (I was using my own regex expression which can be passes as a parameter to the JQuery library):

// ^ - start of string anchor
// (-)? - match a '-', optional
// \d* - match zero or more digits
// \. - match a '.'
// \d{0,decPlaces} - match up to specified num of dps
// )? - decimal points are optional
// $ - end of string anchor
$('.decimal').limitkeypress({ rexp: /^(-)?\d*(\.\d{0,4})?$/ });





 

Passing Parameter values from code (C#) to SSRS

Technology:

Microsoft Visual Studio 2010 with C# & ASP.NET,  Framework 4.0
Microsoft SSRS 2005
Microsoft Sharepoint 2012

At some point, you may encounter a scenario whereby you need to pass a default value from an ASP.Net application (using C#) to an SSRS report parameter hosted on Sharepoint. For example, an application may have a 'View Report' button which takes the user to an external SSRS report hosted in Sharepoint. If the user is working with a unique set of data in their application, the report should ideally be filtered for this set of data also.

In Sharepoint, a report's URL will be:

http://<SharePoint_site>/_layouts/ReportServer/RSViewerPage.aspx?rv:RelativeReportUrl=/<SharePoint_Document_Library>/<Report_Name>.rdl




You can specify a report parameter name and value pair by explicitly specifying the prefix "rp:" (Note that the report parameter name must match the parameter name that is specified in the SSRS report). Here is an example to add-on a parameter with name "Month" that accepts a string value:
 
http://<SharePoint_site>/_layouts/ReportServer/RSViewerPage.aspx?rv:RelativeReportUrl=/<SharePoint_Document_Library>/<Report_Name>.rdl&rp:Month=January

You can specify multiple report parameter name and value pairs by explicitly specifying the prefix "rp:" separated by an '&' symbol: 
http://<SharePoint_site>/_layouts/ReportServer/RSViewerPage.aspx?rv:RelativeReportUrl=/<SharePoint_Document_Library>/<Report_Name>.rdl&rp:Month=January&rp:Year=2014
Multiple parameter name and value pairs can be concatenated together in a separate helper method utilising the StringBuilder class. This method can then return the full parameter string which can be appended to the main report URL in order to produce the full URL.
 
When the user clicks the 'View Report' button in the application, we can use the following statement to open the parameterised report in its report library:

ScriptManager.RegisterStartupScript(this.Page, this.Page.GetType(), "Open", String.Format("window.open('{0}');", <reportUrl>), true);



Tuesday, 24 December 2013

Using JQuery Draggable on ASP Panel & DOM Objects

Technology: 

ASP.Net (.NET Framework 4.0)
jQuery UI - v1.10.3
jQuery - v1.8.0

The .draggable() Jquery function allows DOM objects to be moved around the screen. After some failed attempts at creating my own Javascript to do this within my ASP.Net project, I stumbled upon this simple function, to both my relief and frustration that I had wasted so much time!

Firstly I had to download the jQuery 1.8.0 and JQuery UI 1.10.3 libraries and add these to my ASP.Net project. I then added reference to them in the scripts section of my Master page.

For my scenario, I needed to drag a panel which existed on a child page. I created the panel as follows:

<asp:Panel ID="contentPanel" CssClass="draggable" runat="server" Style="z-index: 125; left: 300px; position: absolute; top: 200px;">

Note the 'draggable' class. I then needed to link this panel to the JQuery method from the J Query UI library so it could be draggable; I created a javascript file for my ASP page and added it as reference at the top of my ASP page:

    <asp:ScriptManagerProxy ID="ScriptManagerProxy1" runat="server">
    </asp:ScriptManagerProxy>
    <script src="../../Scripts/CustomPage.js" type="text/javascript"></script>

Within the CustomPage.js file, I added the following code:

function pageLoad() {
    $('.draggable').draggable();
}

Provided all is set up properly, the draggable() method will be applied to all objects that have a class of 'draggable.' JQuery takes care of the rest.

Note that originally I had used $(document).ready() instead of pageLoad() to contain my JQuery call. This caused problems as I had so many Ajax Update Panels and partial postbacks happening - PageLoad() fires when the page is loaded (like  $(document).ready()),
but also for partial postbacks via update panels. I had been seeing problems with $(document).ready() because when a partial postback occurred, my JQuery association got dropped and it would only be recreated next time a full page load occurred i.e. in $(document).ready().


Sunday, 15 December 2013

SQL OUTPUT Clause

Technology: Microsoft SQL Server 2008 R2

Problem: I have a query which inserts multiple new records into an existing table. I need to retrieve the primary key IDs for these new records once they are inserted. I cannot use SCOPE_IDENTITY() as this returns only the last identity value inserted into an identity column.

The solution is to use the SQL OUTPUT clause. This clause has access to the INSERTED and DELETED virtual tables. In my scenario, I used OUTPUT with the INSERT clause, but it can also be used with UPDATE, or DELETE to identify the rows affected by these statements.

Firstly, I created a table variable to store off the new IDs for the inserted records. Note that you could also use a standard table or a temp table. Table variable worked best in my case.
DECLARE @NewIDs TABLE (Id int, CustomerName varchar(50))
I can then proceed to do my INSERTS via some SQL...
INSERT MyDestTable (CustomerName, Description, CreatedBy, CreatedDate)
OUTPUT Inserted.ID, Inserted.CustomerName INTO @NewIDs 
SELECT CustomerName, Description, SYSTEM_USER, GETDATE()
FROM MySourceTable 
The above query will select all records from 'MySourceTable' and insert them into 'MyDestTable.' (I've kept the select simple here, but in a real world scenario we would probably want to add a where clause or some joins to pull back only the records we need to insert, instead of the whole dataset). By adding one line between the INSERT and SELECT, I now have access to all the newly inserted records and their auto-assigned IDs:
SELECT Id, CustomerName FROM @NewIDs 

Preventing SSRS Autorun

Technology: SQL Server 2008 R2 Reporting Services

When developing a parameterised SSRS report using BIDS I had the requirement of specifying a default value for every filter. The report would be executed directly from SharePoint or called from an ASP web application which passed specific values through to the filters. In either case, the report was automatically running as soon as the user navigated to it - normal functionality if all parameters have values.
The problem was that the end users needed the ability to verify their parameters and change if necessary, before execution.
I searched for quite some time, looking for a property of the report where I could prevent auto-run, but nothing turned up. That left me with 2 solutions:

1 - Do not default one of the parameters so auto-run won't kick in i.e. force the user to have to choose one of their parameters. I didn't like this method as its extra work for the user and their original requirement was to have all parameters defaulted, so it would be a contradiction.

2 - Add a new parameter with no default value (to prevent auto-run) which allows blank values, meaning the user can simply ignore it. This was the better solution for my scenario, so I created a new parameter with the following configuration:



I called this 'System Use Only' so the users would know to ignore it. This parameter appears on the report as an empty text box, therefore forcing the users to hit Apply to see results:



Alternatively, you could make use of this text box to capture an electronic signature to display on the report for auditing, a time stamp, or some other user input which could show on the report and be printed with it.