views:

34

answers:

3

Hi Guys,

Doing some client-side JavaScript development, which requires me to call a client-side API which only accepts one parameter at a time (cough, cough, facebook).

Basically i need to call an API method twice:

someFBApi.requestPerms('email')
someFBApi.requestPerms('publish_stream')

Now, i have a wrapper function for this call which looks like this:

function requestPermission(permission, callback) {
 someFBApi.requestPerms(permission, callback);
}

But the problem is, i have to call the function "requestPermission" twice from all over the place:

requestPermission('email', function(perm1granted) {
   requestPermission('publish_stream', function(perm2granted) {
      // do something with perm 1 and perm 2

I would like to be able to do this:

requestPermissions('email,publish_stream', function(firstPerm,secondPerm) {
   // do something with firstPerm, secondPerm

I know i have to call FB API twice (fine), but i want that 'doubling up' to occur in that function (not all over the place). Know what i mean?

So, i'll accept an answer of two forms:

  • Can i pass an array of strings, iterate through those? (maybe JSON?)
  • Delimeted-string, then split the string in the function.

Keep in mind the function returns a value indicating whether or not the permission was granted. So it needs to accept an array/delimited list of strings and return an array/delimited list of strings.

The more simple the solution, the better. (jQuery fine)

+2  A: 

Don't be tempted to use the string parsing solution. An array is cleaner and simpler:

/* note: permisions is expected to be an array */
function requestPermission(permissions) {
    for (var i=0; i<permissions.length; i++) {
        doSomething(permissions[i]);
    }
}

Now, the only problem would seem to be what to do with the callback. I'm assuming that the API is asynchronous and you'd want something like this:

doSomething(when_done)->doSomething...(finally)->execute_callback

For that you can use a sort of recursion. Except it wouldn't really be recursion in the traditional sense since each call happen asynchronously. Something like:

/* note: permisions is expected to be an array */
function requestPermission(permissions,callback) {
    var p = permissions.shift();
    var f = callback;
    if (permissions.length > 0) {
        // if this is not the last permission then
        // call this function again in the callback:
        f = function () {
            requestPermission(permissions,callback);
        }
    }
    someFBApi.requestPerms(p,f);
}

Now you can use it like this:

requestPermissions(['email','publish_stream'],finalCallback);
slebetman
I like this. It creates a chain of calls and calls your callback at the end.
Marco
Spot on. Thanks. (I gave you the answer over @John Kugelman) because although both answers are the same and correct, you got in 14 seconds earlier. =)
RPM1984
FWIW this doesn't keep track of the result of each permission request.
John Kugelman
@John: It could easily be added in. I didn't know the details of the API he's calling so don't know the function prototype expected by the callback. I'm just giving a general idea of the mechanism as clearly and simply as I can.
slebetman
+2  A: 

Using some array juggling you can drain items from a permissions array while accruing results in a results array. Tricky use of requestPerms's callback parameter will have our function be called once for each permission request to be performed, culminating in a call to the user's callback function once all of the permission requests have been performed.

function requestPermissions(permissions, callback, results) {
    if (typeof(results) == "undefined") {
        results = [];
    }

    // Call requestPerms with the first element in permissions and have
    // it add the result to the results array and then call requestPermissions()
    // again recursively to handle the next request.    
    if (permissions.length > 0) {
        var permission = permissions.shift();

        someFBApi.requestPerms(permission, function(result) {
            results.add(result);
            requestPermissions(permissions, callback, results);
        }
    }
    // We've handled all of the permission requests, so now--finally--call the
    // user's callback function.
    else {
        callback.call(results);
    }
}

# Usage
requestPermissions(
    ['email', 'publish_stream'],
    function(emailPerm, publishPerm) {
        // Do something with emailPerm and publishPerm.
    }
);

This is completely untested, but hey, that's what you get for free!

John Kugelman
Although i didnt give you the "correct" answer, this is still correct. +1
RPM1984
A: 

.

function requestPermissions(permissions, callback, ret) {
    // ret is a map of the success of the permissions
    if (!ret) ret = {};

    // Request the first permission in the array.
    FB.requestPerms(permissions[0], function (r) {
        ret[permissions[0]] = r;

        // If it was successful and there are more permissions 
        // to ask for, call requestPermissions again.
        // (If it wasn't successful, don't continue.)
        if (r && permissions[1])
            requestPermissions(permissions.slice(1), callback, ret);

        // Otherwise, call the callback.
        else
            callback(ret);
    });
}

requestPermissions(['email', 'publish_stream'], function (success) {
    if (success['email'] && success['publish_stream'])
        // ...
});

The above solution works sequentially, that is, one after another. I'm not sure how the Facebook API works, but if it allows requesting multiple permissions simultaneously, this could work too:

function requestPermissions(permissions, callback) {
    var ret = {};
    var count = permissions.length;

    // jQuery to make things easier
    $.each(permissions, function (i, value) {
        FB.requestPerms(permissions, function (success) {
            ret[value] = success;

            if (--count == 0) // Last one?
                callback(ret);
        });
    });
}
Casey Hope