i need jquery to fire when people picker returns the value to the main form from the browse pop up window
Asked Answered
C

5

6

has anyone attempted trying to fire jquery change event when people picker returns the value to the main form from the pop up browse window? i have tried several tags in the jquery statement but nothing seems to work. (SP 2010)

<wssawc:PeopleEditor AllowEmpty="false" AcceptAnyEmailAddresses="true" ValidateResolvedEntity="true"
ShowButtons="true" ShowDataValidationErrorBorder="true" ShowEntityDisplayTextInTextBox="true"
ShowErrorPlaceHolder="true" ValidatorEnabled="true" MultiSelect="false" ID="primaryOwnerPicker"
runat="server" SelectionSet="User" Width="12em" AllowTypeIn="false" DoPostBackOnResolve="false"
EnableBrowse="true" ForceClaims="true" Title="Primary Owner People Picker" />

i have tried

$("textarea[title='Primary Owner People Picker']").change(function ()
{
    alert("here");
});

any help would be greatly appreciated...

Conchiolin answered 7/9, 2011 at 1:42 Comment(1)
Very useful question , thnx sir :)Morbilli
U
14

You didn't specify the version of SharePoint but the following explanation applies to SharePoint 2007 and was not confirmed in 2010.

The people picker's value can be set by clicking the 'Check Names' icon or the 'Browse' icon.

If you click the 'Check Names' icon which is an anchor tag, the onclick event invokes 'WebForm_DoCallback' which will asynchronously make an HTTP request to the SharePoint server to validate the name entered into the people picker.

Following is the WebForm_DoCallback signature:

function WebForm_DoCallback(eventTarget, 
eventArgument, 
eventCallback, 
context, 
errorCallback, 
useAsync){
...
}

One of the WebForm_DoCallbacks argument that that you will be most interested in is 'eventTarget', the people picker text area. You will also be interested in 'eventCallback' as it's the callback method invoked after the async HTTP request returns. In this case, it's 'EntityEditorHandleCheckNameResult(result, ctx)' defined in core js.

Following is the definition of the EntityEditorHandleCheckNameResult function

function EntityEditorHandleCheckNameResult(result, ctx)
{
   EntityEditorClearWaitCursor(ctx);
   EntityEditorCallback(result, ctx);
} 

Notice that it delegates the event handling to the EntityEditorCallback method. This is also the case if you click the 'Browse' icon which opens a dialog for you to find and select a user. The 'Browse' icon obviously leverages a different call stack but as they both rely on EntityEditorCallback, I will focus on this method as the solution works when you click 'Check Names' or 'Browse'.

To execute your code after EntityEditorCallback is invoked, you can leverage the following code:

var invokeAfterEntityEditorCallback =  function(func) {
    var old__EntityEditorCallback = EntityEditorCallback;
    if (typeof EntityEditorCallback != 'function') {
        EntityEditorCallback = func;
    } else {
        EntityEditorCallback = function(result, ctx) {
            old__EntityEditorCallback(result, ctx);
        func(result, ctx);
        }
    }
};

Following is a custom people picker event handler which alerts the result and the ID of the people picker text area:

function onPeoplePickerFieldSet(result, ctx){
    alert(result);
    alert(ctx); 
}

Following is logic that will allow the onPeoplePickerFieldSet method to be invoked after the people picker name is checked or selected from the browse dialog. Also, this statement can be invoked in the document.ready event handler if you are using jQuery.

invokeAfterEntityEditorCallback(onPeoplePickerFieldSet);

The 'result' argument of the onPeoplePickerFieldSet method is an XML result indicating successful validation as well as the domain quailified user name. The following XML is an example resulting from click the 'Check Names' icon:

<Entities Append="False" Error="" Separator=";" MaxHeight="3">
   <Entity Key="HOLLOWAY\csteel" DisplayText="Craig Steel" IsResolved="True" Description="HOLLOWAY\csteel">
      <ExtraData>
         <ArrayOfDictionaryEntry xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
            <DictionaryEntry>
               <Key xsi:type="xsd:string">DisplayName</Key>
               <Value xsi:type="xsd:string">Craig Steel</Value>
            </DictionaryEntry>
            <DictionaryEntry>
               <Key xsi:type="xsd:string">Email</Key>
               <Value xsi:type="xsd:string">[email protected]</Value>
            </DictionaryEntry>
            <DictionaryEntry>
               <Key xsi:type="xsd:string">SPUserID</Key>
                <Value xsi:type="xsd:string">16</Value>
            </DictionaryEntry>
            <DictionaryEntry>
               <Key xsi:type="xsd:string">PrincipalType</Key>
               <Value xsi:type="xsd:string">User</Value>
            </DictionaryEntry>
         </ArrayOfDictionaryEntry>
      </ExtraData>
      <MultipleMatches />
   </Entity>
</Entities>

The 'ctx' argument is the ID of the people picker text area and can be used in a jQuery selector statement.

That's it!

Undermanned answered 18/12, 2011 at 16:29 Comment(5)
I did not explicitly state this but subscribing to the people picker text area's change event in jQuery will not work because of the asynchronous nature of the intrinsic solution. Instead, injecting your custom logic per my recommendation is a more reliable solution.Undermanned
Very useful, I even wrote a post about overriding callback method EntityEditorCallback here vgrem.wordpress.com/2013/03/27/…Studio
Huh? Kudos for the knowledge, but your write-up is very confusing. Should he use a $('a[title="Check Names"]').click() or use some API into invokeAfterEntityEditorCallback()? The former is more straight-forward if all he needs is to resolve the name. Giving all the background, without proper context, just muddies the waters unnecessarily - especially since I don't see a use-case to use that API/XML. The value in the people picker can be tested as changed with $('div[title="People Picker"]').html() == x, where x was what it was before so he can know if the name has resolved or not.Hardtop
I still believe the background is sufficient if you want to understand the components at play. I assumed that my target audience did not want to copy and paste code from the web and hope it works. I was also clear when i stated that you cannot handle a jquery click event because there is an async HTTP call to the server that you will not be able to intercept. To avoid a race condition, I provided a more robust solution. All you have to do is shadow/override the default invokeAfterEntityEditorCallback implementation and invoke it with a custom callback in document.ready.Undermanned
Handling the click event and testing the div's HTML does not factor in the async behavior nor the race condition. When are you going to check the value of the div? Network latency, server load etc. will contribute to how long you have to wait before you can check the value in the div. This is pretty significant don't you think?Undermanned
T
1

I used the answer from Athens Holloway above, with a couple tweaks. My use case was excluding a particular user from the people-picker. You can exclude a user from people-picker using peoplepicker serviceaccountdirectorypaths on the central admin server, but for various change control reasons that wasn't an option for us. Adding Javascript to the one particular site let us get the job done without affecting the whole site collection.

This is the complete script that excludes a single user from the People picker:

  var peoplePickerCtx;

  var invokeAfterEntityEditorCallback =  function(func) {
    var old__EntityEditorCallback = EntityEditorCallback;
    if (typeof EntityEditorCallback != 'function') {
        EntityEditorCallback = func;
    } else {
        EntityEditorCallback = function(result, ctx) {
            old__EntityEditorCallback(result, ctx);
        func(result, ctx);
        }
    }
};

function onPeoplePickerFieldSet(result, ctx){
    // gets the long ID string of the people-picker control when the user touches the control
    if (result != undefined) {
      var checkThis = result.toString();
      peoplePickerCtx = ctx.toString();
    }
}

function userMessage (checkThis)
{
    if (checkThis.indexOf("USERNAME TO EXCLUDE GOES HERE") !=-1) 
    {
      alert ('That account is not valid YOUR ERROR MESSAGE GOES HERE')
      return false;
    }
    return true;
}

  function PreSaveAction() {
    // this is a standard function - give it this name and it runs pre-save
    var returnMe = false;

  // used simple getElementById instead of jQuery because it picks up what is actually in the blank. 
  // jQuery picked up the old value until after the user clicked CheckNames button
    var checkThis= document.getElementById(peoplePickerCtx+"_upLevelDiv").innerText.toLowerCase()
    if (checkThis!=undefined) 
    {
        returnMe = userMessage (checkThis)
    }

   return returnMe ;
  }; 


invokeAfterEntityEditorCallback(onPeoplePickerFieldSet);


</script>
Travel answered 8/8, 2012 at 15:30 Comment(0)
L
0

Try this instead:

$("textarea[title='Primary Owner People Picker']").live(function ()
{
    alert("here");
});

And it would be helpful to understand your problem if you can post full html/js code.

Linda answered 7/9, 2011 at 1:47 Comment(1)
.live() is deprecated as of jQuery 1.7, and so is not recommended -- api.jquery.com/live -- use .on() or maybe .delegate() , instead.Hardtop
H
0

How about this:

$("textarea[title='Primary Owner People Picker']").on('change', function ()
{
    alert('here');
});
Hardtop answered 5/12, 2014 at 4:2 Comment(2)
This is the same solution that the OP said didn't work. Am I missing something?Undermanned
He said using .change(function() { ... }) didn't work, but using .on is slightly different: jsperf.com/document-on-click-vs-element-click/2. I mainly wanted to draw attention to the post about .live(), that this was the new way to write that: weblog.west-wind.com/posts/2013/Jun/12/… . And for grabbing the value when the box changes, this answer, when adding something like var name = $(this).val() worked fine for me, so not really sure what the OP needed.Hardtop
K
0

Athen's answer worked like a charm for me. Since validation sometimes throws an error (like multiple matches to a name) I don't want to do my code to run until validation returns no errors. Unfortunately this requires users to click the validation button again after they select the correct name from the multiple returned. Here is just a little additional code I used to parse the result:

function onPeoplePickerFieldSet(result, ctx){
    xmlDoc = $.parseXML(result);
    $xml = $(xmlDoc)
    if($xml.find("Entities").attr("Error") == "")
    {
        getUserData($xml.find("Entity").attr("Key")); //this is the username
    }
}
Kaolinite answered 28/6, 2016 at 21:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.