SP 2010: Customizing the forms for External Lists (BCS) in SharePoint 2010 by using Custom Field Controls and jQuery

Author: Tobias Zimmergren
http://www.zimmergren.net | http://www.tozit.com | @zimmergren

Introduction

As many of you know, customizing a form for a SharePoint list isn’t very tricky to do – but when it comes to modifying the forms for an External List it becomes a bit more of a challenge. In this article I will walk you through how the BCS (Business Connectivity Services) model can enable you to modify the New- and Editforms by creating and utilizing your own Custom Field Controls and I will also talk about how you can change the behavior and rendering of your DisplayForm using jQuery.

Related articles about BCS that may be worthwhile:

[blockquote]

  • SP 2010: Developing for SharePoint 2010 and Windows Azure – Part 1
  • SP 2010: Custom RSS provider for your BCS connected External Lists
  • SP 2010: BCS problem with AuthenticationMode and RevertToSelf
  • Access denied by Business Data Connectivity – Solution
  • SP 2010: Programmatically work with External Lists (BCS) using the Client Object Model
  • SP 2010: Programmatically work with External Lists (BCS) in SharePoint 2010
  • SP 2010: Getting started with Business Connectivity Services (BCS) in SharePoint 2010

    [/blockquote]

    Scenario

    So let’s pose that our scenario is that we’ve got a a source of data coming in through BCS and is represented like it’s always represented out of the box with BCS. What we would like to do is to customize the New- and EditForms to allow custom logic and we would also like to change how the DispForm behaves.

    In this sample we’ve got a very simplistic BCS model containing one entity with these properties:

  • Identifier (string)
  • Color (string)
  • Published (boolean)

    In SharePoint, our model is represented like this in the out of the box UI:

    Display Form New- and Edit Forms
    ScreenShot1530 image

    What we really want to achieve in this article is to manipulate the behavior of our Display- and New/Edit forms to look something like this:

    Display Form
    Published: Icon instead of Yes/No text.
    Color: Lit up with the selected color in the UI.
    New- and Edit Forms
    Color: Replaced with a custom field control
    image image

    As you can see in the last two images above, the result of our development is that we’ll be using a custom control (DropDown) instead of the standard TextBox for our Color-field, and we’ll change the way the Published-field looks in the Display Form. It should give you an idea of how you can customize and alter the behavior of your BCS External List Forms.

    So without further ado, let’s get started with modifying our forms!

    (I assume that you already have a BCS Model in place and will not iterate the steps for creating one here…)

    Modifying New/Edit forms: Custom Field Control to the rescue

    When it comes to the BCS Model, you should really always edit it through the XML and not through the Visual Studio UI. Start by right-clicking your BCS Model and selecting the "Open With…" alternative:
    image

    Then choose your favorite XML editor:
    image

    When you’re in this mode, you obviously have to be careful not to mistype or misspell anything as it can result in a broken BCS Model. Awesome :-)

    To cut it short, here’s an extract for the "Creating" Method, which references a Custom Field Control called ColorField:

                <Method Name="Create">
                  <Parameters>
                    <Parameter Name="returnEntity1" Direction="Return">
                      <TypeDescriptor Name="ReturnEntity1" TypeName="TOZIT.Samples.BCSExtensions.BdcModel1.Entity1, BdcModel1">
                        <TypeDescriptors>
                          <TypeDescriptor Name="Identifier1" IdentifierName="Identifier1" TypeName="System.String" />
                          <TypeDescriptor Name="Published" IsCollection="false" TypeName="System.Boolean" />
                          <TypeDescriptor Name="Color" TypeName="System.String">
                            <Properties>
                              <Property Name="SPCustomFieldType" Type="System.String">ColorField</Property>
                            </Properties>
                          </TypeDescriptor>
                        </TypeDescriptors>
                      </TypeDescriptor>
                    </Parameter>
                    <Parameter Name="newEntity1" Direction="In">
                      <TypeDescriptor Name="NewEntity1" TypeName="TOZIT.Samples.BCSExtensions.BdcModel1.Entity1, BdcModel1">
                        <TypeDescriptors>
                          <TypeDescriptor Name="Identifier1" IdentifierName="Identifier1" TypeName="System.String" CreatorField="true" />
                          <TypeDescriptor Name="Published" IsCollection="false" TypeName="System.Boolean" CreatorField="true" />
                          <TypeDescriptor Name="Color" TypeName="System.String" CreatorField="true">
                            <Properties>
                              <Property Name="SPCustomFieldType" Type="System.String">ColorField</Property>
                            </Properties>
                          </TypeDescriptor>
                        </TypeDescriptors>
                      </TypeDescriptor>
                    </Parameter>
                  </Parameters>
                  <MethodInstances>
                    <MethodInstance Name="Create" Type="Creator" ReturnParameterName="returnEntity1" ReturnTypeDescriptorPath="ReturnEntity1" />
                  </MethodInstances>
                </Method>

    As you can see above I’ve referenced a property called "SPCustomFieldType" in the code (Read more on BCS Custom Properties), which in turn is referencing something called "ColorField". The ColorField is my CustomField control that is simply a DropDown-box to be represented in the UI instead of the good’ol text box.

    Modifying Display Forms: jQuery to the rescue

    When it comes to modifying the DispForm of the External List, I’ve had several attempts with the documented RendererDefinition in the past and not one single time it worked for me nor any of my clients. So with that experience, I’ve resorted to using jQuery to modify the rendition of the Display Form. Obviously one could use jQuery for the New- and Edit Forms as well, if you want to.

    Short story, the jQuery looks like this:

    // Found this through google, but can't remember the source. 
    // Great script for string replacements!
    String.prototype.replaceAll = function (str1, str2, ignore) {
        return this.replace(new RegExp(str1.replace(/([\/\,\!\\\^\$\{\}\[\]\(\)\.\*\+\?\|\<\>\-\&])/g, "\\$&"), (ignore ? "gi" : "g")), (typeof (str2) == "string") ? str2.replace(/\$/g, "$$$$") : str2);
    };
    
    $(document).ready(function () 
    {
        // Render an icon instead of Yes/No text
        var publishedHtml = $('h3.ms-standardheader:contains("Published")').closest('tr').children(".ms-formbody").html().toString();
        publishedHtml = publishedHtml.replaceAll("Yes", "<img src='/_layouts/images/TOZIT.Samples.BCSExtensions/checked.png' />");
        publishedHtml = publishedHtml.replaceAll("No", "<img src='/_layouts/images/TOZIT.Samples.BCSExtensions/unchecked.png' />");
        $('h3.ms-standardheader:contains("Published")').closest('tr').children(".ms-formbody").html(publishedHtml);
    
        // Render the entire TD in the color that was chosen
        var colorHtml = $('h3.ms-standardheader:contains("Color")').closest('tr').children(".ms-formbody").html().toString();
        var colorHtmlTd = $('h3.ms-standardheader:contains("Color")').closest('tr').children(".ms-formbody").attr("style", "background-color:" + colorHtml + ";");
    });

    Essentially what this jQuery snippet does is that it will find the correct elements in the HTML markup that corresponds to my Fields (you see the :contains("Published") part? That’s where I find the Published-field in the markup). Then I simply alter the text that is sent to us from the server, replacing "Yes/No" with an image of a checked or unchecked checkbox. Pretty simple trick to light up the form a bit without the hassle of trying to get your RendererDefinition working…

    Tip: If you want to easily inject your jQuery to the External List Forms, I’d recommend using a DelegateControl override on the AdditionalPageHead. The code for my AdditionalPageHead DelegateControl looks something like this:

            protected void Page_Load(object sender, EventArgs e)
            {
                string httpRequestUrlString = HttpContext.Current.Request.Url.AbsoluteUri;
    
                // Note: You should create a smarter verification for when to load the scripts than to use a hardcoded value like I've done in this sample. 
                if ((httpRequestUrlString.Contains("/Lists/Sample Entity/") || httpRequestUrlString.Contains("/Lists/Sample%20Entity/")) && httpRequestUrlString.Contains("DispForm.aspx")) // Only render scripts if it's the Display Form on the Sample Entity list
                {
                    // Add a reference to jQuery if it isn't already loaded
                    ScriptLink.Register(this.Page, "/_layouts/TOZIT.Samples.BCSExtensions/Scripts/jquery-1.7.2.min.js", false);
                    ScriptLink.Register(this.Page, "/_layouts/TOZIT.Samples.BCSExtensions/Scripts/bcsDisplayFormScriptSample.js", false);
                }
            }


    The code snippet above simply checks the current request and determines whether it’s your specific list being loaded, and then also determine if it’s the DispForm.aspx file being served. As noted in the comments, you should modify this if-statement to suit your needs, should you decide to create a DelegateControl like this.

    Summary

    Working with BCS is both fun and challenging at the same time. Like most SharePoint projects your requirements always change, and there’s always a need for further investigating the possibilities for how we can deliver quality solutions. In this article I’ve talked about some tips for how you can modify the NewForm and EditForm of your BCS External List by simply using a Custom Field Control. I’ve also talked about how you can deliver customized forms using jQuery as in the DispForm sample above.

    As a final note I’d like to shout out to Scot Hillier who is a fellow SharePoint MVP and author of the Professional Business Connectivity Services in SharePoint 2010 book for valuable tips and awesome discussions regarding this topic.

  • Follow me

    Tobias Zimmergren

    Founder / Consultant / Advisor at TOZIT AB
    Tobias Zimmergren delivers high-quality articles about business and technology around the Microsoft scene.

    Tobias focuses on advisory and consultancy for the Office 365 and SharePoint offerings from Microsoft.
    Follow me
    • Pingback: SharePoint Daily » Blog Archive » SharePoint in the Cloud; Windows 8 is Enterprise Ready; Office 2013 on Windows Tablets()

    • Pingback: SharePoint in the Cloud; Windows 8 is Enterprise Ready; Office 2013 on Windows Tablets - SharePoint Daily - Bamboo Nation()

    • http://www.edocr.com/doc/42879/sharepoint-programmer-london Roger Fitzgerald

      Oh! Thanks. I want to modify display name and at last i found your blog i will use your coding for modify display name Thank you very much

      • http://www.zimmergren.net/ Tobias Zimmergren

        Hi Roger,

        I’m glad you liked it – I’m using the jQuery approach more and more since it’s so easy to modify the behavior of the forms this way.

        Thanks for reading.
        Tobias.

    • Keith Hamilton

      Using jQuery with BCS Update and Create forms offers a world of possibilities. My problem is that I am generating and deploying a BDCM file through Visual Studio 2010. I have no idea how to put a delegate control on a page that’s generated by an administrator via the creation of the External List. Perhaps I missed something. Can you elaborate? Thank you.

      • http://www.zimmergren.net/ Tobias Zimmergren

        Hi Keith,
        So I’m not entirely sure what your exact scenario offers. But what you’ll need to make sure if you want to use the conditional if-statement is to be able to fetch either the list name, url or other uniquely identifying artifact for the external list and external content type in order for the DelegateControl to use the if-statement as shown.
        Of course, one could always just let the script always execute without the if-statement in the Delegate Control’s Page Load, but that means it’ll be executing on every page request and look for the controls mentioned through the jQuery.
        Normally a Delegate Control is loaded on every page on the site where you activated i, so the reason for us having the if-statement right now is to make sure it doesn’t render the jQuery on all pages. In your scenario it might be worth a shot to just remove the if-statement and let the jQuery be published on every page (or include the jQuery in the .master and skip the Delegate Control altogether).
        Do some investigations on how long time the page takes to load with and without the jQuery to find out if it’s worth it or not. My guess is that it’s not a problem to remove the if-statement but of course that’s on a per-scenario basis :-)
        Hope that helps.
        Cheers,
        Tobias.

    • sivarajan

      I just want to show only date in the external list. Currently It showing both. Based on your example, I created a custom field and it will show only Date. When I add the custom field manually to any one of the custom list, it is working well. But I am getting below error with External list

      Field type DateOnly is not installed properly. Go to the
      list settings page to delete this field. This below meta data currently I am using in “Read List” and “Read Item”

      DateOnly true

      Please let me know that what the mistake in my code?

    • sivarajan

      Continue with previous post, the below code I am using

      DateOnly

      true

    • http://twitter.com/tartakynov Artem Tartakynov

      Hi Tobias,

      could you please share the code for this example? I was unable to reproduce your approach in my solution, it’s simply doesn’t work. I’m starting to think that there’s no way to use SPCustomFieldType with BCS create method

    • Pingback: SPFieldUrl does not work | Question and Answer()

    • shady ghanem

      I’m trying to add a rich text to the create form but with no success. Any help please.

    • Shaun

      Tobias, how would I replace a control with javascript? Can you give ma an example – I am looking to replace a text field with a drop down on the edit form.