Showing posts with label jquery. Show all posts
Showing posts with label jquery. Show all posts

Friday, October 25, 2013

Creating a printable InfoPath form

I don't like printing.  But inevitably, someone will want to do it somewhere.

We have a list, which uses an InfoPath form for data entering and viewing.  In here, we created a Print view, which is basic black text on white background, and read-only.

However, when trying to print this view, the rest of our SharePoint master page and branding is printed with it, and it doesn't look very professional.  So we needed to create a printable version of this Print view.

Some suggestions online included using jQuery to remove everything BUT the InfoPath form, but this sounded like a messy way of doing things.  Instead, I figured I could just create a new blank page in SharePoint Designer and grab the item ID from the URL.

My first attempt failed.  I tried using a Query String Filter Web Part, but then realised that sending an ID to an InfoPath Web Part doesn't do what you'd think it would do.  It doesn't magically open the item you're referencing with the ID, it simply changes the InfoPath form item ID.  You could use this method for pre-populating an InfoPath form based on parameters in your query string, but not for actually loading an already-existing form.

I figured that you could instead use that ID to filter a List View of your list, and then send that single item to the InfoPath web part.  This would also mean I wouldn't need the Filter Web Part, as a List View has its own Filter and Parameter settings.  So, here's what I did.

  1. Using SharePoint Designer, create an ASPX page in your site called PrintForm.aspx.
  2. In the ASPX page, add an InfoPath form web part, and configure the web part to use the list you're trying to print items from.  Configure this web part to use the correct Print view that you've already created in InfoPath Designer.
  3. Somewhere else on the page, add a Data View, and again configure to use the list you're trying to print items from.  Configure this web part to be hidden or not visible (unless you want to see the list view as well).
  4. With the List View web part selected, add a Parameter.  This will be a query string parameter with the name ID, and the Query String Variable of ID as well.  (You can change this to ItemID or something else if you want)
  5. Next, add a Filter for the List View web part.  This will get the Field Name ID to equal the parameter you just created, which will be displayed as [ID] or [ItemID] or whatever you chose in the previous step.
  6. Finally, Add a Connection from the List View to the InfoPath web part.  You want to Send Row of Data To the InfoPath web part, using the Target Action "Get Form From".  
  7. Save and check in the file as appropriate.

Now, if you try to access the URL of this page with an ID added to the end, you will get a nice, basic printable view of your data.  You'll want the URL to look like this:

http://sharepoint/sitename/Pages/PrintForm.aspx?ID=25

What you'll need to do then is add a Print button to the normal Read or Edit view of the InfoPath form, which will send the user to that URL above, with the current item ID after the ID= (in the example above, the item ID is 25).

There's also a little bit of JavaScript you can throw in to your PrintForm.aspx page which will tidy up a few last remnants of the InfoPath web part - namely, the web part name, and the light blue border.  It also presents the user with their browser Print dialog, to save them having to go to File/Print.  It looks like this:

<script src="/scripts/jquery-1.9.1.min.js" type="text/javascript"></script> 
<script type="text/javascript">
  $('.ms-WPHeader').hide();
  $('.ms-WPBorder').css('border', 'none');
  setTimeout(function() {
    window.print();
  }, 500);
</script>

Edit: added a setTimeout before printing, because it was printing a blank page, even though print preview was working correctly.

Monday, June 10, 2013

JSON returned from listdata.svc for a full list, but "XML" for a single item

I've been trying to use jQuery to get some data from a SharePoint list named Articles, using REST.  Hit a wall, couldn't figure it out.  Quick blog post about how I got around it.

Basically, when I tried to use $.getJSON with this URL:

http://sharepoint/_vti_bin/listdata.svc/Articles()

I was able to parse the data in jQuery as you'd expect.  Worked like a dream.  However, when I tried to just return one single list item, using:

http://sharepoint/_vti_bin/listdata.svc/Articles(1)

jQuery silently failed.  Couldn't get any data out of it whatsoever.  When I looked at Google Chrome's Developer Tools (specifically, the Network function), I could see that Articles() was being returned as application/json as you'd expect, but Articles(1) was being returned as text/plain.  jQuery didn't like that.

So, I added a parameter to my URL:

http://sharepoint/_vti_bin/listdata.svc/Articles(1)?format=JSON

And everything is right in the world again.

Wednesday, November 21, 2012

Hiding certain fields from document properties using jQuery

I have a document library that uses a few "hidden" fields during its various automated workflows.  However, for some of these fields, I can't mark them as hidden fields in the document library properties, possibly because they're related to a content type.  So I need to find another way to hide them from the user when viewing or editing document properties.

I found a solution on the blog SharePoint Sherpa - SharePoint 2007 – Hiding fields on NewForm.aspx and EditForm.aspx, the easy way - but wanted to use jQuery, so adapted it slightly.  Here is what I came up with.

1. Find the document library's DispForm.aspx and/or EditForm.aspx in the hidden Forms folder. This can be found in SharePoint Designer, selecting All Files for that site, and finding the Forms folder in the correct library.
2. Find the line:
<asp:Content ContentPlaceHolderId="PlaceHolderMain" runat="server">
3. Add the following code:


<script type="text/javascript">

_spBodyOnLoadFunctionNames.push("hideFields");

function hideFields() {

$('.ms-formlabel:contains("Field name 1")').parent().hide();
$('.ms-formlabel:contains("Field name 2")').parent().hide();
$('.ms-formlabel:contains("Field name 3")').parent().hide();
$('.ms-formlabel:contains("Document ID")').parent().hide();

}
</script>

4. Change "Field name 1" to the name of the first field you want to hide.  Do the same for the other lines, and add more lines as required.  (I've chosen to hide Document ID - it's in use throughout our SharePoint site, but I don't want the users to see it in this library)

I'm sure there are ways to further improve this, perhaps by putting the field names into an array, but this will do for now.

Friday, August 17, 2012

The simple art of making Json work in Internet Explorer

A couple of projects I've been working on - both for my day job, and for my personal site - utilise ASP.NET MVC, jQuery and Json.  My prior development was using exclusively ASP.NET AJAX and, before that, plain old PHP, so when I discovered the three technologies above, I've not really understood why web development was ever any other way.

I primarily develop in Google Chrome - I used to use FireFox and Firebug, but found that Chrome's included Developer Tools are as good as - possibly better than - Firebug, particularly the Network monitor. The organisation I work in only supports Internet Explorer, but that would only affect the layout and styling, right?  Once I've got the page looking right, I wouldn't need to check the actual functionality when it comes to Json data.

I couldn't have been more wrong.  Although the site worked fine in Internet Explorer, posting data back to the database, and the updated information would even show in Chrome, IE just refused to show what had changed.  So I dusted off the F12 Developer Tools in Internet Explorer - extremely difficult to do after using Chrome's Development Tools - and started to diagnose.

The first step I took was to open the Json request in a new IE tab.  This wouldn't work.  Instead of showing the raw Json data as I'd expect, it would attempt to download a file.  I didn't want this, and for a while, thought this might be the cause of all my problems.

I did some research, and the ever-useful stackoverflow gave me the answer - I had to change every return Json command in my Controller to explicitly specify a MIME type.  I shouldn't have expected Internet Explorer to figure it out for itself, like Chrome does.  This link - IE9 JSON Data “do you want to open or save this file” - gave me the following answer:

return Json(someData, "text/html", System.Text.Encoding.UTF8,
                        JsonRequestBehavior.AllowGet);

Splendid - IE doesn't insist on downloading this file now, and will show the raw Json data instead.  But looking at the data returned, I didn't see an error that would cause the data displayed on my actual page to be out of date - I used a simple "return Json(DateTime.Now ... )" test and this showed the correct time, down to the second.

So I continued my search for a solution to my second problem, and found another post - Unexpected Caching of AJAX results in IE8 - that indicated Internet Explorer forcibly caches AJAX requests.  Although the request appears in the Network monitor, the data it uses is out of date.  Adding the following line to my jQuery code resolves everything:

$.ajaxSetup({
    cache: false
});

I'm glad I've managed to solve this issue, but I must admit, it's taken some of the fun out of developing.  Everything was going so smoothly with MVC, Json, etc., until I discovered how antiquated and difficult Internet Explorer still is to this day.  Why is it so strict with MIME types?  Why is it automatically caching dynamic data?  And, of course, why does it interpret CSS so differently to other browsers?

And I suppose the ultimate question (or answer) is, why do Microsoft have to run an advertising campaign to convince people to use a free browser that is, let's face it, still included in Windows by default?

Rant over.  Moving on.

Thursday, August 2, 2012

Silverlight appears on top of pop-up menu

The SharePoint site I'm working on features a top navigation bar that drops down a submenu when the main menu buttons are hovered over.  There's nothing particularly clever going on there - it uses jQuery, and is tied in with the standard SharePoint navigation.

However, a few pages on the site have a Silverlight object at the top of the editable page - so, directly underneath the top navigation bar.  On these pages, the Silverlight object would appear to be always on top, so the pop-up element would always appear behind it.  This means that you couldn't navigate to other areas of the site.

I found a fix on the Silverlight forums that consisted of two parts:

  1. For the DIV that contains the Silverlight object, position: absolute is required.
  2. For the Silverlight object, an additional param is required: windowless should be set to true, like this:  <param name="Windowless" value="true"/>
Problem solved, like magic.

Friday, June 1, 2012

Navigation dropdowns in SharePoint 2010 using jQuery

I've been looking for a way to create dynamic top navigation dropdowns in SharePoint 2010.  I'd managed to create the dropdowns but only using fixed code, so if a subsite was created, the code would have to be changed too.

I found a few helpful resources online, but the best for me was http://css-tricks.com/simple-jquery-dropdowns/.  I've included my code below.

SharePoint 2010 master.page

<SharePoint:AspMenu
ID="TopNavigationMenuV4"
EncodeTitle="false"
Runat="server"
EnableViewState="false"
DataSourceID="topSiteMap"
AccessKey="<%$Resources:wss,navigation_accesskey%>"
UseSimpleRendering="true"
UseSeparateCss="false"
Orientation="Horizontal"
StaticDisplayLevels="2"
MaximumDynamicDisplayLevels="2" 
SkipLinkText=""
CssClass="s4-tn"></SharePoint:AspMenu>




jQuery
$(document).ready(function() { 
 //Hide all submenus - this should probably be done in CSS
 $('.menu-horizontal ul ul').hide(); 
 //If a child is selected, I also want the parent to be selected
 $('.menu-horizontal ul ul li.selected').parent().parent().addClass('selected');
 //When the mouse hovers over a parent:
 $('.menu-horizontal ul li').hover(function() {
  //Show the first (and only) child ul, containing a li for each subsite
  $('ul:first',this).show();
 }, function(){
  //Hide the child ul after the mouse has left
  $('ul:first',this).hide();
 });
}); 




CSS

This is all very customised to my SharePoint 2010 environment - the above should work out of the box.

Tuesday, April 24, 2012

Delaying an autocomplete jQuery search

I recently implemented an autocomplete function on a site, using jQuery to update the results and a JsonResult controller to get the actual data.  When the content of a search box changed (using event trigger onkeyup), it would perform a search on the contents of that text box.  I've gone a few steps further and split the text box on spaces and commas, to create a wildcard search, but that's not the point of this post.

The issue I saw is that a new call to the database or cache was being carried out with every keypress.  This was a problem.  So I found some code on http://jsbin.com/ebela4/8/edit#javascript,html and adapted it slightly.  Here it is:


var delay = 600;
var isLoading = false;
var isDirty = false;

function AutoCompleteChange() {
if (!isLoading) {
// This only performs a search if four or more characters have been
// entered. Change the number to change this restriction.
if ($("#txtSearch").val().length >= 3) {
isLoading = true;
setTimeout(function () {
isLoading = false;
if (isDirty) {
isDirty = false;
// Perform actual search
// INSERT YOUR CODE HERE
}
}, delay);
};
};  
};