I found this fantastic post today that I just had to comment on: | In a SharePoint entry form the user can select multiple values from a list. This should include an “All” option so in a long list the user can select or de-select all values with one click. | The idea is to use JQuery to perform a select 'All' on all the checkboxes in a list. DannyE posted this JavaScript: $(”.ms-RadioText[title=’All’] :checkbox”).click(function(){
var otherids = (this.id).substring(0, (this.id).length-2 );
$(”input[id^=’”+otherids+”‘]”).attr( “checked” , (this.checked)?”checked”:”" );
});
It looks for all the items with the ms-RadioText class that also have a Title attribute that equals 'All', it adds a click handler that will then toggle the checked status of the checkbox, its extremely cool, way better than the latest block buster movie ...
Anyway, that's all well and good, I'm not adding much value reposting his stuff, so I'd just like to improve on his deployment recommendation.
Instead of adding a script reference to the master page and then inserting a content editor region to paste the JavaScript in, I would suggest using the JQuery Script Manager:
So the idea is to use SharePoint Designer to register the control with the JavaScript. Note here to use the ScriptTemplate you'll have to grab my latest script manager control from here.
<cc1:jQueryManager ID="JQueryManager1" runat="server">
<ScriptTemplate>
$(".ms-RadioText[title='All'] :checkbox").click(function(){
var otherids = (this.id).substring(0, (this.id).length-2 );
$("input[id^='"+otherids+"']").attr( "checked" , (this.checked)?"checked":"" );});
</ScriptTemplate>
</cc1:jQueryManager>
This will insert the JQuery Script Manager and declaratively add the JavaScript code to the page. This way you don't need to worry about the script resources or having multiple client side load functions.
How can you not love JQuery after seeing the power of the above code? it's just that awesome!
The web part that I'm presenting today is more of a building block, it doesn't do much on its own. It makes use of the JQuery Corners Plugin. To set the corner types you can modify the Corner Type setting: The above example will cause the following JavaScript to be output: jQuery('cornerDiv').corner('tr 25px');
This web part makes use of the JQuery Script Manager that I've posted about previously.
As usual the source can be found here.
A screencast of the control in action can also be found here.
I've posted a couple of articles on JQuery and it's use in SharePoint and also provided some sample web parts. Recently I was putting together these web parts into a single project and I ran into a problem. Each web part was adding the JQuery script resources to the page as if it was the only control on the page, for example the ImageCarousel and the Tag Suggestion web parts both had code that needed to be run on the JQuery load event, this problem would also crop up when multiple instances of the same web part were added to the page. What was outputted to the page was something like: $(document).ready(function(){
//function call for webpart1
}
$(document).ready(function(){
//function call for webpart2
}
$(document).ready(function(){
//function call for webpart2 instance 2
}
So I started developing a Script Manager control that I could add to the page that would output the JQuery load event just once, but with all the calls for the page inside this event. As with anything programming related these days, I found what I was looking for at http://codeplex.com/JQueryScriptManager/ I've changed a bit of the implementation, but the basic intent has remained the same. Hopefully I'll be able to get these changes updated to codeplex.
Looking at the revised code for the ImageCarousel web part:
jQueryManager jqueryManager = null;
protected override void OnInit(EventArgs e)
{
jqueryManager = jQueryManager.GetCurrent(Page);
if (jqueryManager == null)
{
jqueryManager = new jQueryManager();
Page.Controls.Add(jqueryManager);
}
Page.ClientScript.RegisterClientScriptInclude("JCarousel", Page.ClientScript.GetWebResourceUrl(this.GetType(),
"JQueryWebParts.js.jquery.jcarousel.pack.js"));
base.OnLoad(e);
}
Now inside the PageInit we check for the presence of a JQueryManager script control, if we don't find one, we add it to the controls collection. Just like the ASP.NET Ajax ScriptManager control, there can only be one per page.
Now to add code that is globally scoped which also resides in the same script block where our OnLoad event lives:
jqueryManager.RegisterScript("-- javascript code without <script> blocks");
//example:
jqueryManager.RegisterScript("var someItems = [5,4,3]");
To get javascript to run when the page is loaded (this will bundle calls into a single load event):
jqueryManager.ReadyFunctions.Add(new RegisterStartFunction("jQuery('#carousel').jcarousel();"));
Use the ReadyFunctions collection which takes a RegisterStartFunction object as a parameter.
Internally the JQuery script manager control is performing the following:
StringBuilder Start = new StringBuilder();
if (Scripts != null)
{
foreach (RegisterScriptBlock r in Scripts)
Start.Append(r.ScriptBlock + Environment.NewLine);
}
if (ReadyFunctions != null)
{
Start.Append("$(document).ready(function(){");
foreach (RegisterStartFunction r in ReadyFunctions)
Start.Append(r.FunctionName + Environment.NewLine);
Start.Append("});\n\n");
}
Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "JQuery", Start.ToString(), true);
The source code can be downloaded here. This includes the updated JQuery Script Manager and the ImageCarousel web part that I've previously posted about.
I think this approach will provide a nice platform to continue building web parts based on JQuery Plugins, have fun.
Recently I posted about using JQuery in SharePoint web parts in this post I wrapped up the JCarousel plugin. Instead of requiring the JCarousel.js file to be included into the master page, I instead made the web part inject the HTML to cause the JavaScript file to be loaded. The first step was to include the packed version of jquery.jcarousel.pack.js into my project: Notice the Embedded Resource setting for the build action. Now if we add the following code to our assembly.cs file: [assembly: System.Web.UI.WebResource("SPImageCarousel.jquery.jcarousel.pack.js", "text/javascript")]
The above line now makes our embedded resource available for use in our web part which is done by the following code:
protected override void OnInit(EventArgs e)
{
Page.ClientScript.RegisterClientScriptInclude("JCarousel", Page.ClientScript.GetWebResourceUrl(this.GetType(), "SPImageCarousel.jquery.jcarousel.pack.js"));
base.OnLoad(e);
}
This code will ensure that the script is only added to the page once since the key "JCarousel" is the first parameter, remember that more than one web part can be added to a page at the same time, so we need to consider this as we develop our web parts. OnInit is the perfect event to call RegisterClientScriptInclude it's nice and early in the page lifecycle.
So hopefully you'll find this a nice and easy way to include your JavaScript resources, it does have the disadvantage of requiring a recompile to include a later version of the JavaScript file, so your mileage may vary if this is a concern.
Better still if your using .NET 3.5 Service Pack 1, you could make use of the CompsiteScript element of the script manager to combine the javascript files so the browser makes fewer calls to the server.
I've mentioned before that I'm partial to JQuery, I consider it to be the Jessica Alba of JavaScript. With all the work that has been done creating awesome JQuery based UI components, it seems like such a shame that us SharePoint developers aren't making more use of them. So I present to you my first JQuery based web part, the Image Carousel: Based on JCarousel, this web part presents the contents of a picture library in a carousel that can be scrolled by the navigation buttons. The web part simply imports the jcarousel.js file, the web part then injects a JavaScript array of the images that reside in the selected picture library along with some javascript that initialises the carousel. The code to find the SharePoint picture library list is trivial: SPSite site = SPContext.GetContext(HttpContext.Current).Site;
SPWeb web = site.OpenWeb();
foreach (SPList list in web.Lists)
{
if (list.BaseTemplate == SPListTemplateType.PictureLibrary)
{
//grab the images from this list
jsArray.Append(ProcessList(list));
}
}
The web part makes use of custom toolpart for the selection of the picture list:
I think this provides a good template and starting point to start putting more of those JQuery plugins to use inside SharePoint
A small screencast of the control in action can be found here.
The end effect is some exceptional functionality for little development effort, which is really what JQuery is all about.
Some of the things that you need to think about when integrating:
- Make sure that the injected div tag that will be used at the host has a unique id, remember that more than one webpart can be added to a page, if you hard code the html to have specific ID's, you will run into problems.
- Make sure the JavaScript gets injected into the right part of the page, also just like the above point, ensure that each injected bits of code have a unique name, so that multiple webparts on the same page don't cause problems.
- Use the packed version of the component, SharePoint is bloated enough already, use the smallest possible footprint you can.
The source code can be found here.
JQuery is my all time favorite JavaScript library, it's so simple to use and incredibly powerful, but if you include all the plugins that are available, I just don't think that you would find a better tool for client side scripting. My favorite validation plugin is the 'Validation Plugin', let me give you an example of how it is used: Lets say you have a signup form, you want the user to select a user name, a password with confirmation and an email address, assume all of this is inside a form tag named 'signup'. All of the HTML input element ids are 'Password', 'ConfirmPassword', 'Email'. The JavaScript would be: <script type="text/javascript">
$().ready(function() {
$("#signup").validate({
rules: {
UserName: {
required: true,
minLength: 2,
remote: "/Account/CheckUserName"
},
Password: {
required: true,
minLength: 2
},
ConfirmPassword: {
required: true,
minLength: 5,
equalTo: "#Password"
},
Email:{
required: true,
email: true,
remote: "/Account/CheckEmail"
}
},
messages: {
UserName: {
required: "Please enter a username",
minLength: "Your username must consist of at least 2 characters",
remote: jQuery.format("{0} is already in use")
},
Password: {
required: "Please enter a password",
minLength: "Your password must consist of at least 2 characters"
},
ConfirmPassword: {
required: "Please provide a password",
minLength: "Your password must be at least 2 characters long",
equalTo: "Please enter the same password as above"
},
Email: {
required: "Please enter your email address",
minLength: "Please enter a valid email address",
remote: jQuery.format("{0} is already in use")
}
}
});
});
</script>
Now notice how I used the remote property with '/Account/CheckEmail' and '/Account/CheckUserName', these are URL's that will be called by the client side JavaScript, they will pass along the current value of the textbox, so you could write server side code to validate the input, an ASP.NET MVC Controller Method could look like:
public JsonResult CheckUserName(string username)
{
return Json(CheckValidUsername(username));
}
Notice the use of a JsonResult, The ASP.NET MVC framework is great for this type of thing, combine both JQuery and the MVC framework and you have a powerful combination, Jeff Atwood has come to the same conclusion and used both of these tools to build stackoverflow.com.
All of the above code is so clean and easy to read, can you ever remember saying that about JavaScript code?
|