0

I used some code from Check if Current Users belongs to SP group using javascript Client Side Object Model to check if a SP user is in a SP group. I wanted to loop through some groups for a user, so I stuck that code in a loop. However the code only executes on the last value of the loop array. Any thoughts?

function addSchools() {
    for (var i = 0; i < schoolArray.length; i++) {
      groupId = schoolArray[i][2]
      optionText = schoolArray[i][0]
      console.log(optionText)
      isUserMemberOfGroup(currentUserId, groupId,
        function(isCurrentUserInGroup) {
          if (isCurrentUserInGroup)
            console.log('yes');
          else
            console.log('no');
        },
        function(sender, args) {
          console.log(args.get_message());
        });;;
    }

The output looks like:

schoola
schoolb
schoolc
shooold
yes

instead of

schoola
yes
schoolb
no
schoolc
yes

isUserMemberOfGroup:

function isUserMemberOfGroup(userId, groupId, success,error) {

 var ctx = SP.ClientContext.get_current(); 
 var allGroups = ctx.get_web().get_siteGroups();
 var group = allGroups.getById(groupId);
 ctx.load(group,'Users');

 ctx.executeQueryAsync(
    function(sender, args) {
        var userInGroup = findUserById(group.get_users(),userId);
        success(userInGroup);
   },
   error);    

   var findUserById = function(users,id){
       var found = false;
       var e =  group.get_users().getEnumerator();
       while (e.moveNext()) {
            var user = e.get_current();
            if (user.get_id() == id) {
                found = true;
                break;
            }
       } 
       return found; 
   };

}

Community
  • 1
  • 1
As3adTintin
  • 2,406
  • 12
  • 33
  • 59

3 Answers3

0

isUserMemberOfGroup() takes a callback that logs 'yes' or 'no', so by the time that callback gets called, all the iterations of the loop have finished and all the schools have been logged. Consider moving the school logging into the inside of the callback to preserve synchronicity.

EDIT: Adding some code.

function addSchools() {
schoolArray.forEach(function (item) {
  groupId = item[2]
  optionText = item[0]
  console.log(optionText)
  isUserMemberOfGroup(currentUserId, groupId,
    function(isCurrentUserInGroup) {
      console.log(optionText);
      if (isCurrentUserInGroup)
        console.log('yes');
      else
        console.log('no');
    },
    function(sender, args) {
      console.log(args.get_message());
    });;;
}
}

By using the array.forEach() method you can tuck each loop instance into a isolated scope so you don't have to worry about variables getting overwritten.

Cameron
  • 434
  • 2
  • 4
  • Thanks! I sort of know what a callback is (i've red a few documents but am still confused). Where is the callback in the `isUserMemberOfGroup()` function? – As3adTintin Jan 22 '16 at 21:24
  • You are passing it in as the third parameter, it is `function(isCurrentUserInGroup) { ... }`. It's basically a function and when the `isUserMemberOfGroup()` is finished it will call that function passing a boolean indicating its result as the parameter `isCurrentUserInGroup` so you can use it. – Cameron Jan 22 '16 at 21:34
  • In short, a callback is a function you pass as a parameter to an async function. When the async function is finished, it will invoke (call) that callback with the return value. While the async function is working, the rest of your code keeps going, which provides a smooth user experience. – Cameron Jan 22 '16 at 21:38
  • hmm ok thanks for helping me understand. so would I want to put the school logging next to `var found = false` and `found = true` in `isUserMemberOfGroup`? – As3adTintin Jan 22 '16 at 21:42
  • Oh whoops, I hadn't noticed that you posted that method implementation as well. I would keep the logging together, meaning keep all of it in the schools method. Unfortunately it isn't as easy as g.sui's answer suggests, as you are sharing the scope asynchronously so option text will always be logged as the last school in the loop, i.e. schoolc. The easiest way to fix this would be to use array.foreach assuming you are programming for a browser that supports that method (if not consider downloading the underscore library). I will write some code in my original answer in a second. – Cameron Jan 22 '16 at 21:57
  • Thanks so much for your help. I do use underscore.js in parts of this script already so that might be best. In the meantime i have played with `ctx.executeQueryAsync( function(sender, args) { var userInGroup = findUserById(group.get_users(),userId); console.log(optionText) console.log('yes') option.text = optionText x.add(option); }, console.log('no') ); ` – As3adTintin Jan 22 '16 at 22:01
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/101437/discussion-between-cameron-morrow-and-as3adtintin). – Cameron Jan 22 '16 at 22:10
0

function addSchools() {
    for (var i = 0; i < schoolArray.length; i++) {
      groupId = schoolArray[i][2]
      optionText = schoolArray[i][0]
      //console.log(optionText)
      isUserMemberOfGroup(currentUserId, groupId,
        function(isCurrentUserInGroup) {
          console.log(optionText) //put it here!
          if (isCurrentUserInGroup)
            console.log('yes');
          else
            console.log('no');
        },
        function(sender, args) {
          console.log(args.get_message());
        });;;
    }
g.sui
  • 1,550
  • 3
  • 15
  • 20
  • Thanks for the suggestion. This results in `schoolc` `yes`, where the user is not even in `schoolc`. – As3adTintin Jan 22 '16 at 21:31
  • To make this solution work you need to use array.forEach (or something else that wraps the loop implementation in an isolate scope) instead of a basic for loop, otherwise the optionText variable will have its value changed synchronously before it gets logged asynchronously. – Cameron Jan 22 '16 at 22:24
0

just got it to work using:

ctx.executeQueryAsync( 
 function(sender, args) { 
  var userInGroup = findUserById(group.get_users(),userId); 
  console.log(optionText) 
  console.log('yes here we go ' + optionText) 
  var option = document.createElement("option"); 
  option.text = optionText 
  x.add(option); 
 }, 
error ); 

Thanks everyone for your input!

As3adTintin
  • 2,406
  • 12
  • 33
  • 59