| | Stumble It! | Add to Mixx! | | diigo it | | Slashdot |

Friday, March 26, 2010

SharePoint - Prevent User from Selecting Certain Dates

I've been getting smart on jQuery a lot lately and haven't had a lot of time to spend on cool new SharePoint hacks, but yesterday I had a request to add this little feature to one of the lists that I manage.

Very generally speaking, the list coordinates network maintenance and we've found that submitters won't check to see if a day is full of maintenance events before they submit a request. My task was to add a function to the form to check if the day that had been selected was flagged as full.

My solution came in a few steps:
  1. Create a second list that just contains dates that have been flagged as full. The maintenance coordinators simply add new dates to this list as they fill up. You'll need to go through the code of this list and pull out the ID attribute for the table. Load the page in your browser, view the source code, and look for a table tag with the class of "ms-listviewtable". This is the ID that you want to copy. Also copy the URL for the list. You'll need to provide both strings to the script below.
  2. Add this JavaScript code to a Content Editor Web Part on the NewForm.aspx page (using the "NewForm.aspx?ToolPaneView=2" trick) to pull, parse, and compare the dates that have been flagged as full to the dates that have been selected in a date field.
    <script type='text/javascript'>

    var tbl_id = 'YOUR BIG LONG TABLE ID GOES HERE!!!';
    var url = 'http://path/to/your/List/AllItems.aspx';

    function read_locked_dates() {
    var ifm = document.getElementById('locked_days_list');
    if (ifm.src != url) { ifm.src = url; return false; }
    var doc = (ifm.contentWindow) ? ifm.contentWindow.document : ifm.contentDocument;
    var tbl = doc.getElementById(tbl_id);
    var nobrs = tbl.getElementsByTagName('nobr');
    for (var n=0;n<nobrs.length;n++) {
    blocked_dates.push(nobrs[n].innerHTML);
    }
    }

    function insert_date_check() {
    // this will detect manual updates to the date
    var inputs = document.getElementsByTagName('input');
    for (var i=0;i<inputs.length;i++) {
    if (inputs[i].parentNode.className == 'ms-dtinput') {
    if (inputs[i].attachEvent) { inputs[i].attachEvent('onchange',check_this_date); }
    else { inputs[i].addEventListener('change',check_this_date,false); }
    }
    }
    // this will detect updates to the dates done via the calendar clicker
    var ifms = document.getElementsByTagName('iframe');
    for (var i=0;i<ifms.length;i++) {
    if (ifms[i].getAttribute('title').match(/Select a date from the calendar./i)) {
    if (ifms[i].attachEvent) { ifms[i].attachEvent('onload',check_this_date); }
    else { ifms[i].addEventListener('click',check_this_date); }
    }
    }
    }

    function check_this_date() {
    var picked_dates = [];
    var dates = document.getElementsByTagName('input');
    for (var d=0;d<dates.length;d++) {
    if (dates[d].id.match(/DateTimeField/i)) {
    picked_dates.push(dates[d].value);
    for (var b=0;b<blocked_dates.length;b++) {
    if (dates[d].value == blocked_dates[b]) {
    dates[d].style.background = 'red';
    dates[d].value = 'date blocked';
    return false;
    } else {
    dates[d].style.background = '';
    }
    }
    }
    }
    }
    var out = document.getElementById('output');
    var blocked_dates = [];
    _spBodyOnLoadFunctionNames.push('read_locked_dates');
    _spBodyOnLoadFunctionNames.push('insert_date_check');

    </script>
Once you've added this to your NewForm.aspx page, anytime someone tries to edit a date field, it will check the date they've picked against the list you provide & prevent them from picking the date if it's flagged.

Cheers!

1 comments:

Dunda said...

If I wanted to prevent users from selecting weekends, could I create the second list for weekends by using a recurring event every weekend (Sat & Sun)? Or would this only have one item in the list and thus not work properly?