How to override the NewDocSet.aspx redirect

If you are opening the NewDocSet.aspx page in a dialog, similarly to this:

options.url = L_Menu_BaseUrl + "/_layouts/15/NewDocSet.aspx?List=" + {listGuid} + "&ContentTypeId=" + {CT} + "&RootFolder=" + L_Menu_BaseUrl + "/Lists/YourList";
options.title = "New Document Set";
options.autoSize = true; 
// Show dialog
SP.SOD.execute('sp.ui.dialog.js', 'SP.UI.ModalDialog.showModalDialog', options);

you may have noticed that after creation of the docset, the dialog redirects your page to the welcome page of the newly created doc set. If you are opening this dialog from some kind of a dashboard, this is usually an undesired behavior.

I have taken a look at the NewDocSet.aspx backend with ILSpy and I have determined that when the new Document Set is provisioned, the code end with a calls to this function – ‘window.frameElement.navigateParent’. Turns out this is a function defined by SharePoint, when you open a dialog. It basically redirects the parent window to a new URL. And NewDocSet.aspx uses this function to redirect the window to the Welcome page of the new doc set.

So, to override this behavior, we simply override the dialog’s window frame function (make sure you execute this AFTER the dialog is opened):

// Override the redirect behavior of NewDocSet.aspx
for (var i = 0; i < frames.length; i++) {
    // Find the frame of the dialog
    var frmWindow = frames[i];
    if (frames[i].location.href.indexOf(‘/_layouts/15/NewDocSet.aspx’) > -1) {
        // Override the function
        var prxy = frmWindow.frameElement.navigateParent;
        frmWindow.frameElement.navigateParent = function () {
            // Disregard the original function’s URL, refresh the page we are currently on
            prxy.apply(this, [window.location.href]);
        };
    }
}

The patter is called proxy pattern, by the way.  This code will refresh the page that opened the NewDocSet.aspx dialog, instead of redirecting to the doc set’s welcome page.

Good luck (with SharePoint, you need it).

Advertisements

SharePoint 2013 Refiner Multi-Value (‘Contains’ instead of an ‘Equals’)

You are in a situation where your Managed Property contains multiple values (e.g. you programmatically populate a Property Bag, which is added to the IndexedPropertyKeys and then exposed as a Managed Property). You add a Content Search Web Part on your page and also a refiner. In the Refiner panel you add your managed property and you are horrified by the following end result:

1

If you are reading this page you already know that such rendering causes a problem – the entries within the multi-value field are not ‘normalized’ to single entries, hence, you now can’t search only for items that have a property which contains only (e.g.) one of the values. You have already probably tried setting the ‘multi-value’ property of the Managed Property, but alas, no success.

Fear not, for I have a solution! It is delivered as a custom Refiner filter, which is based on the Filter_MultiValue.html OOB Refiner filter. Here it is: click here.

How to use it? Simple:

1. Drop the file into your Filters folder (Site Collection -> Settings -> Master pages and page layouts -> Display Templates -> Filters)

2. Make sure you Save, Check In and Publish the file

3. Go to your refiner and edit the web part properties -> Choose refiners

4. Select the newly added Filter

2

5. Ok -> Save page

And the result now is:

3

Much better! Selecting a refiner value and applying actually works too 🙂

4

For the curious, how does the custom Filter work? Well:

1. We set the var useContains = true; Although in my experience it has no effect on the end result

2. More importantly, we add one more for(;;) cycle in the code, which splits every filter item into separate filters:

5

So, instead of having:

[ ] Value 1, Value 2, Value 3, …

you will have:

[ ] Value 1

[ ] Value 2

[ ] Value 3

3. But MOST IMPORTANTLY, instead of hex-ing the refiner token, as the OOB filter does, we use the plain-text value:

6

This is crucial! Without this part the refiner will not work as expected.

So let’s compare an original query URL generated by the OOB Filter_MultiValue.html with the custom Filter_Contains_MultiValue.html.

Before:

#Default=
{
“k”:””,
“r”:[{
“n”:”HahnAirPMOProjectManagerDisplayValue”,
“t”:[“\”ǂǂ4c41425c41646d696e6973747261746f72\””],
“o”:”OR”,
“k”:false,
“m”:{“\”ǂǂ4c41425c41646d696e6973747261746f72\””:”LAB\\Administrator”}}]}

After:

Default=
{
“k”:””,
“r”:[{
“n”:”HahnAirPMOProjectManagerDisplayValue”,
“t”:[“LAB\\Administrator”],
“o”:”OR”,
“k”:false,
“m”:{“LAB\\Administrator”:”LAB\\Administrator“}
}]
}

That specific part seems to cause SharePoint to do ‘contains’ search, instead of an ‘equals’ search.

Hope this helps!

PS

Don’t forget to set your ‘delimiter’ variable to whatever string you use for separating the values within the field. It is currently set to ‘, ‘ (coma and space).

Update 1:

I have updated the source code to handle strings with backslash in them differently. i.e.:

– If the string has a backslash (e.g. ‘domain\admin’) – don’t put it withing brackets

– if the string has no backslash (e.g. ‘Farm Admin’) – put it in brackets, otherwise the KQL is invalid and causes an error

Fixing ‘The SPListItem being updated was not retrieved with all taxonomy fields’ or how to provision taxonomy fields correctly

If someone wants to provision a taxonomy field in a declarative way, the following pattern should be followed:

      <Field Type="Note" DisplayName="Strategy_0" StaticName="Strategy_0" Name="Strategy_0" ID="{the GUID of your hidden NOTE field here}" ShowInViewForms="FALSE" Required="FALSE" Hidden="TRUE" />
      <Field Type="TaxonomyFieldType" DisplayName="Strategy" ShowField="Term1033" Required="FALSE" EnforceUniqueValues="FALSE" ID="{6f1ce2c9-9c40-407f-a0b9-7785220a14ff}" StaticName="Strategy" Name="Strategy">
        <Customization>
          <ArrayOfProperty>
            <Property>
              <Name>TermSetId</Name>
              <Value xmlns:q2="http://www.w3.org/2001/XMLSchema" p4:type="q2:string" xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">{the GUID of your termset here}</Value>
            </Property>
            <Property>
              <Name>AnchorId</Name>
              <Value xmlns:q3="http://www.w3.org/2001/XMLSchema" p4:type="q3:string" xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">00000000-0000-0000-0000-000000000000</Value>
            </Property>
            <Property>
              <Name>TargetTemplate</Name>
              <Value xmlns:q6="http://www.w3.org/2001/XMLSchema" p4:type="q6:string" xmlns:p4="http://www.w3.org/2001/XMLSchema-instance"></Value>
            </Property>
            <Property>
              <Name>TextField</Name>
              <Value xmlns:q6="http://www.w3.org/2001/XMLSchema" p4:type="q6:string" xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">{the GUID of your hidden NOTE field here}</Value>
            </Property>
            <Property>
              <Name>IsPathRendered</Name>
              <Value xmlns:q7="http://www.w3.org/2001/XMLSchema" p4:type="q7:boolean" xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">false</Value>
            </Property>
          </ArrayOfProperty>
        </Customization>
      </Field>

That would be sufficient, if it were not for the SspId property (the GUID of your keyword term store). Unfortunately there is no token for this and SharePoint is not smart enough to use the default one, if you leave it empty! You will get an error ‘The SPListItem being updated was not retrieved with all taxonomy fields‘. So, a little code work-around is needed.

You have to create a feature receiver or something else, which should run the following code against your field:

        public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {
            var web = properties.Feature.Parent as SPWeb;

            // Strategy
            var strategyField = web.Lists["YourList"].Fields["YourTaxonomyField"] as TaxonomyField;
            TaxonomyHelper.ConnectTaxonomyField(web.Site, strategyField);
        }
        /// <summary>
        /// Fix up a taxonomy field
        /// </summary>
        /// <param name="site"></param>
        /// <param name="field"></param>
        public static void ConnectTaxonomyField(SPSite site, TaxonomyField field)
        {
            //Create a Taxonomy Session
            TaxonomySession session = new TaxonomySession(site);
            if (session.DefaultKeywordsTermStore != null)
            {
                field.SspId = session.DefaultKeywordsTermStore.Id;
                field.Update();
            }
            else
            {
                throw new Exception(string.Format("DefaultKeyWordTermStore not found in this site {0}", site.Url));
            }
        }

Again, if SharePoint used the default keyword store if you leave out the SspId empty or if there was a token for it, that would not be necessary.

Still, I am happy with the approach, as it is 95% declarative and I need the code only to link my field to the keyword store. The TermsetId is part of my declaration, and not the code, so, goal achieved!

SharePoint document library list view webpart drag and drop

The following article assumes that you know how to add programmatically list view web parts on your page.

You might find yourself being in a situation in which you are programmatically adding a List View Webpart pointing to a document library on your site and you wonder why:

  • ‘add document’ link does not show
  • drag & drop does not show up or does not work

Basically, you have ended up with something along the lines of:

drag drop not working

First, and foremost, you have to change your code and instead of adding ListViewWebPart, you have to add XsltListViewWebPart (source).

var webPartToAdd = new XsltListViewWebPart
                        {
                            ChromeState = PartChromeState.Normal,
                            ChromeType = PartChromeType.None,
                            Title = "Documents List View",
                            ListName = web.Lists["Documents"].ID.ToString("B").ToUpper(),
                            XmlDefinition = web.Lists["Documents"].DefaultView.GetViewXml()
                        }

This will get you to the point where you see the drag&drop functionality (in IE only, I don’t see it in Firefox):

drop here

However, when you drop the file, you might get the error:

exception

The reason for this error is the fact that sp.js and sp.core.js are not registered on the page (SP.Utilities and SP.Utilities.CommandBlock are undefined)! I think this is a bug in SharePoint, because if you simply click Edit on the page and then save it (without changing anything), the web part will start working (because the scripts will now be registered on the page).

So, how do we overcome this issue? Well, I have determined that if we execute the following script on the page, the drag&drop in the web part will work fine:

SP.SOD.executeFunc('sp.js', 'SP.Utilities.Utility', function() { console.log('sp.js loaded'); });
SP.SOD.executeFunc('sp.core.js', 'SP.Utilities.CommandBlock', function() { console.log('sp.core.js loaded'); });

This code will include the scripts that SharePoint ‘forgets’ to include. You have variety of options how to register those scripts on the page. I have decided to include them as a content of a Content Editor WebPart which I provision on the same page where I provision the (xslt) list view web part:

// add script registration work-around (there is a bug in the framework, which does not register those scripts until we edit the page).
var xmlDoc = new XmlDocument();
var xmlElement = xmlDoc.CreateElement(“HtmlContent”);
xmlElement.InnerText = “<script type=’text/javascript’>SP.SOD.executeFunc(‘sp.js’, ‘SP.Utilities.Utility’, function() { console.log(‘sp.js loaded’); }); SP.SOD.executeFunc(‘sp.core.js’, ‘SP.Utilities.CommandBlock’, function() { console.log(‘sp.core.js loaded’); })</script>”;
var cewp = new ContentEditorWebPart
{
ChromeState = PartChromeState.Normal,
ChromeType = PartChromeType.None,
Title = “Drag and drop script registration workaround”,
Content = xmlElement
};

And then, viola!, the drag&drop works:

viola

 

I hope this helps,

Hristo

jQuery in SharePoint

There are rumors jQuery might be included as part of SharePoint 2010. In an anticipation for that, today’s article aims to show what the integration between SharePoint 2007 and jQuery looks like, how to use it and what are the benefits.

So what is jQuery?
jQuery is a lightweight JavaScript library that emphasizes interaction between JavaScript and HTML. It was released in January 2006 at BarCamp NYC by John Resig. jQuery is free, open source software Dual-licensed under the MIT License and the GNU General Public License. Microsoft and Nokia have announced plans to bundle jQuery on their platforms, Microsoft adopting it initially within Visual Studio for use within Microsoft’s ASP.NET AJAX framework and ASP.NET MVC Framework whilst Nokia will integrate it into their Web Run-Time platform.

Simply put, it is a high performance rapid development, AJAX-enabled library on top of JavaScript.


API
There are a lot of articles and tutorials out there, on how to use jQuery in general. Here is the most essential documentation you will need – the jQuery API.

SharePoint integration
Integration between jQuery and SharePoint boils down to finding a smart way to get a jQuery reference in your pages.

Basically you can do this ‘manually’, which is well described here or you can use an automated integration solution (see below).

The manual approach essentially consists of two steps:
1) Deploying the libraries (js) to a location which can be accessed by the pages – that would be the LAYOUTS folder in the 12 hive
2) Loading the libraries on the pages – by modifying the master page, load the library specifically in the page you want to use it or other… It is all well described in the posted article.

The automated solution is a better one. You can get “SmartTools jQueryLoader for SharePoint” which does the integration for you. There is a good article which walks you through the installation process, so we are not going to that here. Make sure you watch the video, though.



Just try it out

If you just want to quickly try the magic of jQuery in SharePoint out, without bothering with the full integration you can do what is described here. The example in this article uses jQuery library which is hosted on Google Code (rather than in your 12 hive) and it dynamically queries the SharePoint web service to retrieve your current tasks, then visualizes them on the page. No need to develop a web part, it is just as simple as that!

You should also check this out, although for some reason I couldn’t get it to work. Basically this is supposed to let you test any jQuery code, from a small ‘editor’ on your home page.

Benefits
So what are the benefits of using jQuery in SharePoint?

AJAX
Well, obviously it adds AJAX functionality to your SharePoint web application. You can now retrieve and visualize data asynchronously, without putting any load on the SharePoint server. It also allows you to create more appealing and faster UI.

Page elements control and flexibility
Additionally, SharePoint allows you to change content structure for subsites, lists, libraries, views, columns, content types and the Web parts, but sometimes that’s not enough. Sometimes developers/designers or users need to make changes to the functionality and appearance of a SharePoint site in a way that is not allowed by the IT department. Since SharePoint Designer is usually restricted, we need an alternative way. That would be jQuery. Just to give you a concrete example of such situation, here is a guy who had to make the corners of the quick launch menu rounded.

jQuery saves development time
jQuery simplifies the way you traverse HTML documents, handle events, perform animations, and add Ajax interactions to your web pages. To summarize it one sentence only: couple of lines in jQuery allow you to do better what you could do with over 20 lines of JavaScript.

Many other…

  • You don’t have to check for null objects
  • CSS3 compliant and has a great CSS selector integration
  • Huge community which supports it. Many tutorials out there…
  • Simple and fast development
  • Lightweight!
  • etc…

Performance
jQuery 1.3 is fast. As in the “fastest JS framework out there”. Here are some nice tips on how to write a fast jQuery code.

Debugging jQuery in SharePoint
FireBug is the preferred way to debug jQuery (and JavaScript in general). Here is a nice article which goes into details.

Examples
http://www.endusersharepoint.com/THE “jQuery & SharePoint” website.
jQuery sparklines
Showing random images in SharePoint 2007 using jQuery
Highlight SharePoint List rows conditionally
Paging large content in SharePoint using jQuery
Many other…

SharePoint Web Services Wrapper

Recently I noticed that a common reason for developers to seek help on the MSDN forum is related to difficulties understanding and/or utilizing the SharePoint Web Services. You can’t blame the developers. It’s much more convenient to work with an Object Oriented API, rather than exchanging XML messages with a Web Service. For example, take a look at the Lists.asmx -> GetListItems. Of course it’s no rocket science, but it will sure save time if you could avoid dealing with the XML directly.


I spent some time researching if there is some kind of a library out there which provides ‘managed’ access to those Web Services. I.e. – work with .NET objects, rather than construct and parse XML elements. The closest thing I have found is this and it’s totally outdated and incomplete. At least it’s some reassurance to me that I am not missing the big picture and indeed, there might be people who would appreciate such framework.

So, I decided to start a project which will try to implement such .NET Object Oriented API around the SharePoint Web Services. Of course, for those corner weird cases (as well for the advanced developers), the underlying XML will still be accessible. Here is a good description of all the SharePoint services. My goal is to cover them all, eventually. I will start with the most commonly used ones.

It is hosted on CodePlex – http://spwebserviceswrapper.codeplex.com/
The project is not published yet, as there is no single line of code written yet. I will be doing this in my spare time. Once I shape it to my liking, it will become open source and everyone is welcome to contribute.

Got comments? Suggestions/Objections? There is a similar library already implemented? Please do let me know.

Hristo