Hello kind readers…
So at times Sandbox solutions translates to some frustrating hours do usually leave you with some learning's… and I have one to share, pardon me if you already know about this,
Recently we had a requirement that when we have a URL column in the list and if the user is trying create an item in that list then instead of having to copy paste or type a Url they should have an option to browse the site collection and choose link.
Now generally a direct approach would be to create a custom new form with the Asset URL picker control and deploy it with the list as the new item form to be used, but with sandbox challenges always come and second it was just a requirement for browsing so didn't make sense to go through all the hassle of creating a custom new form.
Some findings… so when you have a image field on your new item page and you click on it to add a image then a nice picker dialog is opened where you can choose the image or hyper link. Now if you check when you do have such a field that by default comes with a picker functionality then there are two additional JS files AssetPickers.js and SelectorControls.js also called on the page which basically has the code for calling the picker dialog and all but if you don't have such a field these files are not loaded and you can't just call the functions which you copied from the page view source on these field :)
The challenge:
The new item form page would have a URL field, the URL field by default comes with a hyper link saying (test this url), so we need to change the text of the link to (Pick a link for the file) and then call the asset picker to choose the file and send it back to the URL textbox
The Approach:
Being a big fan of Jquery and Client object model I think of them as first weapons and they don't fail me :). So what I did was created a custom js file and referenced it in the master page which would check the URL of the current page to see if it’s the New Form page of the respective list and if it is.. Fires the required functions.
If(url containns /lists/mylist/newForm.aspx) // you can have any condition based on your requirement
{
$("a[id$='_UrlControlId']").removeAttr('onclick'); //remove default functionality
$("a[id$='_UrlControlId']").html('Pick a link for the file'); //change the link text
$("a[id$='_UrlControlId']").click( function () {
//attach your custom functionality
});
}
So far so good… this seemed to work fine and changing the link text and click event, BUTTTT still how to get the asset picker dialog as the two js files I talked about before don't load on this page…. So came the answer with some digging…
Basically when you click a image button to choose an image it calls the AssetImagePicker.aspx which again has 2 browse buttons for calling image or hyper link, but in my case I was looking for ONLY hyper link… so I wanted to browse the whole portal and choose the link … and to my help came the wonderful page… AssetPortalBrowser.aspx this is the dialog that is called when you want to browse.. Now you can't just call the page by /_layouts/AssetPortalBrowser.aspx
but you would need some default query string parameters to make it work as you want. So the Url should look like..
SiteRelativeURL+'/_layouts/AssetPortalBrowser.aspx?&AssetUrl='+SiteRelativeURL+'&RootFolder='+SiteRelativeURL+'&MDWeb='+webID+'&AssetType=Link
So you call the layouts page in with the root site relative url , and the query string params,
- AssetUrl = give the server relative URL of the site you want to browse
- RootFolder = again give the server relative URL of the place you want to look into within the site by default
- MDWeb = web GUID of the site you are looking into
- AssetType = the kind of asset this browser is used for
With these params in place you get the AssetPortalBrowser page as expected… but the task is still half done..
Now once you know how to get the page, you still want it to come out as a pop from the link on your URL field and also on closing the popup should get the values back in the URL field text box of your item… so what do we do now…
Before that.. We need to know the web id as well of the root site.. As the site server relative url can be found on the page itself in a javascript variable.. I wrote about the variable in
my earlier
posts but for root web id you need the Client Object model, that’s fairly simple. Now for the popup we use the
SP.UI.ModalDialog framework, so on you click event of the link you use the
SP.UI.ModalDialog.showModalDialog(options); … now what is options… options is the object which we will send with the required parameters, so the options object looks like this
var options = {
title: 'Custom title for Dialog',
width: 400,
height:600,
url: _spPageContextInfo.siteServerRelativeUrl+'/_layouts/AssetPortalBrowser.aspx?&AssetUrl='+_spPageContextInfo.siteServerRelativeUrl+'&RootFolder='+_spPageContextInfo.siteServerRelativeUrl+'&MDWeb='+webID+'&AssetType=Link,
dialogReturnValueCallback:myDialogCallback
};
The dialogReturnValueCallback is à important argument as this the function that is called when the dialog is closed, so when the dialog is closed myDilaogCallback will fire with whatever return value is sent from the dialog.
Now so far I was able to change the text on the URL hyper link and attach my custom click event to pop up the asset portal browser to browse the site collection and choose a document BUT when I click ok it would just refresh and do nothing… which was a bummer as I thought that would be handled by SharePoint itself… but it wasn't … now again Jquery came in for help… (I will by Jquery a chocolate this time ;) ) .. So what I did was .. Since I know the custom dialog title I am passing for the dialog and the custom JS files on master page are also run on these dialogs so I check in my JS file if the dialog has the respective custom title and if yes, fire my custom function that will remove the default function of the OK button and put my custom function on click event of the button… so it becomes to be…
var okBtn = jQuery("input[value='OK']");
if(okBtn.length > 0)
{
okBtn.removeAttr('onclick');
okBtn.click(function () {
var urlval =jQuery("input[id$='LocationUrl']").val();
//the result should be OK as this will tell that ok was clicked.. And 2nd param sends the value I want back in text box
SP.UI.ModalDialog.commonModalDialogClose(SP.UI.DialogResult.ok, urlval);
});
}
Now when I click the ok button it does not refresh or anything simply closes in a flash and sends back the URL value to the text box :)
So finally we have the link on the URL field which used to test the URL originally now popping up the default SharePoint portal browser for me and after I choose the file is sending it back to my call back function in which I can populate the respective text box.
Now there are still lot many improvements to this… I don’t want to write more … m tierd :( … so what I mean is like you can load the scripts only on respective pages using the SOD.Register script and executeFunc … and that kinda improvements.
Hope this helps and gives you an idea… on how you can use the same process to link this functionality to basically any HTML element or dynamically created HTML element from Jquery... to do the functionality for you.
NOTE: When you are using Jquery and dialog pages or for that matter SP2010.. Try using the Jquery no conflict and use jQuery instead of $ as the dollar sign is used by SharePoint as well internally and causes random errors.
- "T"