Leveraging callback variables.

For developers using the Construct 2 Javascript SDK

Post » Thu Aug 08, 2013 9:52 pm

Hello all,

I'm in the process of writing plugins to expose BlackBerry 10 APIs to Construct 2 developers. Everything has gone smoothly until now as the process has been:
  • Invoke API.
  • Let API do its thing.
  • API finishes, trigger Conditions to allow response Actions.

  • Now I need to make the returned values accessible to the developer so they can leverage the data in their own logic.

    For example, I am calling an API that returns an array of Purchases (i.e. things the end-user has bought for the application.)
         /* Action: getExistingPurchases */
         Acts.prototype.getExistingPurchases = function () {
              var _this = this;

              if (typeof blackberry !== 'undefined') {
                  blackberry.payment.getExistingPurchases(
                        true,
                        function onSuccess(data) {
                             _this.callbackArgs = data;
                             _this.runtime.trigger(cr.plugins_.blackberry10.prototype.cnds.onGetPurchasesSuccess, _this);
                        },
                        function onFailure(error) {
                             _this.callbackArgs = error;
                             _this.runtime.trigger(cr.plugins_.blackberry10.prototype.cnds.onGetPurchasesFailure, _this);
                        }
                  );
              }
         };
    On success (or failure) the functions trigger a Condition to allow certain actions to take place. But at that point, it seems to me that data (or _this.callbackArgs) is simply lost. Most of the time the developer will want to loop through the results on their own and take actions (i.e. ensuring a purchased level is unlocked, etc.) but I'm just not sure how to make that accessible to them.

    Does anyone happen to have any insight here? If I can clarify at all, please let me know.

    I just don't see how to bridge the gap between a developer needing to use the data, and having the data in a callback function of my plugin. I feel Expressions may be involved here but haven't found a proper path forward.WaterlooErik2013-08-08 21:53:20
    B
    4
    S
    1
    Posts: 79
    Reputation: 808

    Post » Tue Aug 13, 2013 3:09 pm

    I think I've managed to find an approach here.

    On application Startup, the intent will be to use the BlackBerry10 Object and call GetExistingPurchases.

    Then, if you want to check purchases at Runtime, there will be a BlackBerry10 method for CheckExistingPurchase (where you pass the ID of the good to check.)

    The missing link is taking the Array returned by GetExistingPurchases and storing it as some usable variable that can be referenced later. Is this where Expressions come in? How would I go about creating a a global, member variable for the BlackBerry10 Object?

    Any advice would be greatly appreciated.


    EDIT: I think I've got it with Expressions. I'll give it a shot here and will follow-up if I have further questions or (ideally) post my solution.WaterlooErik2013-08-13 15:48:50
    B
    4
    S
    1
    Posts: 79
    Reputation: 808

    Post » Tue Aug 13, 2013 7:39 pm

    Sorry, I missed this thread at first. The original code sample you gave is fine, you'd just make an expression to return the value of this.callbackArgs and just document that the expression can only be used in the trigger event. I'd recommend using separate variables instead of just one callbackArgs though, so you don't get confused between the error/success event data.

    Edit: for another example see other plugins like AJAX or Array - AJAX saves the received data ("last data") then fires a trigger, and has an expression to get the last data. Array has some expressions to get variables at given indices in the array.Ashley2013-08-13 19:42:58
    Scirra Founder
    B
    399
    S
    236
    G
    89
    Posts: 24,529
    Reputation: 195,400

    Post » Tue Aug 13, 2013 9:00 pm

    Thanks Ashley, I've managed to make some good progress and am just short of being complete. I have one last issue in the sample I am creating. You can see my defined event flow here.

    On loader layout completion, I...
  • Log the progress.
  • Call GetExistingPurchases.
  • Call RegisterBBM.

  • This part seems to work fine, and GetExistingPurchases will either trigger success or failure as follows.
    ...
    blackberry.payment.getExistingPurchases(
         true,
         function onSuccess(data) {
              cr.plugins_.blackberry10.prototype.exps.existingPurchases = JSON.stringify(data);
              _this.runtime.trigger(cr.plugins_.blackberry10.prototype.cnds.onGetPurchasesSuccess, _this);
         },
         function onFailure(error) {
              cr.plugins_.blackberry10.prototype.exps.PaymentError = error.errorText + ' (' + error.errorID + ')';
              _this.runtime.trigger(cr.plugins_.blackberry10.prototype.cnds.onGetPurchasesFailure, _this);
         }
    );
    ...
    So far, we're good. The request actually fails (since I've been side-loading and there is no connection to the Payment servers yet.) So, in the diagram, BlackBerry10.onGetPurchasesFailure is triggered as expected.

    However, my output is only:
    Payment (Failure): Get existing purchases.

    Where I would expect two additional lines to be logged as well. Specifically:
    1) A newline and the contents of PaymentError.
    2) A new line and "Shazam2!"

    But neither of those two actually show; it's as if something stops execution, but Web Inspector logs no errors.

    If I need to clarify anything at all, please just let me know. I'll continue hammering away here, but if anybody has any insight, again I'm happy to hear it.

    Cheers!
    B
    4
    S
    1
    Posts: 79
    Reputation: 808

    Post » Wed Aug 14, 2013 10:25 am

    This line looks wrong:

    cr.plugins_.blackberry10.prototype.exps.PaymentError = ...

    Why not just assign to _this.paymentError or just a paymentError variable in the closure scope? (Everything should be wrapped in a big function that is called on startup, so you can put variables outside of functions and they're closure scoped, not global.)

    As it stands, it looks like you're overwriting the function that is called for the PaymentError expression with something else.
    Scirra Founder
    B
    399
    S
    236
    G
    89
    Posts: 24,529
    Reputation: 195,400

    Post » Wed Aug 14, 2013 3:17 pm

    Ah, I assumed accessing those Expressions worked the same way as accessing a Condition to be triggered. But can see the flaw in that now. I will give this a try and will let you know. Thanks again for the insight!

    Edit: I took a look at the WebSocket plugin and I have been misusing Extensions. It's all coming together now...

    Solved: I was using Expressions as variables instead of functions that return values based on variables; if that makes sense. Looking at some of the other plugins made it clear and (pending final testing) stay tuned for BlackBerry Messenger (Register, Set Status, and Invite Others To Download) and In-App Payment (Purchase Good, Check Good Price, and Get Existing Purchases List) being made available in the coming days.

    Thanks again!WaterlooErik2013-08-14 20:02:05
    B
    4
    S
    1
    Posts: 79
    Reputation: 808

    Post » Thu Aug 22, 2013 6:26 pm

    If anyone else comes along to this thread, just wanted to share this so you can see my final implementation:
    https://github.com/blackberry/Construct2Plugins
    B
    4
    S
    1
    Posts: 79
    Reputation: 808


    Return to Javascript SDK

    Who is online

    Users browsing this forum: No registered users and 0 guests