How To Parse An Ajax [object XMLHttpRequest]

On June 18, 2010, in Web Design, by shereen

This is a quick post to summarize a couple areas of confusion I often see on the web surrounding Ajax and the XMLHttpRequest call. I think for myself, the best source of information that summarizes how this all works is the Javascript Developer Center over at Yahoo. In particular, this article: http://developer.yahoo.com/javascript/howto-ajax.html

So what is all this ajax hype? Let’s break it down based on the great summary from Yahoo:

In a traditional, non-AJAX web world, if your web application needs to get new data to update itself — even if that’s just a tiny bit of data — you write your page so that when new data is required a user action (a button click, for example) triggers the browser to make an HTTP connection (a form submission) back to the web server. The problem is that with each HTTP connection, a new page is reloaded. All the elements of the page are broken down and recreated each time while the user waits for the network and waits for the page to redraw. Its incredibly inefficient, slow, and not much fun for the user.

Great explanation.

Now, we use a lot of Ajax in our applications here at Black Ninja because of it’s efficiency, ease of use and simplicity. What I’d like to point out are the options and gotchas for parsing the XMLHttpRequest object (directly from the Yahoo article credited above, but summarized in bullet form. Anything in green are my comments):

  1. After the XMLHttpRequest call is complete, the response data is contained either in the responseText property, the responseXML property, or both. So if for example, you’re alerting on your response object, and the message box returns “[object XMLHttpRequest]“, the response data is either in response.responseText or response.responseXML.
  2. If the data you get back from the web service is in XML format, both responseXML and responseText are filled.
  3. If the data is in any other format, responseText is filled. However, whether responseXML gets filled is dependent on the browser and the Content-type the server returns (text/xml or application/xml). In practice, responseText seems to be more reliably filled across browsers and web services.
  4. If the responseXML property is filled by the XMLHttpRequest object, that property contains a Document object whose elements you can access in JavaScript using standard DOM methods (getElementsByTagName, etc).
  5. If your response format was XML but all you have is responseText, you will need to use an XML parser to get the information you need out of the XML text. Both Mozilla and Internet Explorer have XML parsers built in; see this tutorial from www.faqts.com for help in getting started.
  6. If your response was in JSON format parsing is perhaps easiest of all. JSON is short for JavaScript Object Notation — JSON is JavaScript. To interpret a JSON response just eval the response, and you’ll get a JavaScript object back:
    var myObj = eval ( xmlhttp.responseText );

    Once you have the data in hand you can update the page with standard JavaScript and DHTML methods. No need to reload or redraw the entire page — just modify the part of the page that needs the new data.

Super great summary, thank you Yahoo Developer Center!

 

For everyone who attend both my presentations this week on SharePoint 2010, Visual Studio 2010 and the developer productivity tools, a huge thank you for all the great feedback. I had a great time running both sessions and was happy to be able to interact with some of you after the sessions.

I received a lot of requests for posting the slides and demo scripts online and perhaps even a recording of the session itself. Good news, we do have a live recording available from the Vancouver SharePoint User Group session that ran during the evening. You can view the live recording here: http://vimeo.com/11150378.

If you’d like access to the powerpoint and the demo scripts, I’ve got good news there as well. They can be downloaded directly from here: Slides and Demos.

I will try to get back to everyone else that has emailed me since the session and left their business cards for more info within the next week! Thanks all.

 

This is a quick overview on how to add a column’s description to your custom edit and disp forms in SharePoint 2007.

List Name: Projects
Column Name: Status
Column Type: Lookup
Column Description: “Choose the status for this current project.”

To add a column to a form and display it’s contents, it’s pretty straight forward:

SPWeb web = SPContext.Current.Web;
SPList projects = web.Lists["Projects"];
SPListItem item = projects.GetItemById(Convert.ToInt32(Request.QueryString["ID"]));
 
// use this to grab the value, you can get either the ID or the Value in the column
SPFieldLookupValue status = new SPFieldLookupValue(Convert.ToString(item["Status"]));
lblStatus.Text = status.LookupValue;
 
// use this to grab the columns description, or any other property for that column
SPFieldLookup statusDesc = new SPFieldLookup(projects.Fields, "Status");
lblStatusDesc.Text = statusDesc.Description;

The above works great, but please note that the column name for the SPFieldLookup method requires the SharePoint Internal Field Name. So for example, if your column name was Project Status, and you created the column with the spaces, then it will be Project_x0020_Status.

Tagged with:  

Hiding columns in SharePoint is nothing new really, there have been several articles written on this topic. The approach for doing this, however, does inspire some debate in terms of what the best practice is. Let’s say we can agree that there are three ways to get this done:

  1. Using the built in content types to specify which columns you wish to be hidden.
  2. Using jQuery and a content editor web part to hide the columns as desired.
  3. Hide the columns programmatically using code.

I just wanted to make some comments on all three. The content type approach is a good one and relatively simple to implement. Once you’ve enabled content types for your list or library, click on the default content type, let’s say it’s Item, and choose the column you’d like to have hidden and simply set it’s column settings to Hidden. Here is an excellent reference for this technique: http://littletalk.wordpress.com/2009/03/30/hide-remove-title-column-from-sharepoint-list/.

Ok so the above works good, but what happens if you only want to introduce these hidden columns on your New and Edit forms but not your Disp form as an example. Or what if your scenario requires that they are hidden from all default New, Edit and Disp forms, but you have some custom SharePoint Designer disp forms that you’ve created that those fields need to be visible on. The content type approach will hide the column for all forms and so that won’t always work. We need something more granular.

So there is where the jQuery approach comes in handy. Some great resources for this:

As per the comments by Nathan Ahlstrom in the second link noted above, the final fix for me was to use:

<script type="text/javascript">
$(document).ready(function() {
    $('nobr:contains("Completion time")').closest('tr').hide();
    $('nobr:contains("Score")').closest('tr').hide();
});
</script>

Please note that I had to add quotes around the tr tag for this to work for me.

The final approach uses some custom code and the object model to hide columns for a given list. http://www.sharepointkings.com/2008/05/how-to-hide-column-of-sharepoint-list.html. Now I’m not entirely sure how this works with custom forms besides the New, Edit and Disp forms, and until I have time to try out, I won’t know the answer to that. It’s worth mentioning because it does give you some granularity in that you can specify hidden properties per form.

That’s all for now. Please send in your comments if you have them, would love to hear from you.

Tagged with:  

Heading to SPTechCon in February

On January 20, 2010, in SharePoint 2007, by shereen

I’ll be heading down to SPTechCon this February 10-12 in San Francisco and I’m looking forward to it for a variety of reasons. I’ll be participating as a Live Blogger once again and I’m really excited about this program that Mark Miller over at EndUserSharePoint.com has setup. It was a lot of fun at the SharePoint Conference ’09 and it’ll be just as great if not better this time around.

In case you weren’t following us at the conference late last year, this is your opportunity to get some of your questions answered through the live feeds. Sign up as a Live Blog Follower and the days of the conference you simply need to start submitting your questions. You can sign up using the following link: http://2010-02-10-sptechcon.eventbrite.com/. Also just before I head down there, I’ll be setting up the live feeds on my blog, so you can follow us here as well.

I think the social aspects of these conferences has changed quite a bit with the use of tools like twitter and live blogging and it makes that experience that much more enjoyable. I am eager to get down there and mingle with some of the SharePoint people out there. Hope to see some of you there!

Tagged with:  

Ok I thought I’d post on this because it stumped me for close to 2 hours. So in my scenario, I have a WSS 3.0 installation with several SharePoint Designer workflows built. Many of these workflows use the Useful SharePoint Designer Custom Workflow Activities solution available on codeplex. After doing a migration from one server to another, I found that when I attempted to open up my workflows that contained those custom activities, I would get an error:

Failed to load workflow.

Really frustrating error because it gives you absolutely nothing to go on. I do want to mention that I also tried building a brand new workflow and selecting one of these custom workflow activities and the behavior was odd. If i tried to add one as an ACTION inside my workflow designer, nothing would happen. No error, but the activity wasn’t added to the step either. It was as if my click/selection had no effect.

So I made the decision to completely remove and reinstall the custom activities. The codeplex solution comes nicely packaged using the SharePoint Installer, so all I had to do was run a remove and then a reinstall. Normally, a final step to getting this working according to the InstallGuide.txt is to:

Go to Central Administration -> Application Management -> Manage Web Application Features and activate the feature for desired web applications (usually it’s Sharepoint – 80 or Sharepoint – 443).

The odd thing was that I found this step was already done for me and the solution was listed as already deployed. So back to SharePoint Designer I went, double clicked on the .xoml file, damn, same error! I found several blog posts indicating that I should clear the SharePoint Designer cache. So I closed down SD, deleted the folders starting with 12.x.x.x and loaded SD back up. I tried to open my xoml file, still no luck, same error.

At this point I was getting pretty confused. I manually did a check of the Assembly to make sure it contained the DP.SharePoint.Workflow dll, I double checked the Features folder to make sure it contained the DP.SharePoint.Workflow folder and I make sure the .ACTIONS file was contained within the Workflow folder and that the permissions on it were not wonky. I also verified the web.config contained the safe control entries for that dll. All looked good to me.

FINALLY, I decided to compare my web.config against the old server’s web.config to make sure that I wasn’t missing anything. I did a quick search on DP and found that the old web.config contained one more entry than my new web.config did:

1
<authorizedType Assembly="DP.Sharepoint.Workflow, Version=1.0.0.0, Culture=neutral, PublicKeyToken=0298457208daed83" Namespace="DP.Sharepoint.Workflow" TypeName="*" Authorized="True" />

So it would appear that I was missing this authorized type necessary for custom workflow activities. How or why this did not get added when I did my reinstall, I have no idea. But once that entry was added back, I was good to go again. My workflows open just fine without error.

I hope this helps someone else out there!

Tagged with:  

jqGrid Text/Word Wrapping

On December 3, 2009, in Web Design, by shereen

Just a quick post for anyone else having this issue. I am working with the latest version of jqGrid, and I am dealing with cell data that is longer than the width of the cell making it difficult to see. I wanted to have this data wrap and the height of the cell adjust to fit the wrapped content.

I found a ton of useful info on the jqGrid forums but it didn’t quite get me there.

The forum article in the above link suggests that you add the follwing CSS to your page:

1
2
3
.ui-jqgrid tr.jqgrow td {
    white-space: normal !important;
}

The above worked great for FF, but in IE, it would wrap the content, but the cell height would not auto adjust and therefore you really couldn’t see the full content. So I made a couple more changes as per the code snippet below and this seemed to work for me.

So the height:auto forces the cell height to auto adjust based on the size of the wrapped content. I haven’t noticed any side effects of changing this. If anyone has I’d love to hear about it. The vertical-align:top ensures that the text positions at the top so that the cells with less content don’t disappear in the centre due to the larger cell blocks. And finally, I added a bit of padding so that my cells don’t look oddly aligned due to the vertical-align bit, but that’s optional. It’ll work without it.

1
2
3
4
5
6
.ui-jqgrid tr.jqgrow td {
    white-space: normal !important;
    height:auto;
    vertical-align:text-top;
    padding-top:2px;
}

If anyone else has run into this issue or has had to make a similar change, add your contribution to the comments below.

Tagged with:  

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!

 

jQuery – Get All Divs Whose ID Starts With

On November 12, 2009, in Web Design, by shereen

Structure:

1
2
3
4
<div id="thisismydiv1"></div>
<div id="thisismydiv2"></div>
<div id="thisismydiv3"></div>
<div id="thisismydiv4"></div>

To return an array of all divs that start with ‘thisismydiv’, you would use the following:

1
var divList = $("div[id^='thisismydiv']");

The above translates to, find me all divs whose id starts with ‘thisismydiv’. You could now do something cool like add a class to all those divs:

1
$("div[id^='thisismydiv']").addClass('myClass');
Tagged with:  

Just a quick thing to note, if you’re trying to write to the event log within your custom SharePoint solutions and run across this error:

Cannot open log for source {0}. You may not have write access.

This is definitely permissions related. A quick bit of searching and I found some useful info:

The CustomSD registry value for the Application event log is found under the HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\Applicationregistry key.  It is a string value which uses Security Descriptor Definition Language (SDDL) to describe which accounts have access to which functions (e.g. read, write, clear) of the event log.  By default the application event log will allow any IIS 6 application pool identity write access (either as a service logon or, in the case of custom accounts in the IIS_WPG group, as a batch logon). (reference: http://forums.asp.net/t/1131903.aspx)

So the key in the above paragraph is that the app pool identity already has permission to write to the event log, so instead of mucking around with permissions, I made sure my function for writing to the eventlog is elevated as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static void LogMessage(string message)
{
    SPSecurity.RunWithElevatedPrivileges(delegate()
    {
        if (!EventLog.SourceExists("SharePoint Custom Solutions"))
        {
            EventLog.CreateEventSource("SharePoint Custom Solutions", "Application");
        }
 
        EventLog.WriteEntry("SharePoint Custom Solutions",
                                    message,
                                    EventLogEntryType.Error);
    });
}