Second Life of a Hungarian SharePoint Geek

August 30, 2011

Inline editing internals – How to make only specific fields editable?

Filed under: Inline editing, SP 2010 — Tags: , — Peter Holpar @ 00:06

Recently I worked on a task that required me to dig deeper into the internal working and customization options of the new inline editing feature of SharePoint 2010. One of the requirements was to include several fields into a view, but enable users to edit only a few of them based on some conditions.

I found no documentation about customization possibilities of the inline editing, so I had to explore it for myself.

As we know inline editing can be turned on for a view by checking the Allow Inline Editing checkbox on the Edit View page.

image

For this post I’ve created a simple list that includes a Title field, a Text, a Choice, a Person or Group field called Owner, a Date field, and two numeric fields called Num1 and Num2. I’ve enabled inline editing for the view. The following screen shows the default rendering of the inline editing mode (insert mode).

image

I’ve added a new item to illustrate edit mode as well:

image

It’s easy to find out that the above setting corresponds to the InlineEdit property of the SPView class. The type of this  property is String and as defined in the documentation its value is “true if the view is in inline edit mode; otherwise, false. The default value is false.”

After analyzing this property in Reflector it turned out that its value is used in the ResolveAutoMode method of the XsltListViewWebPart where the AutoMode property (bool) of  BaseXsltListWebPart is set based on the existence of this value (string is null or empty) and in the CreateChildControls method of the DataFormWebPart class where its value is compared to “true”.

(InlineEdit is persisted for the view in the XsltListViewWebPart/XmlDefinition/View/InlineEdit)

Finding the AutoMode property was a great help to solve the problem as it helped me to find the AutoModeHeader and AutoModeForm templates in vwstyles.xsl (C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\LAYOUTS\XSL). During the XSL transformation the AutoModeHeader template is called first, then the AutoModeForm template is called for each fields.

To achieve our goal, we will customize the AutoModeForm  template. Its original version looks like this:

  1. <xsl:template name="AutoModeForm">
  2.   <xsl:param name="thisNode" select="."/>
  3.   <xsl:param name="Position" select="1"/>
  4.   <xsl:param name="Fields" select="."/>
  5.   <xsl:param name="mode"/>
  6.   <xsl:variable name="ID">
  7.     <xsl:call-template name="ResolveId"><xsl:with-param name="thisNode" select ="$thisNode"/></xsl:call-template>
  8.   </xsl:variable>
  9.   <xsl:variable name="IDField">
  10.     <xsl:choose>
  11.       <xsl:when test="$EntityName != ''">BdcIdentity</xsl:when>
  12.       <xsl:otherwise>ID</xsl:otherwise>
  13.     </xsl:choose>
  14.   </xsl:variable>
  15.   <td class="ms-vb" onkeydown="CoreInvoke('HandleInlineEditKeyDown',this)">
  16.     <xsl:choose>
  17.       <xsl:when test="$mode='Insert'">
  18.         <SharePoint:FormField runat="server" id="ff{count($Fields) – position()}{$Position}" ControlMode="New" FieldName="{@RealFieldName}"
  19.                               __designer:bind="{ddwrt:DataBind('i',concat('ff', string(count($Fields)-position()), $Position),'Value','ValueChanged',string($IDField),'', string(@RealFieldName))}"/>
  20.       </xsl:when>
  21.       <xsl:otherwise>
  22.         <SharePoint:FormField runat="server" id="ff{count($Fields) – position()}{$Position}" ControlMode="Edit" FieldName="{@RealFieldName}" ItemIdAsString="{$ID}"
  23.                               __designer:bind="{ddwrt:DataBind('u',concat('ff', string(count($Fields)-position()), $Position),'Value','ValueChanged',string($IDField),ddwrt:EscapeDelims(string($ID)), string(@RealFieldName))}"/>
  24.       </xsl:otherwise>
  25.     </xsl:choose>
  26.     <SharePoint:FieldDescription runat="server" id="ff{count($Fields) – position()}description{$Position}" FieldName="{@RealFieldName}" ControlMode="Edit"/>
  27.   </td>
  28. </xsl:template>

Before making any modification of the files, I suggest you to create a subfolder in the XSL folder (let’s call it inline in this example) and copy both the main.xsl and vwstyles.xsl files there. Now we can safely edit the files.

First, open main.xsl and update the href attribute of import node to match the location of the copied file:

<xsl:import href="/_layouts/xsl/inline/vwstyles.xsl"/>

Next we have to change the reference to the XSL file in our view. To do this, we start SharePoint Designer, and open the site, the list, and the source of the view (in my case AllItems.aspx).

Locate the GhostedXslLink attribute of the XsltListViewWebPart (default value should be main.xsl), and modify it to point to our new main.xsl version:

GhostedXslLink="inline/main.xsl"

You should also create an XslLink node for the XsltListViewWebPart/XmlDefinition/View node:

<XslLink>inline/mainx.xsl</XslLink>

(AFAIS GhostedXslLink helps SPD to render a preview for the view, while XslLink directs the SP rendering engine to the correct XSL, sometimes I set XslLink as an attribute for the view as well)

Note I: It is important to check the InlineEdit node of the view and set it to TRUE if it is FALSE.

<InlineEdit>TRUE</InlineEdit>

If we save the view and refresh the page, we should not see any difference, as we have not altered the AutoModeForm template yet. So let’s do it now!

The original AutoModeForm template uses the FormField control. In Insert mode this control is used with ControlMode set to New:

<xsl:when test="$mode=’Insert’">
  <SharePoint:FormField runat="server" id="ff{count($Fields) – position()}{$Position}" ControlMode="New" FieldName="{@RealFieldName}"
                        __designer:bind="{ddwrt:DataBind(‘i’,concat(‘ff’, string(count($Fields)-position()), $Position),’Value’,’ValueChanged’,string($IDField),”, string(@RealFieldName))}"/>
</xsl:when>

However, in Edit mode, ControlMode is set to Edit:

<xsl:otherwise>
  <SharePoint:FormField runat="server" id="ff{count($Fields) – position()}{$Position}" ControlMode="Edit" FieldName="{@RealFieldName}" ItemIdAsString="{$ID}"
                        __designer:bind="{ddwrt:DataBind(‘u’,concat(‘ff’, string(count($Fields)-position()), $Position),’Value’,’ValueChanged’,string($IDField),ddwrt:EscapeDelims(string($ID)), string(@RealFieldName))}"/>
</xsl:otherwise>

Now we should find out how to display the fields in display mode even if the item is edited / inserted. First idea was we should use the FormField control but set ControlMode to Display.

If we try it out:

<SharePoint:FormField runat="server" id="ff{count($Fields) – position()}{$Position}" ControlMode="Display" FieldName="{@RealFieldName}" />

it seems to work in “edit” mode:

image

but it will produce the following strange result in “insert” mode:

image

Note II: if your web part renders the same strange result for edit mode (see below) it may be due to that you have not set the InlineEdit node correctly to TRUE using SDP (see Note I above).

image

Note III: after altering and saving the XSL files, you should force SharePoint to re-read them by restarting the application pool (or IISRESET).

The reason for the result we seen above is that in this case the PreviewValueTyped property of the given field type is rendered. For an SPFieldText it is “FieldName field value.”, for an SPFieldNumber it depends on the number of decimal places configured for the field, but typically similar to 1,234.56, for an SPFieldDateTime the current date, etc. For the exact code you can check the RenderFieldForDisplay method ItemFieldValue getter method of the BaseFieldControl that is the base class of the FormField control. (Note IV: based on the context of your XsltListViewWebPart and list items you may end up with the value of the DefaultValueTyped property as well.)

Our next try is the FieldValue control:

<SharePoint:FieldValue runat="server" id="ff{count($Fields) – position()}{$Position}" ControlMode="Display" FieldName="{@RealFieldName}" />

The following screens show the “edit” and “insert” modes. The empty row on the second one illustrates the read-only “insert” mode.

image

image

Note V: If your field has no default value, it might be easier and I really suggest you not to use any control for that field. On the other hand, neither of these methods handles default values on item creation.

You may ask what is it good for to have a full read-only inline editor. You are right, so we add some simple conditions here. Be In this simple example we will decide if the field is editable based on the field name (@RealFieldName) and the inline edit mode ($mode).

  1. <xsl:choose>
  2.  
  3.   <xsl:when test="(@RealFieldName='Text' or @RealFieldName='Title') and $mode!='Insert'">
  4.     <SharePoint:FieldValue runat="server" id="ff{count($Fields) – position()}{$Position}" ControlMode="Display" FieldName="{@RealFieldName}" />
  5.   </xsl:when>
  6.  
  7.   <xsl:otherwise>
  8.     <xsl:choose>
  9.       <xsl:when test="$mode='Insert'">
  10.         <SharePoint:FormField runat="server" id="ff{count($Fields) – position()}{$Position}" ControlMode="New" FieldName="{@RealFieldName}"
  11.                               __designer:bind="{ddwrt:DataBind('i',concat('ff', string(count($Fields)-position()), $Position),'Value','ValueChanged',string($IDField),'', string(@RealFieldName))}"/>
  12.       </xsl:when>
  13.       <xsl:otherwise>
  14.         <SharePoint:FormField runat="server" id="ff{count($Fields) – position()}{$Position}" ControlMode="Edit" FieldName="{@RealFieldName}" ItemIdAsString="{$ID}"
  15.                               __designer:bind="{ddwrt:DataBind('u',concat('ff', string(count($Fields)-position()), $Position),'Value','ValueChanged',string($IDField),ddwrt:EscapeDelims(string($ID)), string(@RealFieldName))}"/>
  16.       </xsl:otherwise>
  17.     </xsl:choose>
  18.   </xsl:otherwise>
  19. </xsl:choose>

If we are not in insert mode, we will set Text and Title field to read-only:

image

In this case, the “insert” mode is fully editable:

image

What kind of more advanced conditions can we use to decide if the field should be displayed in edit mode or not? Originally I planned to create a really powerful solution injecting my custom data and functions as Waldek did for Content Query Web Part. Unfortunately there is a significant difference between CQWP and XsltListViewWebPart, namely the second is implemented as a sealed class, so we cannot inherit our custom classes from that. Despite this I almost succeeded doing something very similar, but that is another story worth its own post.

However, there is a lot of XSL parameters you can use, just check the main.xsl, or the existing conditions in vwstyles.xsl.

Just to name a few, you can try to play inserting these ones in your template to display their values:

To get the view name:

<xsl:value-of select="$XmlDefinition/@DisplayName"/>

The full XML definition:

<xmp>
    <xsl:copy-of select="$XmlDefinition"/>
</xmp>

The node we currently working on:

<xmp>
    <xsl:copy-of select="$thisNode"/>
</xmp>

All of the rows from the view:

<xmp>
    <xsl:copy-of select="$Rows"/>
</xmp>

If you would like to learn more about inline editing, you should check the following files as well (in folder C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\LAYOUTS):

INPLVIEW.aspx
INPLVIEW.js
INPLVIEW.debug.js
(that is a human-readable version of the former one)

Advertisements

6 Comments »

  1. cool!
    i’m really more intersted in how do you add custom functions for xsltlistviewwebpart 🙂

    Comment by EricWang (@EricInBj) — September 1, 2011 @ 09:20

  2. Hello,

    First i want to say that you have a very nice Sharepoint blog. One of the best i`ve read so far.
    I have a question about the xsl vwstyles.xsl .
    I tried to make the ControlMode attribute dynamic.
    ControlMode=”Edit”
    Can i use javascript, for example a function defined in inplview.debug.js say getControlMode(fieldName) that would return
    a string : ‘Display’ or ‘Edit’ ?

    I tried ControlMode=’javascript:getControlMode(fieldname)’, but it does not recognise the javascript tag.

    I also tried to make it an xsl attribute

    getControlMode(‘test’);:
    but it does not work.

    Is there any way to do this?

    Thanks,

    Dan

    Comment by techyardn — March 14, 2012 @ 14:11

    • Hi,

      Thanks for your feedback on the blog!

      As far as I remember I did something similar last summer. You should render the field both in Display and Edit modes and hide / display them on demand using jQuery.

      Peter

      Comment by Peter Holpar — April 9, 2012 @ 20:20

  3. Thanks Peter,

    Indeed i have resolved my issue with jquery + cewp .

    Dan

    Comment by techyard — April 9, 2012 @ 20:46

  4. Glad I found this article. Thanks for all the detail you’ve provided here. For what it’s worth, there’s a big button in SPD that toggles ‘Inline Editing’ on/off which essentially adds the InlineEdit element to the ViewStyle for you.

    Comment by bkwdesign — June 20, 2012 @ 21:18

  5. This is really cool. One thing I’ve found annoying with inline editing is that you have to turn it on one by one for all views. Have you or anyone found a way to enable inline editing for all views in a single site or list/library either through powershell or some other method? We have hundreds of views that were implemented before I came along.

    Comment by Isha — July 24, 2012 @ 14:45


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Blog at WordPress.com.

%d bloggers like this: