Saturday, July 14, 2012

Prevent Text Box Selection And Automatically Select Different Control

I ran into an interesting issue where I needed to allow a user to select a contact in a custom SharePoint 2010 application. Preventing the selection of the text box is not as straight forward as one might hope, especially handling cross browser. Since SharePoint has the concept of a People Picker, I decided that I could leverage that pattern to increase application performance. The requirement had several parts:
  1. The result needed to only display the users name
  2. The ID of the contact needed to be saved
  3. The label needs to be able to send the value back to the server, but prevent people from editing the label
The first and third points are solved by using a text box instead of a label. The ID is saved by hiding ID text box so that it is posted back with the rest of the data. We make the solution slightly more elegant by treating the text box like modern browsers handle the file input control; clicking the text box opens the dialog. There is nothing that is specific to ASP.NET and can be easily converted to standard HTML.
<asp:TextBox ID="txtContact" onfocus="focusCtrl('btnContact', event);" runat="server"></asp:TextBox>
<asp:TextBox ID="txtContactID" style="display: none;" runat="server"></asp:TextBox>
<asp:Button ID="btnContact" OnClientClick="return contactPicker('txtContactID', 'txtContact');" Text="Select" CausesValidation="false" runat="server"></asp:Button>
<asp:RequiredFieldValidator ID="rfvContact" ControlToValidate="txtContact" ErrorMessage="Contact is required" ValidationGroup="Required" Display="Dynamic" InitialValue="" CssClass="ms-error" EnableClientScript="false" runat="server">
    <img alt="Validation Error" title="Contact is required" src="/_layouts/images/EXCLAIM.GIF" />
</asp:RequiredFieldValidator>
<script type="text/javascript">
     $(function () { focusCtrl('btnContact'); });
</script>
A couple important notes about the focusCtrl function, the code above assumes that the specified control will be initially selected, but the same function is used for the text box focus event with different outcomes. The initial run without the event won't pass an event into the function which won't trigger the control click event. Once the focus event has fired off an event is passed in and causes the controls click event to fire. I included a version of the contact picker function to show how we are populating controls on the callback.
function focusCtrl(ctlID, e) {
    var ctl = $('input[id$=\'' + ctlID + '\']');
    e = e || window.event;
    var t = (e) ? e.target || e.srcElement : null;
    if (ctl.length > 0) {
        ctl.focus();
        if (t != null) {
            ctl.click();
        }
    } else if (e || window.event) {
        $(t).blur();
        //Focus next textbox
        //$(t).next("input:not(input[type='submit']):visible").focus();
    }
    return false;
}

function contactPicker(txtID, txtLabel) {
    var options = {
        url: '../Contacts/ContactPicker.aspx',
        title: 'Contact Picker',
        allowMaximize: true,
        showClose: true,
        showMaximized: false,
        dialogReturnValueCallback: function (dialogResult, returnValue) {
                                        if (dialogResult == SP.UI.DialogResult.OK) {
                                            var ret = unescape(returnValue),
                                                name = ret.split(";#")[1];
                                            $("input[id$='" + txtName + "']").val(name);
                                            $("input[id$='" + txtID + "']").val(ret);
                                        }
                                    }
    };
    SP.UI.ModalDialog.showModalDialog(options);
    return false;
}

No comments: