How to hook into response, error when commiting through a model?

Hi Enyo Folks!
I find examples of how to hook into the response or error when working directly with enyo/Ajax, but I want to process the JSON returned from a Model.commit(). Can someone point me to an example of that?

Comments

  • Just in case I'm using the wrong terms... I'm sending login credentials (username, password) with a Model.commit() to a Loopback API. The API responds with a JSON payload that includes an access_token (unhelpfully keyed as "id"), the ttl for that token, token creation date and user_id. I want to add all of those elements to the model but with the access token renamed to access_token.
    I can't figure out how to get that response JSON so I can do that.
    I also need to handle the error case.
    I can't imagine it helps much, but here is the Model:
     var UserLoginModel = kind({
      name: "UserLoginModel",
      kind: Model,
      source: 'mftLoginSource',
      url: mftApiUrl + 'mftUsers/login'
    });
  • I think you'll want to override the {{parse}} method of Model to transform the data.

    http://enyojs.com/docs/latest/index.html#/kind/enyo/Model/Model:parse
  • edited August 2016
    Thanks @theryanjduffy ,
    Yes, I'll want to parse that response, but first I need to access it. I assume that if I were doing a fetch the JSON response would be added to the model, but I am commiting because the Loopback login wants the credentials in a POST.
    The login works with the commit, but the response JSON is not pulled into the Model. My biggest question is how to pull that response into the Model and once that is working I can worry about parsing "id" into "access_token".
  • I wonder if maybe you should just override "fetch" in your source. This is something I am doing for an app that I have built. Not sure if it is the correct way to accomplish the task but I know its how it works for me. I override "fetch" in one of my sources, then in the fetch I do the ajax POST, and in the ajax.response I pass the data back to opts.success. I then parse my data in my collection but I would think you could do the parse in the model.

    Below is an example of what I am saying... Keep in mind I did not test this code, but I believe it may get you close to what your are needing.
    
    var kind = require('enyo/kind'),
        EnyoSource = require('enyo/Source'),
        Ajax = require('enyo/Ajax'),
        Model = require('enyo/Model');
    
    var MftLoginSource = kind({
        name: 'mftLoginSource',
        kind: EnyoSource,
        fetch: function (rec, opts) {
            // implement code to fetch records
            var ajax = new Ajax({
                url: mftApiUrl + 'mftUsers/login',
                method: 'POST'
            });
            ajax.go();
            ajax.response(this, function (inSender, inResponse) {
                opts.success(inResponse.value); // call success callback to return data
            });
            ajax.error(this, function (inError, err) {
                var errorParse = JSON.parse(inError.xhrResponse.body);
                var ajaxError = errorParse.msg;
                opts.fail(ajaxError);
            });
        }
    });
    new MftLoginSource({ name: 'mftLoginSource' });
    
    var UserLoginModel = kind({
        name: "UserLoginModel",
        kind: Model,
        options: { parse: true },
        source: 'mftLoginSource',
        parse: function (data) {
            // modify you data
            return data;
        }
    });
    
  • Hi @Fred_D_Castillo ,
    Thank you so much! It seems like this strategy might work, but I somehow need to get the postBody to MftLoginSource. What I'm doing now is setting the username and password for the mftLoginModel from the appropriate onyx/Inputs and that is why commit works. I need to figure out how to get that into a postBody param for the MftLoginSource
  • Maybe instead of doing what I said in fetch, you do your work in commit.
    Looking at the doc on "Building Data-Driven Apps", they have an example of working with the Facebook JS SDK. Maybe that could help you a little more. Looking at their example, they are doing a "rec.get('user')" that may be what you would need to do.
    I may try what your doing tonight and see if I can figure something out.
    
     var FacebookFeedSource = kind({
            name: 'FacebookFeedSource',
            kind: Source,
            fetch: function (rec, opts) {
                var resource;
                if (rec instanceof Collection) {
                    var user = rec.get('user') || 'me';
                    resource = '/' + user + '/feed';
                } else {
                    resource = '/' + rec.id;
                }
                FB.api(resource, function (response) {
                    if (response && !response.error) {
                        opts.success(response);
                    } else {
                        opts.fail(response);
                    }
                });
            },
            commit: function (rec, opts) {
                if (rec.isNew) {
                    FB.api('/me/feed', 'POST', rec, function (response) {
                        if (response && !response.error) {
                            opts.success(response);
                        } else {
                            opts.fail(response);
                        }
                    });
                } else {
                    opts.fail();  // FB only supports adding new posts, not editing
                }
            },
            destroy: function (rec, opts) {
                FB.api(rec.id, 'DELETE', function (response) {
                    if (response && !response.error) {
                        opts.success(response);
                    } else {
                        opts.fail(response);
                    }
                });
            }
        });
        new FacebookFeedSource({name: 'fbfeed'});
    
  • I have another problem going on... Even if I hard code a valid postBody into the MftLoginSource, the JSON is not getting into the UserLoginModel. I can log the inResponse.value from ajax.response(this, function (inSender, inResponse) in your code and it looks just like what I'd expect and I'm not logging any errors... Is it possible that this fetch override is preventing population of the Model?
  • Hey @Fred_D_Castillo !
    Your strategy WORKS! It was simply that I had to send opts.success(inResponse) rather than opts.success(inResponse.value)
    -Thank You!!!
  • Great, glad you got it working. Sorry the ".value" was specific to a webservice I was using and didn't remove that when I pasted it here.
  • The "rec.get('user')" idea is working too! (what the heck is "rec" short for???). The only thing still not working is the parse override. Even though the model is getting populated, the parse method is not firing. I stuck a console.log in the method and it never logs...
  • I have no idea what the "rec" stands for either...LOL

    In your model you have the options: { parse: true }, set and then you added
    parse: function (data) {
            // modify you data
            console.log('Parse Date:', data);
            return data;
        }
    and nothing ever happens?

  • Hey Fred, I realized that options: {parse:true} was missing and got it working. Here is the whole shebang (I shifted from 'mft' prefixes to 'lb'):
    var kind = require('enyo/kind'),
        EnyoSource = require('enyo/Source'),
        Ajax = require('enyo/Ajax'),
        Model = require('enyo/Model');
    
    var lbApiUrl = 'http://localhost:3000/api/';
    
    var LbLoginSource = kind({
        name: 'LbLoginSource',
        kind: EnyoSource,
        fetch: function (rec, opts) {
            // implement code to fetch records
            var ajax = new Ajax({
                url: lbApiUrl + 'mftUsers/login',
                method: 'POST',
                cacheBust: false,
                postBody: {username: rec.get('username'), password: rec.get('password')}
            });
            ajax.go();
    
            ajax.response(this, function (inSender, inResponse) {
                opts.success(inResponse); // call success callback to return data
            });
            ajax.error(this, function (inError, err) {// WIP: Needs Work...
                var errorParse = JSON.parse(inError.xhrResponse.body);
                var ajaxError = errorParse.msg;
                opts.fail(ajaxError);
            });
        }
    });
    new LbLoginSource({ name: 'LbLoginSource' });
    
    var UserLoginModel = kind({
        name: "UserLoginModel",
        kind: Model,
        source: 'LbLoginSource',
        options: { parse: true },
        parse: function (data) {
            // modify you data
            data.access_token = data.id;
            delete data.id;
            return data;
        }
    });
    var LbUserLoginModel = new UserLoginModel({name: "LbUserLoginModel"});
    
    module.exports = {
         LbLoginSource: LbLoginSource,
         LbUserLoginModel: LbUserLoginModel
    };
    It is all working except the error handling - but who needs that, right? ;-)
    -I can't thank you enough!
  • edited August 2016
    In case you run into something similar, cacheBust: false, was important here because my API rejected any query string appended to the login URL.
Sign In or Register to comment.