SharePoint 2013

How to Fix the SharePoint Modified Date to use Date and Time

If you’ve started using SharePoint 2013 you probably noticed that Microsoft changed the way they present the Modified value.  In SharePoint 2010 the Modified field showed a Date/Time stamp, but in SharePoint 2013 the Date/Time is replaced with something like “3 minutes ago”.  Personally I like this, but some users may not and the Date/Time stamp may be really important especially for Legal Departments or other Audited applications.

Fortunately there is a very simple fix, using the Client Side Rendering to override SharePoint’s default rendering of the Modified field.

The script is simple enough:

(function() {
var overrideCtx = {};
overrideCtx.Templates = {};

overrideCtx.Templates.Fields = {
‘Modified’: {
View: function(ctx) {
//var utcDate = new Date(ctx.CurrentItem.Modified);

return “<span>” + ctx.CurrentItem.Modified + “</span>”;
}
}
};
SPClientTemplates.TemplateManager.RegisterTemplateOverrides(overrideCtx);
});

As I’ve discussed in other blogs(here, here, and here) on CSR we use our self executing function and within it we create the Override Context (overrideCtx) object along with it’s Templates and Fields properties.  Within Fields we specify which field, Modified, and what form, View, we are managing the rendering for.  The nice aspect of this is that we can override the rendering on one or many forms and rely on SharePoint to handle the rendering for the forms we don’t want to override.

In the function for our form we simply return an HTML formatted string that should be displayed.  Using the browser developer tools you can view the argument passed to our View function as well as the CurrentItem’s properties and determine what value to display.  In the case of the ‘Last Modified’ Date/Time stamp the property we want to use is Modified.

Finally, in order to make SharePoint use our override template we pass our Override Context object to the RegisterTemplateOverrides and then add a reference to our JavaScript file to the Display Form’s JSLink property.

Advertisements

Client Side Rendering of Form Fields

I’ve been working on a site migration from SharePoint 2010 to SharePoint 2013 and a lot of what we did in 2010 was to customize forms the user interacts with.  One of the requirements we had was to ensure a Project Name and Project Alias field did not contain the same information.  In SharePoint 2010 this had been done by adding some JavaScript to the page, grabbing each control by HTML Element ID, and then comparing their values.  When we migrated these fields all got new HTML Element IDs so our validation logic was broken.

Obviously, we could go and update the JavaScript to use the new IDs, but if we migrated to another environment or performed and upgrade in the future we would probably have an issue again.  Instead SharePoint 2013 added Client Side Rendering which allows us to control the form’s rendering using JavaScript which would should allow our solution to be more portable and enable the field validation.

I have written a couple of other blogs about the Client Side Rendering of a View and Rendering of Specific Field(s).  While those were useful I found I was still missing a lot of information about how we could add the validation, what was needed to make sure values provided in the form were saved, and how to make the controls interact.

Before we begin a word of caution:  Once a Field Template is provided the template must provide the UI Controls for the user to interact with, a method to retrieve the value specified by the user, a method of displaying the previously specified value, and any validation INCLUDING if the field is required or not.  The example below will include elements of all of this, but your implementation may differ based on your scenario.

First, remember that we need to write good JavaScript that does not pollute the global JS space, so remember to wrap everything in your self executing function.

(function() {
//overrideContext code below
})();

Second, we are going to specify an override on the Edit Form for our specific fields, you may also want to do this on a new form but in our case the Project Alias was not available on the new form so we didn’t worry about it there.  Remember once we provide the override for the Field we are fully responsible for the type of input(s)/controls the user will have to interact, retrieving the value for SharePoint, and performing any ‘Required’ field validation along with any other custom validation we may want.  In order to provide the override in the proper format we must create our OverrideContext object with the proper properties.

var overrideCtx = {};
overrideCtx.Templates = {};

overrideCtx.Templates.Fields = {
‘ProjectAlias’ : {
EditForm: function(currentCtx) {
}
},
‘ProjectName’: {
EditForm: function(currentCtx) {
}
}
};

SPClientTemplates.TemplateManager.RegisterTemplateOverrides(overrideCtx);

At this point we have now specified that we want to override the ProjectAlias and ProjectName fields when the Edit Form is rendered.  However, since we have not returned any HTML formatted controls from either function if we placed all this in a JavaScript file and added it as the JS Link on the Edit form what would actually happen is the ProjectAlias and ProjectName input control wouldn’t exist.

Focusing on the ProjectAlias Field we can add the following to return an HTML TextBox for the user to make use of.

var ctx = SPClientTemplates.Utility.GetFormContextForCurrentField(ctxCurrent);
var controlId = ctx.fieldName+ “_davidmcwee_control”;

//Get Field Value, Value Validation, and Validation Error handling code will all get added here

return String.format(‘<input type=”text” id=”{0}” name=”{0}” />’, controlId);

Now we have a simple text box that will render because the function provided to EditForm is expected to return HTML that can be directly embedded in the page for rendering.  Also we are controlling the ID and Name attributes of our HTML Element so our validation later will be much easier.  While we have the control being rendered, if you actually try to provide a value nothing will get saved because we haven’t specified how to get the value from the control.  So before we return our HTML string we need to register our “getter” method so SharePoint knows how to get the value for our overridden field.

ctx.registerGetValueCallback(ctx.fieldName, function() {
return $get(controlId).value;
});

$get is a SharePoint provided function which return the HTML DOM object and is similar to the jQuery $(“#” + controlId).  I’ve used only the SharePoint functionality here to prevent confusion with other JS libraries.

Important thing to note:  The first argument to the register function is the Field’s Name, if you use any other value your function will still get called, but the value you return will not get applied to the field it should be associated with.  I originally used the controlId as the first argument but found the values were never saved, it took a lot of searching and trial and error to finally realize the issue.

Now that we can retrieve and save our control’s value we can implement validation.  In order to provide validation we need to create a Validator object that implements the Validate(…) function.

//Added the Field Validator just below the declaration of overrideCtx.Templates = {};
fieldValidator = function() {
fieldValidator.prototype.Validate = function(value) {
var isError = false;
var errorMessage = “”;

if($get(“ProjectAlias_davidmcwee_control”).value == $get(“ProjectName_davidmcwee_control”).value)
{
isError = true;
errorMessage = (“ProjectName and Project Alias are not allowed to be the same.”);
}

return new SPClientForms.ClientValidation.ValidationResult(isError, errorMessage);
};
};

In the above code you can see we did hard code the HTML IDs, while this was done in our dev code we did move to saving each of the Control IDs as properties so they could be retrieved later and the code would be more generic.  However, the idea is that we will get the two controls value’s and compare them, if they match we will set isError to true and provide a message back to the user.

Now we need to add our Validator to the Form’s list of Validators in association with our field and we also need to handle a validation error.

var validators = new SPClientForms.ClientValidation.ValidatorSet();
validators.RegisterValidator(new fieldValidator());
ctx.registerClientValidator(ctx.fieldName, validators);

These lines handle creating a validator set, so you can have multiple validators on a single field, adding the validator we created above to the set and registering the validator with the field.

ctx.registerValidationErrorCallback(ctx.fieldName, function(errorResult) {
SPFormControl_AppendValidationErrorMessage(controlId, errorResult);
});

These lines handle the Validation Callback, but this function is not always called.  This function is invoked when the input fails validation or if the previous attempt to save failed validation.  The nice thing is that all we really need to do, in this case, is pass along the results as well as the HTML Element ID to the SPFormControl_AppendValidationErrorMessage function.  You could consider adding other logic here to clear, update, or add suggestions to the user for possible “good” values if validation fails.  The errorResult object provided two properties errorMessage which is the message you specified, and validationError which is the Boolean value you specified in your Validation object.

Once all of this is added, you now have a functioning form override with field dependencies.  Here is the entire JavaScript file in PDF format for you to view.

I Hate SharePoint Apps like I Hate Mark Zuckerberg

This blog post has been tumbling in my head since I began working on SharePoint 2013 Apps.  This is probably the third time, at least, I have tried to express my thoughts on the development shifts in SharePoint from 2007 & 2010 to 2013.

Beware some things in this post may be offensive to people, especially Mark Zuckerberg, but I wanted to bring a little humor into the geek speak.

Do I Really Hate SharePoint Apps?

I think hating SharePoint Apps is like hating someone like Mark Zuckerberg for creating Facebook.  I don’t hate him for creating Facebook and making billions, I hate that I didn’t think of creating Facebook first.  I could have created a web site where we share things that should be kept to ourselves.

“… I meet this chick at the bar and we hooked up and now my _____ is all swollen and it burns when I …”,

WOW, I really didn’t need to know that, but oh great you also included a picture!  Because that image won’t be permanently burned into my memory from here until the end of time, THANKS Friend! And now to perform a lobotomy on myself.

Or where adults can act like immature teenagers by unfriending each other (please read with ditsy Valley Girl ‘accent’)

“Suzie unfriended you because your friends with Katie who just started dating Charlie even though she knew that Suzie liked Charlie and wanted to go out with him.”

Yeah, next time you read your Facebook feed I dare you not to think of this post!

But alas, Mark beat me to it.

So no, I don’t hate SharePoint Apps, but there are parts of them I haven’t fallen in love with, or even understand why they work this way instead of that.

Augmenting SharePoint or Bolting On

I was talking with a coworker recently and described my past, and current, experience with SharePoint and described it as “Augmenting SharePoint” either to improve the user experience (custom content types and lists to allow users to collect information consistently), build automation capabilities/processes (workflows that would handle publishing and retiring of content), or use data from other systems to enhance information in SharePoint (KPIs from Project Server along with Task Lists in SharePoint).

As my coworker pointed out, Apps are much less of the augmentation and much more of a bolt on.  Sure, you can borrow some of what SharePoint has in Apps, but your App isn’t going to be used in the same context and location that user created a document library or enabled/disabled features.  Our Apps are isolated, associated with SharePoint, but they aren’t SharePoint just like a Zynga game (or whoever makes your favorite Facebook game) isn’t Facebook and doesn’t change Facebook.

Change of Perspective

When I approached SharePoint Apps with the mindset that I was going to augment what SharePoint gave the user, I found nothing but frustration.  I would think first about what SharePoint could provide: lists for storing data, user security, etc. but I would quickly realize my App expected too much and that there was too little focus on my application.

I have now tried to spin that perspective 180 degrees, thinking first about what I want to build, maybe it as better calendar, and what it should do even without SharePoint.  Then after I knew what my App should do and how I was going to make it work I would think if there was anything I needed from SharePoint.

More customizations with Client Side Rendering

Recently I posted about how you can use Client Side Rendering (CSR) to display contacts on a map.  After posting about how to display the entire list data, I decided I wanted to see how CSR could  be used to change the user experience while adding, updating, and viewing list items, updating items, and viewing items.  This post will provide a high level overview of how I was able to change the display during New, Display, and Edit of an individual item and then later I will actually put this together with the Contact Map idea.

Where’s the Documentation?

As mentioned in the previous blog, this work was all pretty much done 100% in the dark.  I was able to find a few blogs about how to style specific fields, in particular those custom fields being added by a feature, but there really isn’t much about the full CSR capabilities.  In order to figure some of this stuff out I ended up using the IE Developer Tools Console to view various objects, in particular the SPClientTemplates.TemplateManager and SPClientTemplates._defaultTemplates JavaScript objects.

Specific Items mean Specific Field(s)

My original goal was to do something, really anything, with all the input fields.  However, to date, I haven’t been able to figure out how to get my CSR to change all the fields, but I have been able to impact specific field(s) and in the remainder of this post I will focus on impacting my custom field ‘Lat’.  This being said, the CSR does include a OnPostRender function which you can use to ‘go back’ and update the fields, but it doesn’t do anything while the field is being rendered.

CSRs need to self execute, and to prevent namespace pollution I’m using the self wrapping anonymous function.

(function() {
})();

We will again use the overrideCtx and overrideCtx.Templates objects to specify the various items we want to control.

var overrideCtx = {};
overrideCtx.Templates = {};

Unlike our Contacts on a List example this time rather than overriding the Item template we are going to override the Fields.  Fields is a bit different from the item in that rather than providing a function which is passed a context object, Fields is an object that specifies the field(s) we want to override during render.  For each field specified we can then provide our rendering template function which receives the current Field’s context.

overrideCtx.Templates.Fields = {

‘Lat’: {

‘NewForm’: function(ctx) { return (“<div style=’border: 1px solid blue;’>Hello World</div>”); }
‘EditForm’: function(ctx) { return (“<div style=’border: 1px solid green;’>Hello World</div>”); }

}

};

Initially, the names ‘NewForm’ and ‘EditForm’ which match up with the URL /NewForm.aspx and /EditForm.aspx caused me to assume the naming’s should use the name of the ASPX form.  However, ‘DispForm’ (/DispForm.aspx) did not provide the expected rendering and this is where the IE Developer Tools were critical.  Using the IE Developer Tools and the Console I was able to look at the SPClientTemplates._defaultTemplates where I was able to traverse the object structure and found the function ‘DisplayForm’.

Related

SharePoint Contacts on a Map with Client Side Rendering

SharePoint Contacts on a Map with Client Side Rendering

Several years ago, back in the dark days of SharePoint (MOSS) 2007, Tom Resing and I worked together on a demo displaying contacts from a SharePoint contact list on a Bing/Google Map.  He and I presented this at several SharePoint Saturday events (Boston, Virginia Beach, Richmond, Tampa) and found highly positive response.  It has been a while since Tom and I worked together, and a lot has changed in SharePoint so I wanted to revisit our old demo and take a newly available approach.

SharePoint 2007 & 2010

When Tom and I first worked together jQuery was early in development, HTML5 was only being discussed, and Chrome didn’t exist.  JavaScript was used a little, but because of the browser limitations it didn’t have the capabilities it has today, so SharePoint relied heavily on XML and XSLT to edit and customize the display of information.  The demo was remarkably simple but required significant work with XSLTs.  We would do the demo in SharePoint 2007 by adding a SharePoint DataView Web Part (DVWP) and customize the XSLT list and item rendering to add the map and geocode the items.  This worked well, but injecting JavaScript through an XSLT translation required HTML encoding of symbols like ‘&’ and ‘>’ which really made the JavaScript code very difficult to read and understand.

History Lesson: You can find Tom’s old slide deck here.

SharePoint 2013 – Client Side Rendering (CSR)

Today jQuery is a mature, and a common tools set, HTML5 is becoming more and more common, and business applications rely on JavaScript almost as much as Server Side code.  SharePoint 2013 introduced a new method, utilizing JavaScript, to provide rendering of lists rather than using the ‘old’ method of XSLT.  Given this improvement, I thought it was worthwhile to revisit the old demo, and give it a refresh.

Updated Demo

I have been unable to find a solid MSDN CSR API reference, but I can tell you CSR does NOT use the JSOM when executing so no need to perform context loads, queries, etc.  CSR actually seems to provide a JavaScript object that is a JSON’ized version of the List View and Rows so we can actually access row columns by using .[Static Row Column Name].

I’ve created a separate page where I could work with the list data and CSR to ensure I would be able to access my list even if the JavaScript wasn’t working and I would highly recommend others do the same at least during development.  Once your done developing, the CSR can be applied directly to a list/list view.  Also, on the page I added the Bing and jQuery references using a Script web part because I found that adding it in the CSR code did not guarantee that those files would actually be loaded.

From all the code examples I have seen, and JavaScript best practices, CSR files should have a self contained object so your variables and functions do not pollute the global namespace.  However, your CSR must be self executing, so begin with something like:

(function() {
})();

Now we need to create the Template Override object.  This object will be provided to and used by SharePoint to implement the rendering of the list and list items based on what areas we choose to override.

var overrideCtx = {};
overrideCtx.Templates = {};

Our template has to perform three main tasks:

  1. Add a Div that the Bing Map API can use to display the map tiles
  2. Capture each item in the List
  3. Initialize the map and add the geocoded items to it

In order to perform these task we will override the Header, Item, and OnPostRender.

One really nice aspect of the CSR is we can either call JavaScript functions, or we can return back HTML for rendering.  In the Header function we will just return the necessary HTML to add our div which the Bing API will use to display it’s map.  Add the following to override the Header

overrideCtx.Templates.Header = function(ctx) {

 return (“<div id=’mapDiv’ style=’position: relative; width: 450px; height: 450px;’></div>”);

 }

Next we want to capture each item in our list.  Because we don’t have the Bing Map loaded yet we will just store the items so once the Map and Search Manager are loaded we can the perform the geocoding and rendering.  To override our Items use the following:

overrideCtx.addressArray = new Array();
overrideCtx.Templates.Item = function(ctx) {

overrideCtx.addressArray.push({Title: ctx.CurrentItem.Title,
Address: (ctx.CurrentItem.WorkAddress + ” ” …)});

//This has been truncated for more efficient reading

}

Now that we have our Div and Items we can load the Map, Geocode the items, and add them to the display.  I’m going to avoid in depth discussion on how to work with the Bing Maps and Geocoding in this blog, but if you want more detail check out the Bing Map API.

To perform the initialization of the map and search I chose to use the OnPostRender, which ensures all other templating has been performed and is complete meaning everything I need to initialize and geocode is ready.

overrideCtx.OnPostRender = function () {

overrideCtx.Map = new Microsoft.Maps.Map(…);
Microsoft.Maps.loadModule(‘Microsoft.Maps.Search’, { callback: function() {


overrideCtx.geocodeRequest();

 }});

overrideCtx.geocodeRequest = function () {

$.each(overrideCtx.addressArray, function(index, val) {

var currentContact = {

where: val.Address,
callback: function (result, userData) {

var pushpin = new Microsoft.Maps.Pushpin(…);
overrideCtx.map.entities.push(pushpin);

},

};

});

}

Finally, now that our template is ready to be used we need to register it with SharePoint.  At the end of the self invoking function add:

SPClientTemplates.TemplateManager.RegisterTemplateOverrides(overrideCtx);

Use Our CSR

With that our CSR is ready, now add the CSR js file to your site (I prefer to use the SiteAssets library because I’ve had issues in the past with Document Libraries not always returning the expected HTTP headers).  On a page with the Contacts List View (which should include the Address, City, State, and Zip fields) edit the List View web part and expand the Miscellaneous section.  There you will find a new text box ‘JS Link’ where you can add the url to your CSR file.  The JS Link field allows you to also use the ~site url token to make referencing your file easier and ensure the path is properly formatted for SharePoint to load.

Once you’ve added the CSR the your JS Link Save your changes and enjoy the new Client Side Rendering.

If your interested in my actual CSR JS file you can download it in PDF format here.