iPhone Detected, site running in minimal mode.
Home     Tags/Archives     Tweets     About Kevin

JS Injection for SharePoint List Forms

I’ve seen a few questions out on Twitter in the past few weeks on how to change SharePoint page behavior based on querystrings passed in an URL.  While the context for this question leads to many possible alternatives (filter web parts, custom web part, xslt, js, etc…)  I found that the advice I was giving in most cases was “if you just need something quick (and dirty), then just inject some javascript.  It seems though that arn’t many easily findable tutorials around for how to do this, so I decided to write this article.  Please note that this is NOT the best way to accomplish every possible problem scenario taking into account security, maintainability, performance, etc…  It does however work which makes it a viable tool to add to your bag of tricks in my book.  Also, I’m going to present the code samples here using straight javascript, but you could certainly streamline some of the code by using other frameworks like jQuery.

So to begin, the first thing we need is some javascript that can read the querystring and parse it into a JS array for us to use later.  There are a ton of these snippits all around the web, here’s the one I use:

function getQueryStringArray() {
    var qs = location.search.substring(1, location.search.length);
    var args = qs.split("&");
    var vals = new Object();
    for (var i=0; i < args.length; i++) {
        var nameVal = args[i].split("=");
        var temp = unescape(nameVal[1]).split('+');
        nameVal[1] = temp.join(' ');
        vals[nameVal[0]] = nameVal[1];
    }
    return vals;
}

Ok, so now we need a function to “find” the control we’re after on the page so that we can do stuff to it (like set it’s value, or hide it).  I have found that the easiest way of doing this is to look for an element that has the right TagName (e.g. “input”), the right SharePoint Datatype (e.g. “TextField”), and SharePoint FieldName (e.g. “Title”).  The TagName is easy, since that’s the actual tag of the element in the DOM.  The SharePoint Datatype is actually appended to the END of the ID attribute, so a little parsing will be required.  Finally, the SharePoint FieldName is the value assigned to the TITLE attribute of the element.  It would be cool if we could just key off this alone, but obviously on any given page you can’t guarantee all items will have a unique TITLE attribute.  Here is an example of an element that you may want to target on a form’s NewForm.aspx or EditForm.aspx pages:

<input name="ctl00$m$g_beee8c5c_b1a1_4356_84f5_
462f43dc6b4a$ctl00 $ctl04$ctl09$ctl04$ctl00$ctl00$TextField" type="text" maxlength="255" id="ctl00_m_g_beee8c5c_b1a1_4356_84f5_
462f43dc6b4a_ctl00_ctl04_ctl09_ctl04_ctl00
_ctl00_TextField" title="RelatedCT" class="ms-long" />

And here is an example function that you could use to parse the DOM and return the target element based on these three pieces of information:

function getFieldElement(tagName, identifier, title) {
  var len = identifier.length;
  var tags = document.getElementsByTagName(tagName);
  for (var i=0; i < tags.length; i++) {
    var tempString = tags[i].id;
    if (tags[i].title == title &&
            (identifier == "" ||
             tempString.indexOf(identifier) == tempString.length – len
            )
       ) {
         return tags[i];
    }
  }
  return null;
}

// So for Example, to return the target element above we’d make the following call
var theElement = getFieldElement(“input”, “TextField”, “RelatedCT”);

Once you have a handle to the element, you can do all sorts of things with it.  For exmaple, setting it’s value, making it readonly (if you don’t want to the user to change it’s value once you’ve populated it from the querystring), or even hiding the whole field all-together.  Here is an example function that can does all of the above (note, slight changes are required to work with non-textfields such as checkboxes, dropdowns, lookup lists, etc.)

function processField(theFieldName, theValue, setReadOnly, setHidden) {
    var el=getFieldElement("input", "TextField", theFieldName);
    if(el!=null) {
        if(theValue!=null) {  el.value=theValue;  }
        if(setReadOnly) {  theField.readOnly=true;  }
        if(setHidden) { 
            //Set the whole table row to not display (includes label and all)
            theField.parentElement.parentElement.parentElement
        .style.display="none";
        }
    }
}

Ok, now that we have all of our helper functions ready to go, we need to put them all in a JS file and drop that where it can be accessed from the form pages (or where ever you plan to do the injection).  Possible places to consider are a document library (if you don’t have physical access to the server) or  12/TEMPLATE/LAYOUTS/1033 (if you do have physical server access).  The nice thing about the later location is that you can either directly link to the script from anywhere via /_layouts, OR you can use the  <SharePoint:ScriptLink> tag to have SharePoint automatically generate a non-client-cachable link to the script.  You will also need to use the _spBodyOnLoadFunctionNames.push method on the pages to get SharePoint to correctly insert you “injected” code into the proper spot in the whole JS Init of the pages (remember there are all sorts of things SharePoint pages need to run before we get to your injected code).  When I edit/customize a list’s NewForm.aspx or EditForm.aspx page I generally like to inject this bit of code at the very top of the PlaceHolderMain content placeholder.  Here is an example that links to my saved helper functions from above, pushes a function onto the OnLoad chain, and then set’s the values and visibility of 3 fields from the querystring.

<asp:Content ContentPlaceHolderID=”PlaceHolderMain” runat=”server”>
     <SharePoint:ScriptLink runat=”server” Name=”ListFuncs.js”/>
     <script type=”text/javascript”>
          _spBodyOnloadFunctionNames.push(“processFields”);
          function processFields() {
               var vals=getQueryStringArray();
               processField(“TaskList”, vals[“List”], true, false);
               processField(“TaskID”, vals[“TaskID”], true, true);
               processField(“OriginalAuthor”, vals[“author”], false, false);
          }
     </script>
[ … rest of the form …]
</asp:Content>

While this article certainly was an exhaustive tutorial on how to do this form of SharePoint customization, I’m hoping it will be enough to get some of you started in the right direction and experimenting.


Comments

.

Tags

Hide Low Frequency Tags

Archives

Recent Posts