Category: ASP.NET


I’ve been doing a lot of work recently with Telerik’s RadGrid configuration client side. This includes data binding, sorting, paging and working with columns and data rows. I’ll likely be doing a series on some of the issues I’ve encountered trying to work with these grids completely client side. The first of this series is a relatively simple thing to do server side, but I definitely had issue with it client side.

Scenario:

I have a RadGrid called rgProjects configured with several GridBoundColumn fields and a single GridHyperLinkColumn field. The data binding for this grid is being done via an ajax call to a method in another page that returns some json that I then bind to the grid. I’m leveraging the OnRowDataBound client event of this grid to perform some custom row manipulation. I figured this would be a good place to set up my HyperLink.

Step 1 - Add the GridHyperLinkColumn to the grid

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<telerik:RadGrid ID="rgProjects" EnableViewState="false" runat="server"
            GridLines="None" AutoGenerateColumns="False" AllowSorting="true" Width="100%">
            <MasterTableView TableLayout="Fixed"> 
                <Columns>
                    <telerik:GridNumericColumn DataField="ID" HeaderText="ID" />
                    <telerik:GridNumericColumn DataField="Title" HeaderText="Title" Display="false" />
                    <telerik:GridHyperLinkColumn DataTextField="Project" DataNavigateUrlFields="Project"
                        UniqueName="Project" HeaderText="Project" ItemStyle-Font-Underline="true" />
                </Columns>
            </MasterTableView>
            <ClientSettings>
                <ClientEvents OnRowDataBound="rgProjects_OnRowDataBound" />
            </ClientSettings>
</telerik:RadGrid>

The JSON that’s being returned:

[{"ID":"1204","Title":"shereen's test project","Project":"http://server.local/_layouts/Demo/editform.aspx?ID=1204"}]

So the basic idea was, I wanted my hyperlink to have it’s value set to: “shereen’s test project” and I wanted the url to be set to: http://server.local/_layouts/Demo/editform.aspx?ID=1204.

Do not confuse TITLE with VALUE. By TITLE, I mean the actual TITLE attribute of the A tag that’s used for a tooltip and by VALUE I mean the innerHTML that’s set and is actually visible to the user as the hyperlink itself.

So it would read as follows:

shereen’s test project

This was not working for me initially because both the hyperlink’s value and url were being set as the url, which is not what I wanted:

http://server.local/_layouts/Demo/editform.aspx?ID=1204

In comes the OnRowDataBound event where I can override what’s happening above with what it is I actually want:

Step 2 - Leverage the OnRowDataBound client event to configure our HyperLink

1
2
3
4
5
6
7
8
9
10
function rgProjects_OnRowDataBound(sender, args)
{    
    // manually set the hyperlink's title
    var item = args.get_item();
    var dataItem = args.get_dataItem();
    var link = item.get_cell("Project").getElementsByTagName("a")[0];    
    link.innerHTML = dataItem.Title;
    link.href = dataItem.Project;
    link.title = dataItem.Title;
}

So the key thing to note above is you have to set the innerHTML. Title is optional, but the important ones are href and innerHTML. Any problems let me know!

Building jQuery Tabs That Open & Close

jQuery is obviously a really powerful tool. If you’ve done any work with it, you don’t need convincing. My latest project involving jQuery was a bit tricky because I couldn’t find anything that detailed how to generate a tab once a user clicked on a link, and then how to close that tab if the user clicked the close button. Here is my setup:

  1. I needed to create a page with some static links, that when clicked on would spawn a new tab.
  2. The content area for each tab would contain a Close button that would remove the tab and hide the div contents. I didn’t want the div contents removed because I wanted users to be able to open the tabs again if they wanted to.

NOTE: I did attempt to dynamically generate the div contents by using a jQuery append statement on the content divs, but I ran into issues with this when placing a Telerik RadGrid onto the page and had to abandon that approach.

Building the above with the jQuery UI Tabs library took me part of the way there. In the end, my solution looks as follows:

Building the UI Tabs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<div id="mytabs"> 
   <ul>
      <li><a href="#tabs-home">My Projects Home</a></li>
   </ul>
   <div id="tabs-home">
      <h3>Welcome to My Projects Home</h3>
      <p><a href="#" onclick="showTab('myActiveProjects', 'My Active Projects')">My Active Projects</a></p>
      <p><a href="#" onclick="showTab('mySalesActivities', 'My Sales Activities')">My Sales Activities</a></p>
   </div>
</div>
<div id="tabs-myActiveProjects" style="display:none;">
    <h3>My Active Projects</h3>
    <p><input type="button" name="killTab" value="Close" onclick="hideTab('myActiveProjects')" /></p>
</div>
<div id="tabs-mySalesActivities" style="display:none;">
    <h3>My Sales Activities</h3>
    <p><input type="button" name="killTab" value="Close" onclick="hideTab('mySalesActivities')" /></p>
</div>

Wiring Up The Javascript

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function init()
{
    $("#mytabs").tabs();
}
 
function showTab(tabID, tabName)
{
    currentTabID = tabID;
 
    // this will add a tab via the standard method
    $("#mytabs").tabs("add","#tabs-" + tabID, tabName);
    $("#tabs-" + tabID).css("display","block");
 
    $("#mytabs").tabs('select', tabID);
}
 
function hideTab(tabID) 
{
    $("#tabs-" + tabID).css("display","none");
    $("a[href^=#tabs-"+ tabID +"]").parent().remove();
    $("#mytabs").tabs('select', 0);
}
 
$(document).ready(init);

Don’t forget to include the jQuery UI JS file and the corresponding CSS. You’ll also need to include the jQuery JS file as well. If you have any troubles with this, drop me a note.

1
2
3
<script type="text/javascript" src="jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="jquery-ui-1.7.2.custom.min.js"></script>
<link type="text/css" href="styles/smoothness/jquery-ui-1.7.2.custom.css" rel="stylesheet" />

My next step with the above is to relocate the Close button so that it is an ‘X’ image on the tab itself that when clicked on would close the tab. I’ll update once I figure that out! Good times!

JQuery AutoComplete extraParams and CheckBoxes

I love jQuery. I work with it quite a lot on various projects. One of the coolest features in my humble opinion is AutoComplete. There are a ton of different plugins you can work with, some are variations of others, but for the most part, they work pretty darn good out of the box.

I have been trying unsuccessfully over the past hour or so to pass in the value of a checkbox as a parameter to my AutoComplete plugin as follows:

1
2
3
4
5
cacheLength:0,
minChars:2,
max:20,
autoFill:false,
extraParams: { active : $('input[name=status]').is(':checked') }

Now the issue I was encountering was regardless of what the state of the checkbox was, checked or unchecked, the AutoComplete plugin always returned it’s initial value. So if by default it was unchecked, it always returned false. If by default it was checked, it always returned true.

After a bit of digging, I finally stumbled across this site that explains that the value is locked in once the AutoComplete plugin is initialized: http://stackoverflow.com/questions/1216222/jquery-passing-checkbox-values

So to solve the issue:

1
2
3
4
5
6
7
8
9
cacheLength:0,
minChars:2,
max:20,
autoFill:false,
extraParams: {
    active : function() { 
        return $('input[name=status]').is(':checked'); 
    }
}

Awesome! Thanks to Stack Overflow and redsquare!

How to Add a ToolTip to the Telerik Ajax RadEditor

Ok this one was not immediately obvious to me so I’m posting the solution here. I’m using a Telerik Ajax RadEditor on my page as follows:

<telerik:RadEditor ID="rhfNotes" EditModes="Preview" runat="server" ToolsFile="ToolsFile.xml">
</telerik:RadEditor>

Now, after doing a bit of inspection, I discovered there was a property I could set on the RadEditor called ToolTip that seemed to just require a string value as follows:

<telerik:RadEditor ID="rhfNotes" EditModes="Preview" runat="server" ToolTip="Some message to the user" ToolsFile="ToolsFile.xml">
</telerik:RadEditor>

I assumed this would produce exactly what I needed. Unfortunately, after testing the above out, I got nothing, no tool tip. Doing a search on the forums turned up nothing useful, not even an explanation as to what the ToolTip property was really for. However, I did come across an entirely separate control in the Ajax suite of controls called RadToolTip.

That’s clever I thought, perhaps I’ll just give that a go. I was hoping there would be some sort of property I would set that would allow me to specify what control to tie this tool tip to. Guess what! There is! My final solution was as follows:

<telerik:RadToolTip ID="rttNotes" runat="server" TargetControlID="rhfNotes" Text="Some message to user"></telerik:RadToolTip>
<telerik:RadEditor ID="rhfNotes" EditModes="Preview" runat="server" ToolsFile="ToolsFile.xml">
</telerik:RadEditor>

There you have it. I haven’t played around with all the properties and options I have available to me with the RadToolTip, but I’m sure there are some useful ones in there!

DevTeach Slides and Files

Hi All, I wanted to thank everyone who attended by DevTeach session yesterday on integrating the telerik controls with your SharePoint Custom Solutions. I hope at the very least everyone walked away with something new they had learned or didn’t quite realize was possible before.

If you’d like to view my slides again, there is a pdf version available for download at slideshare.net/shereenqumsieh.

As promised, I have uploaded the custom files I had created for the purposes of my demo. If you have any issues with using these, please let me know. Download Here.

The Vancouver IT community is hosting a DevTeach kick off party on Monday, June 8th. This is the official social event for DevTeach Vancouver so come socialize with us! The event is not just for the attendees of DevTeach Vancouver it’s a free event for everyone. It’s a unique chance for the attendees, speakers and locals to meet and talk over some free beer and pool. I’ll be there! The event will be held at the Soho location and you need to RSVP to attend.

To find out more visit this url: http://party.cuga.ca/Home.aspx

Greetings everyone! I am very excited to annouce that I have been selected to speak at the DevTeach conference that will be held here in Vancouver from June 8-12. I spend a great deal of time blogging about working with the Telerik web controls in my SharePoint development, so I figured this would be a good opportunity to share some of the things I’ve learned and to demonstrate how easy it is to integrate these into your projects.

This is a great conference that promises to be the biggest developer, DBA and ITPro conference in Canada. It’s jam-packed with advanced sessions (level 300 and 400) all on the latest versions of Microsoft products and technologies. I encourage you all to at least check it out and see if some of the other sessions or topics might appeal to you.

Hope to see you there!

Validating a PeopleEditor Control on PostBack

Let’s talk about validation and the PeopleEditor control. There doesn’t seem to be a consensus on how this is supposed to be done so I’ll outline my findings and what eventually worked for me.

I’ll start by explaining what I was attempting to do. I have a PeopleEditor control on a custom application page. My custom application page is located in the _layouts directory. On this page, I also have a submit button that saves my data to a SharePoint list upon submit.

Now, I need to ensure before submit, that the PeopleEditor control contains a valid entry. Blank and invalid values are not permitted.

I first attempted to set the AlllowEmpty property to false. However, that didn’t seem to help. If I clicked submit, the page would post back and then the control would display an error once the page reloaded. At this point, it was too late to be informing the user that there was a problem with their entry, the page had already posted back, so this was not useful.

I also tried setting the ValidationEnabled property to true. That didn’t seem to make any difference either. I am confused as to how these two properties are supposed to work.

My next attempt was to add an ASP.NET required field validator to the page as follows:

1
2
3
<wssawc:PeopleEditor AllowEmpty="false" ValidatorEnabled="true" Width="250px" ID="pePR" runat="server" SelectionSet="User" MultiSelect="false" />
 
<asp:RequiredFieldValidator ID="rfvPR" ControlToValidate="pePR" runat="server" ErrorMessage="Project Requestor (Cannot be blank)" Text="Cannot be blank." ValidationGroup="SubmitForm" Display="Dynamic"></asp:RequiredFieldValidator>

This took care of the client side validation that prevented the user from clicking submit without first entering a value into the control.

However, this did not handle the scenario when a user entered an invalid value in the control and hit submit. In this case, the form will attempt to submit and create the item, but will fail to save the value to the list item field because the value was invalid. An example of an invalid value would be bad data in that field.

To fix this, in my submit method, I added an IF statement to check how many resolved entities there were.

1
2
3
4
5
6
if (pePR.ResolvedEntities.Count > 0) {
    // continue with the submit
}
else {
    // output an error that the user did not enter a valid user
}

If anyone has any feedback, or has had success using the AllowEmpty property, please comment on this post or drop me a note. I’m interested in hearing how others were able to get around this issue.

If you’re building a production SharePoint environment (or even a development one), it’s probably a good idea to get a handle on the best practices for SharePoint databases stored in SQL Server. It will help to understand some key areas before deployment:

  1. Architecture Recommendations
    • Limit content database size to enhance manageability
    • Configure autogrowth settings
  2. Physical Storage Recommendations
    • Separate and prioritize your data among disks
    • Use multiple data files for large content databases and the SSP search database
      • Use multiple data files for content databases
      • Use multiple data files for the SSP search database
  3. SQL Server recommended practices

Blog do Ezequiel wrote a great article that details all of the above. I’ve simply summarized the key points above, but I encourage you to read his post in length. Microsoft has also published some useful resources on this topic (which Ezequiel talks about). I find the following link to be particularly useful:

Planning and Monitoring SQL Server Storage for Office SharePoint Server: Performance Recommendations and Best Practices (white paper)

If anyone has any recommendations for other useful resources pertaining to this topic, please let me know and I’ll include it above and credit your contribution.

How to Find the Server Control ID of a RadGrid

Let’s say you have 2 RadGrids defined in your aspx page. Both grids happen to share the same ItemDataBound event, but you’d like to apply a small tweak depending on what grid is calling the ItemDataBound method.

In order to implement your tweak, you’ll need a way to find the ID of the grid that made the call. And not the ASP.NET generated ID, since that can be rather ugly, but the ID of the control you created in the aspx page. The following example demonstrates how this can be achieved:

1
2
3
<radG:RadGrid ID="rgThisYearsItems" runat="server" OnItemDataBound="rgItems_ItemDataBound"></radG:RadGrid>
 
<radG:RadGrid ID="rgLastYearsItems" runat="server" OnItemDataBound="rgItems_ItemDataBound"></radG:RadGrid>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
protected void rgItems_ItemDataBound(object sender, GridItemEventArgs e)
{
        // we need to determine what grid is calling the itemdatabound event
        RadGrid grid = (RadGrid)e.Item.OwnerTableView.OwnerGrid;
 
        if (grid.ID == "rgThisYearsItems")
        {
            // perform some logic here
        }
 
        if (grid.ID == "rgLastYearsItems")
        {
            // perform some logic here
        }
}

The reason you might want to implement the above is for code reuse. If you’ve got two grids and the ItemDataBound event for both will be really similar minus a line or two, you can have them both call the same ItemDataBound event and use the above logic to determine when to run the custom pieces.

Thoughts?

Powered by WordPress | Theme: Motion by 85ideas.