I am honoured to have been invited back as one of the speakers of SharePoint Saturday UK.
This is a FREE annual event (so far held in the UK midlands) towards the end of the year and always includes a tonne of awesome content for developers, IT Pros and power users, and this year is no exception.
This year it will be held at the Hinckley
Island Hotel, Hinckley, Leicestershire on the 9th November. As usual there are loads of great sessions and some really excellent seasoned speakers of international fame.
I'm will be speaking in the DEV track about Developing custom templates for the Content Search Web Part in SharePoint 2013, but definitely check out the full schedule and speaker list.
The event is always concluded with a SharePint and a good night out so if you are UK based (or fancy travelling over for the day) make sure you register for the event and hopefully I'll see you there!
If you are avid on twitter then be sure to keep an eye on the #SPSUK hashtag for all the latest event updates.
Monday 30 September 2013
MSDN Azure credits... its not for "you", its for "us" ...
So I recently found out about a great new set of offers that Microsoft are offering for all MSDN subscription owners called "Windows Azure Benefit for MSDN Subscribers". You basically get free Azure credits every month and discounted pricing.
For most SharePoint development and testing teams you will be looking at the top two, although much more expensive the Premium ($2.5k per year) and Ultimate ($4.2k per year) these are the MSDN subscriptions which include Office and SharePoint software for development and testing purposes (check out the MSDN Edition comparison for more details). There are other options out there but a lot of development teams will be using MSDN.
Equally if you are doing SharePoint development which in the Azure world will typically mean an "Extra Large" VM (8 Cores and 14GB RAM). This rolls in at $0.48 per hour of operation, and probably raises another major point ... only 14GB RAM?
With Windows 8 Hyper-V (free) and VMWare workstation (around $100) and most contractors running insane dual-SSD 32GB laptops you gotta wonder, why would I want a 14GB VM in the cloud when I can run a 24GB VM locally? Also .. what happens if I am on a train / airport lounge / plane and can't access the internet?
Well .. good point ..
$100 a month is great, but Azure VMs are very expensive!
Now, I know a few contractor friends of mine in the industry who have looked at this and decided that its not for them .. I am one of them (yes that is right .. I'm advocating a new service which I myself am not going to use).
But this is not really for the sole contractor, and certainly not someone who works all of gods hours (either doing research, writing books or blog posts and preparing for conferences and user groups).
Now this is where the average contractor gets off the Azure train. If you are very busy and put in a lot of extra hours it is not uncommon to run your VM for 12 hours a day plus some conference / user group work at weekends ... this can quickly add up*
* note - I realise not everyone works these kinds of hours .. I personally don't, I have a wife and baby daughter at home and generally work a 9-5 work day .. but I know some people work longer hours, and I sure put in extra time when prepping for conferences
5 days a week @ 12 hours per day, plus another 12 hours over the weekend = 72 hours per week
72 * $0.48 = $34.56 per week
$34.56 * 52 = $1,797 per year
$1,797 / 12 = $149.76 per month
So if you are rolling with MSDN Premium you are going to be out of pocket, and even if you are lucky enough to be an MVP (and have MSDN Ultimate) or just have deep pockets .. you are still scraping the barrel and probably watching the clock every week to make sure you don't go over the limit.
"You" are not their target audience ... "We" are ..
I suppose this really rounds to my core point .. this subscription model is not aimed at the individual developer or contractor. It is aimed at development teams. The place I'm currently at has 5 developers working in three different countries all running MSDN Premium. This gives them a combined allowance of $500 per month of Azure credits.
Being an office-based development team it pretty much runs off standard office hours. The development machines only need to be on for office hours (typically 8am - 6pm unless there is a major version launch coming up) and almost certainly don't need to run at weekends. With a group of users you can also look at consolidating your infrastructure (why not run a shared SQL instance so you can drop your VM hardware?). Equally you probably don't need to run all of the services all of the time on every development machine (if you aren't building a search solution then turn it off!).
With $500 per month to spend they can run 5 XL VMs 9am-5pm every week for free (some weeks you won't need to have all 5 machines running .. so turning them off when you aren't using them can help to pay for those other times when you need to run them for longer!).
Even if you do use more horsepower than that .. try putting the figures in front of your IT Manager / Head of Infrastructure ... You might be surprised how happy they are to pay for the "extra" over and above those free Azure credits (some months it might cost you an extra $100 or so .. some months you won't have to pay anything ... compare that to other hosting providers and see how much it would cost you!)
How about using it for testing?
One of the other big boons (and possibly the reason I might use a farm like this) is for testing.
It doesn't really matter how powerful your laptop is, you are never going to be able to build a truly enterprise farm on it (with redundancy in all places and all of the lights and switches turned on). The same credit you get in Azure could be used to model and build massive farms you could use for testing new topologies, or testing load balancing scenarios, or performance and load testing?)
Don't forget, you only pay for the machines while they are turned on so instead of running 1 XL VM for 20 days a month .. why not create 30 Large VMs and run them for 5 days a month of testing?
Conclusion...
Well, this is a very interesting move from Microsoft .. and stacked up alongside their hosted Team Foundation Server offering this does create a very attractive and extremely low-cost cloud-based development scenario.
It encourages people to stick with MSDN and give Azure a go for development and testing, and I'm sure this will end up leading to many companies taking a much closer look at how Azure works for their production environments as well.
For me ? Well .. I might well use it for the next time I do a Kerberos / Load Testing presentation (the idea of setting up a massive 20 server farm to run for a few days for free sounds pretty cool and a great learning experience to boot).
If nothing else, I'm tempted to setup a VM which I leave turned off and only use it in emergencies (my laptop is broken / stolen or my VMs are dead for some reason).
Either way .. if you have an MSDN subscription, head over and take a look. You might be surprised how useful it is!
- MSDN Ultimate - $150 per month
- MSDN Premium - $100 per month
- MSDN Professional - $50 per month
For most SharePoint development and testing teams you will be looking at the top two, although much more expensive the Premium ($2.5k per year) and Ultimate ($4.2k per year) these are the MSDN subscriptions which include Office and SharePoint software for development and testing purposes (check out the MSDN Edition comparison for more details). There are other options out there but a lot of development teams will be using MSDN.
Equally if you are doing SharePoint development which in the Azure world will typically mean an "Extra Large" VM (8 Cores and 14GB RAM). This rolls in at $0.48 per hour of operation, and probably raises another major point ... only 14GB RAM?
With Windows 8 Hyper-V (free) and VMWare workstation (around $100) and most contractors running insane dual-SSD 32GB laptops you gotta wonder, why would I want a 14GB VM in the cloud when I can run a 24GB VM locally? Also .. what happens if I am on a train / airport lounge / plane and can't access the internet?
Well .. good point ..
$100 a month is great, but Azure VMs are very expensive!
Now, I know a few contractor friends of mine in the industry who have looked at this and decided that its not for them .. I am one of them (yes that is right .. I'm advocating a new service which I myself am not going to use).
But this is not really for the sole contractor, and certainly not someone who works all of gods hours (either doing research, writing books or blog posts and preparing for conferences and user groups).
Now this is where the average contractor gets off the Azure train. If you are very busy and put in a lot of extra hours it is not uncommon to run your VM for 12 hours a day plus some conference / user group work at weekends ... this can quickly add up*
* note - I realise not everyone works these kinds of hours .. I personally don't, I have a wife and baby daughter at home and generally work a 9-5 work day .. but I know some people work longer hours, and I sure put in extra time when prepping for conferences
5 days a week @ 12 hours per day, plus another 12 hours over the weekend = 72 hours per week
72 * $0.48 = $34.56 per week
$34.56 * 52 = $1,797 per year
$1,797 / 12 = $149.76 per month
So if you are rolling with MSDN Premium you are going to be out of pocket, and even if you are lucky enough to be an MVP (and have MSDN Ultimate) or just have deep pockets .. you are still scraping the barrel and probably watching the clock every week to make sure you don't go over the limit.
"You" are not their target audience ... "We" are ..
I suppose this really rounds to my core point .. this subscription model is not aimed at the individual developer or contractor. It is aimed at development teams. The place I'm currently at has 5 developers working in three different countries all running MSDN Premium. This gives them a combined allowance of $500 per month of Azure credits.
Being an office-based development team it pretty much runs off standard office hours. The development machines only need to be on for office hours (typically 8am - 6pm unless there is a major version launch coming up) and almost certainly don't need to run at weekends. With a group of users you can also look at consolidating your infrastructure (why not run a shared SQL instance so you can drop your VM hardware?). Equally you probably don't need to run all of the services all of the time on every development machine (if you aren't building a search solution then turn it off!).
With $500 per month to spend they can run 5 XL VMs 9am-5pm every week for free (some weeks you won't need to have all 5 machines running .. so turning them off when you aren't using them can help to pay for those other times when you need to run them for longer!).
Even if you do use more horsepower than that .. try putting the figures in front of your IT Manager / Head of Infrastructure ... You might be surprised how happy they are to pay for the "extra" over and above those free Azure credits (some months it might cost you an extra $100 or so .. some months you won't have to pay anything ... compare that to other hosting providers and see how much it would cost you!)
How about using it for testing?
One of the other big boons (and possibly the reason I might use a farm like this) is for testing.
It doesn't really matter how powerful your laptop is, you are never going to be able to build a truly enterprise farm on it (with redundancy in all places and all of the lights and switches turned on). The same credit you get in Azure could be used to model and build massive farms you could use for testing new topologies, or testing load balancing scenarios, or performance and load testing?)
Don't forget, you only pay for the machines while they are turned on so instead of running 1 XL VM for 20 days a month .. why not create 30 Large VMs and run them for 5 days a month of testing?
Conclusion...
Well, this is a very interesting move from Microsoft .. and stacked up alongside their hosted Team Foundation Server offering this does create a very attractive and extremely low-cost cloud-based development scenario.
It encourages people to stick with MSDN and give Azure a go for development and testing, and I'm sure this will end up leading to many companies taking a much closer look at how Azure works for their production environments as well.
For me ? Well .. I might well use it for the next time I do a Kerberos / Load Testing presentation (the idea of setting up a massive 20 server farm to run for a few days for free sounds pretty cool and a great learning experience to boot).
If nothing else, I'm tempted to setup a VM which I leave turned off and only use it in emergencies (my laptop is broken / stolen or my VMs are dead for some reason).
Either way .. if you have an MSDN subscription, head over and take a look. You might be surprised how useful it is!
Monday 9 September 2013
I'm speaking at SharePoint Connections Amsterdam 2013
SharePoint Connections Amsterdam is now in its third year and has established itself as one of the key annual SharePoint conferences in Europe. Running across two days in November It has an awesome line-up of speakers covering a huge range of topics from IT Pro, Dev (and one track which aims to cover both), Business, End User and even an Office 365 track.
This year SharePoint Connections Amsterdam 2013 will take place at the Meervaart Theatre in Amsterdam on the 19th & 20th November 2013 and I have been honoured to be invited to be one of the speakers in the IT Pro / Dev track.
My session will be all about the new Search capabilities in SharePoint 2013, so if you want to know more about Result Sources, Result Types, Query Rules and Display Templates then this is the session for you!
For more information about the venue, hotels, the speakers, and (most importantly) the sessions and agenda head on over and grab yourself a ticket (before they all go!)
Sign up for the event here and use discount code SP333 for 10% off when you book!
Wednesday 28 August 2013
Changing Site Contents from a Grid to a List
This is something that has been bugging me for a while, and something that has clearly been bugging my users (as they keep saying they can never find anything).
The problem with the tile view is that you have to scan both left-right as well as up-down to find the item you are looking for. With a large number of lists this quickly becomes extremely painful to find what you are looking for.
So I thought, how could you turn it back?
Well, the good news is that the Site Contents view is actually all formatted using CSS with unique IDs and classes, which makes it a snip. the sample I've done below is in jQuery (because it is easy to pin a JavaScript file to every page and it works with Office 365 just as well).
So first off we need ourselves a function to reset all of the
function HideTiles() {
$("#applist .ms-vl-apptile").css({ "display": "block" });
$("#applist .ms-vl-apptile").css({ "min-height": "50px" });
$("#applist .ms-vl-appinfo").css({ "min-height": "50px" });
$("#applist .ms-vl-appinfo").css({ "width": "500px" });
$("#applist .ms-vl-appimage").css({ "height": "50px" });
$("#applist .ms-vl-appimage").css({ "width": "50px" });
$("#applist #apptile-appadd .ms-vl-appimage").css({ "width": "96px" });
$("#applist .ms-vl-appimage a.ms-storefront-appiconspan").css({ "height": "50px" });
$("#applist .ms-vl-appimage a.ms-storefront-appiconspan").css({ "width": "50px" });
$("#applist .ms-vl-appimage a.ms-storefront-appiconspan").css({ "line-height": "50px" });
$("#applist img.ms-storefront-appiconimg").css({ "height": "50px" });
$("#applist img.ms-storefront-appiconimg").css({ "line-height": "50px" });
};
Then we need to actually make sure this gets executed. The problem here is that the Site Contents is rendered on-the-fly using JavaScript so we have to resort to a little Script on Demand to get this working.
$(function () {
ExecuteOrDelayUntilScriptLoaded(HideTiles, "sp.ui.allapps.js");
});
Then the only thing needed is to make sure this script gets dropped onto the page and I've done this using a Custom Action (I could have used a delegate control with CSS style tags but that doesn't work in the Sandbox, i.e. Office 365)
<CustomAction
ScriptSrc="~SiteCollection/_layouts/15/MJH.JSLink/MJH.AddCss.js"
Location="ScriptLink"
Sequence="20">
</CustomAction>
So if you set this up it looks something like this.
Now I admit, the formatting is pretty crude and it could do with a certain amount of smartening up, but the principle is sound and at least the owners of sites with large numbers of lists get an easier to navigate list which is alphabetical, instead of having to scan a page of dozens of tiles.
The problem with the tile view is that you have to scan both left-right as well as up-down to find the item you are looking for. With a large number of lists this quickly becomes extremely painful to find what you are looking for.
The standard "Site Contents" view .. in all its nasty tile-layout glory |
So I thought, how could you turn it back?
Well, the good news is that the Site Contents view is actually all formatted using CSS with unique IDs and classes, which makes it a snip. the sample I've done below is in jQuery (because it is easy to pin a JavaScript file to every page and it works with Office 365 just as well).
So first off we need ourselves a function to reset all of the
function HideTiles() {
$("#applist .ms-vl-apptile").css({ "display": "block" });
$("#applist .ms-vl-apptile").css({ "min-height": "50px" });
$("#applist .ms-vl-appinfo").css({ "min-height": "50px" });
$("#applist .ms-vl-appinfo").css({ "width": "500px" });
$("#applist .ms-vl-appimage").css({ "height": "50px" });
$("#applist .ms-vl-appimage").css({ "width": "50px" });
$("#applist #apptile-appadd .ms-vl-appimage").css({ "width": "96px" });
$("#applist .ms-vl-appimage a.ms-storefront-appiconspan").css({ "height": "50px" });
$("#applist .ms-vl-appimage a.ms-storefront-appiconspan").css({ "width": "50px" });
$("#applist .ms-vl-appimage a.ms-storefront-appiconspan").css({ "line-height": "50px" });
$("#applist img.ms-storefront-appiconimg").css({ "height": "50px" });
$("#applist img.ms-storefront-appiconimg").css({ "line-height": "50px" });
};
Then we need to actually make sure this gets executed. The problem here is that the Site Contents is rendered on-the-fly using JavaScript so we have to resort to a little Script on Demand to get this working.
$(function () {
ExecuteOrDelayUntilScriptLoaded(HideTiles, "sp.ui.allapps.js");
});
Then the only thing needed is to make sure this script gets dropped onto the page and I've done this using a Custom Action (I could have used a delegate control with CSS style tags but that doesn't work in the Sandbox, i.e. Office 365)
<CustomAction
ScriptSrc="~SiteCollection/_layouts/15/MJH.JSLink/MJH.AddCss.js"
Location="ScriptLink"
Sequence="20">
</CustomAction>
So if you set this up it looks something like this.
New formatting (in a single alphabetical list) |
JSLink and Display Templates Part 5 - Creating custom List Views
- Part 1 - Overview, URL Tokens and Applying JSLink to objects
- Part 2 - Changing how individual fields display
- Part 3 - Creating a custom editing interface
- Part 4 - Validating user input
- Part 5 - Creating custom List Views (this post)
- Part 6 - Creating View Templates and Deployment Options
- Part 7 - Code Samples
This is actually one of the more simple examples so I'll start with all of the JavaScript in one block
var mjhViews = mjhViews || {};
mjhViews.itemHtml = function (ctx) {
var returnHtml = "<h2>" + ctx.CurrentItem.Title + "</h2>";
if (ctx.CurrentItem.MyCustomField) {
returnHtml += "<p>" + ctx.CurrentItem.MyCustomField + "</p>";
}
return returnHtml;
};
(function () {
var mjhOverrides = {};
mjhOverrides.Templates = {};
mjhOverrides.Templates.Header = "<div id='MyCustomView'>";
mjhOverrides.Templates.Item = mjhViews.itemHtml;
mjhOverrides.Templates.Footer = "</div>";
mjhOverrides.ListTemplateType = 104;
mjhOverrides.BaseViewID = 1;
SPClientTemplates.TemplateManager.RegisterTemplateOverrides(mjhOverrides);
})();
So we start off as good JavaScript developers and create ourselves a namespace (mjhViews) for our function (so we don't pollute the global namespace). This contains a single function (mjhViews.itemHtml) which accepts the same render context object we've been using throughout this series.
The itemHtml method simply returns some basic HTML consisting of the item Title in an H2 element followed by the "MyCustomField" (if it exists, this field was used in Parts 3 and 4). Of course there are different methods for retrieving the values of the current item but the render context will automatically provide properties for the basic data types (some field types, external data fields in particular, don't work like this and you might need to get creative with AJAX REST calls but be careful about performance!).
Finally we have our anonymous function which actually registers this override with SharePoint, and this is where things get interesting.
The main thing you might notice here is that we aren't controlling any specific fields but instead override the "Header" and "Footer" with plain old HTML. For the "Item" we reference our rendering method and this will be executed for every item present in the view.
We then have two more properties (both of which are optional by the way).
The ListTemplateType and the BaseViewID both define which specific list types and views this rendering should be used for. If you don't specify values for these then when this rendering override is registered it will override EVERY list and view on the page.
Finally we use the same old RegisterTemplateOverrides to tell SharePoint to process our object and do its thing!
Now before I apply this view it looks like this (which should be a pretty familiar SharePoint view):
Standard SharePoint list view |
A custom (if slightly boring) list view done with JavaScript |
The header and footer contain important List View elements |
TypeError: Unable to get property 'style' of undefined or null referenceThe problem is that if you don't override the Header you get some slightly funky behaviour because the headers injects a table object and it expects your content to be rendered inside that HTML table as rows. So by default I end up with the following (note the headers are at the bottom!)
Custom rendering with the header intact, but column headers are appearing AFTER the other content |
mjhViews.itemHtml = function (ctx) {
// start with a <tr> and a <td>
var returnHtml = "<tr><td colspan='3'>";
returnHtml += "<h2>" + ctx.CurrentItem.Title + "</h2>";
if (ctx.CurrentItem.MyCustomField) {
returnHtml += "<p>" + ctx.CurrentItem.MyCustomField + "</p>";
}
// close off our <td> and <tr> elements
returnHtml += "</td></tr>";
return returnHtml;
};
Once we put this in place, our headers are back in the right place.
Custom rendering with column headers in the right place |
In order to make sure the Display Templates are used in the correct places you have a number of options.
- In your schema.xml of a custom list definition you can define the JSLink property allowing you to override specific views. This allows you to build List Templates which have completely bespoke views when required (especially useful for use with list view web parts)
- You can define the JSLink property on the List View Web Part .. and this works either for defined views in the List or for List View Web Parts which you have dropped onto other web part pages or publishing pages.
- You can use Code / PowerShell to modify the JSLink property of the SPView object programmatically
- You can of course just drop in your JavaScript file using a Script Editor or custom Master Page and use the ListTemplateType and BaseViewID properties I told you about at the beginning on this post :)
- or you can use a funky new method which allows users to create their own views using your custom templates ... but more about that in Part 6 :)
..
Next - Part 6 - Creating View Templates and Deployment Options (coming soon)
Tuesday 27 August 2013
JSLink and Display Templates Part 4 - Validating user input
- Part 1 - Overview, URL Tokens and Applying JSLink to objects
- Part 2 - Changing how individual fields display
- Part 3 - Creating a custom editing interface
- Part 4 - Validating user input (this post)
- Part 5 - Creating custom List Views
- Part 6 - Creating View Templates and Deployment Options
- Part 7 - Code Samples
In order for a validator to work you need three moving parts:
- Validation method (to tell SharePoint if the field input is valid or not)
- OnError method (to handle any errors which are raised)
- Registration code to do the plumbing
We'll base this sample on the Custom Editing interface we built in Part 3 and first off we will build ourselves a validation method.
This is technically going to be an object with a Validate method (to which SharePoint will pass a value). The code for this method is as follows:
mjh.MyCustomFieldValidator = function () {
mjh.MyCustomFieldValidator.prototype.Validate = function (value) {
var isError = false;
var errorMessage = "";
if (value == "Item 2") {
isError = true;
errorMessage = "You cannot select 'Item 2'";
}
return new SPClientForms.ClientValidation.ValidationResult(isError, errorMessage);
};
};
The code above contains a very simple if statement to check the items value (in my example saying that an error message will be displayed if the item value is set to "Item 2" .. one of the drop-down choices from Part 3 of this series).
Finally we call the SPClientForms.ClientValidation.ValidationResult method passing in our "isError" (a true/false boolean) and the error message (a text string).
OnError Method
We then need a final method which tells SharePoint basically what to do when an error actually occurs. This is a fairly simple method in which you can basically do whatever you want (pop-up alerts, add HTML to the page, change CSS, whatever you need).
Now we could just use an Alert(error.message) function if we wanted a particularly crude error message but it would be much better to have some formatted error message just like SharePoint does out of the box .. and for that to work we first need to have ourselves a recognisable element that we can manipulate using jQuery, so we add the following code to our rendering method for the edit interface:
// add the error span
returnHtml += "<span id='MyCustomFieldError' class='ms-formvalidation ms-csrformvalidation'></span>";
Once we have this we can manipulate it in our "onError" function (which as you can see is very simple).
mjh.onError = function (error) {
$("#MyCustomFieldError")
.html("<span role='alert'>" + error.errorMessage + "</span>");
};
So all we are really doing is grabbing the span using the ID we gave it, then injecting our error message.
Now for the plumbing ...
So the only thing missing is making this all hang together from inside our render method:
var formCtx = SPClientTemplates.Utility.GetFormContextForCurrentField(ctx);
// register the field validators
var fieldValidators = new SPClientForms.ClientValidation.ValidatorSet();
if (formCtx.fieldSchema.Required) {
fieldValidators.RegisterValidator(
new SPClientForms.ClientValidation.RequiredValidator()
);
} fieldValidators.RegisterValidator(new mjh.MyCustomFieldValidator());
formCtx.registerValidationErrorCallback(formCtx.fieldName, mjh.onError);
formCtx.registerClientValidator(formCtx.fieldName, fieldValidators);
So lets walk through what we are doing in the code above.
First off we create ourselves a new ValidatorSet which will contain the validators that we need for the field. We then do a simple check to see if it is a required (mandatory) field and if it is we add the standard SharePoing "RequiredValidator" to our ValidatorSet.
Then we add our own new "MyCustomFieldValidator" object to the validator set.
Finally we have two register methods. The first one registerValidationErrorCallback is basically telling SharePoint that if our field fails validation that it should call the mjh.onError method to deal will letting the user know what has gone wrong.
The second one registerClientValidator actually registers our validators with SharePoint for the chosen field.
Note - it is perfectly possible to register your client validator without providing a validation error callback. If you do this then the validator will stop the form from being saved but the user won't be told why (they'll just get a frustrating form which won't post back).So .. assuming all of the above has worked correctly you would see something like this if you tried to selected "Item 2":
Validation message being shown in SharePoint |
For the complete code-sample to date (including Parts 2 and 3) please download the Visual Studio solution here:
http://sdrv.ms/15eB6CI
....
Next - Part 5 - Creating Custom List Views
Friday 23 August 2013
JSLink and Display Templates Part 3 - Creating a custom editing interface
- Part 1 - Overview, URL Tokens and Applying JSLink to objects
- Part 2 - Changing how individual fields display
- Part 3 - Creating a custom editing interface (this post)
- Part 4 - Validating user input
- Part 5 - Creating custom List Views
- Part 6 - Creating View Templates and Deployment Options
- Part 7 - Code Samples
Now the process for creating an editing interface is identical for both "New" and "Edit" forms (with the exception that the editing interface also needs to deal with loading up existing values) so for this post our examples will focus on the "Edit Form" functionality.
Registering our Edit Form function
So this uses exactly the same technique that we walked through in Part 2, where we register our desired override method for our named field.
(function() {
var mjhOverrides = {};
mjhOverrides.Templates = {};
mjhOverrides.Templates.Fields = {
'MyCustomField': {'NewForm': mjh.editMethod,
'EditForm': mjh.editMethod
}
};
SPClientTemplates.TemplateManager.RegisterTemplateOverrides(mjhOverrides );
})();
So just like before we create ourselves an override object and tell it we want to use the method "mjh.editMethod(ctx)" to render both the "EditForm" and "NewForm" for our field "MyCustomField" and we then register that using the SPClientTemplates.TemplateManager.RegisterTemplateOverrides method.
The Edit Render Method
The format of the rendering method for the edit interface (in this example) is pretty straightforward. I have simply rendered out a drop-down list containing three items.
mjh.editMethod = function (ctx) {
var formCtx = SPClientTemplates.Utility.GetFormContextForCurrentField(ctx);
formCtx.registerGetValueCallback(formCtx.fieldName, mjh.getFieldValue.bind(null, formCtx.fieldName));
// items to appear in the drop down list
var items = new Array("Item 1", "Item 2", "Item 3");
var returnHtml = "<div id=" + ctx.CurrentFieldSchema.Name + "><select>";
for (var i = 0; i < length; i++) {
returnHtml += "<option";
if (ctx.CurrentFieldValue == items[i]) {
// select the current item if the value matches
returnHtml += " selected ";
}
returnHtml += ">" + items[i] + "</option>";
}
returnHtml += "</select></div>";
return returnHtml;
};
We have also made use of the JavaScript "bind" function so that we can specify arguments that should be passed to our callback method, in this case we want to pass the field name (you'll see why in a minute).
The only other thing special going on here is that I check to see if the current value of the item matches the option, and if it is we add the "selected" attributed.
We have also enclosed the whole thing in a div using the fieldname as the ID, which we can use in our callback method below ...
The Get Value callback
The next thing of course is our method to retrieve the actual field value, and for this we use a little bit of jQuery (you can choose your own way of getting the jQuery library onto the page. Adding it as an extra JSLink URL is quite cool, although if you use jQuery everywhere you might otherwise want to use a Custom Action or Delegate Control so it appears on every page).
The only other thing special going on here is that I check to see if the current value of the item matches the option, and if it is we add the "selected" attributed.
We have also enclosed the whole thing in a div using the fieldname as the ID, which we can use in our callback method below ...
The Get Value callback
The next thing of course is our method to retrieve the actual field value, and for this we use a little bit of jQuery (you can choose your own way of getting the jQuery library onto the page. Adding it as an extra JSLink URL is quite cool, although if you use jQuery everywhere you might otherwise want to use a Custom Action or Delegate Control so it appears on every page).
mjh.getFieldValue = function (fieldName) {
// a div used with jQuery to identify the appropriate items
var divId = "#" + fieldName;
var divId = "#" + fieldName;
// get the selected item
var selectedItem = $(divId + ' option:selected')[0];
var selectedItem = $(divId + ' option:selected')[0];
// return the value
return selectedItem.innerText;
return selectedItem.innerText;
};
So you can see above that we are using the fieldName argument so we can identify the correct div. This allows us to use the same methods on multiple fields without them clashing.
We then simply use a small jQuery statement to pull out the selected item (the "option" element which has an attributed of "selected") and return the "innerText" (which in our example is the value we want to save). Of course you need to be mindful of the data type of the field you are working with. All values are returned as Text but fields such as People and Lookup Fields need to return a specifically formatted string.
I then bound this to a site column (of type Text) with the following schema:
<Field ID="{A424AE9E-1F1D-4ECE-B695-202F5106352E}"
Name="MyCustomField"
DisplayName="My Custom Field"
Description="a text field which has custom rendering?"
Type="Text"
Required="FALSE"
Group="MJH JSLink Columns"
JSLink="~layouts/MJH.JSLink/jquery-1.10.2.min.js|~layouts/MJH.JSLink/MJH.JSLink.js"
Overwrite="TRUE">
</Field>
Once that is all deployed it should look something like this ...
My Custom Field - a Text field but rendered as a drop-down list
|
In the meantime you can download the sample code from this example here:
http://sdrv.ms/14KtFgv
...
Next - Part 4 - Validating user input
Subscribe to:
Posts (Atom)