2

I wanted to be able to send the data from a successful jquery ajax call to other methods in my application because its quite large and it made coding sense to have one api method to work from, so I opted to try out promises. This is my first shot. I am getting some good results but clearly I am still a bit confused on context and timing.

When I run the following code, I am unable to wrap my return data from the ajax call as a jquery object without getting an error:

    var widgetSystem={       

       listenForClick: function(){
        $('div').on('click','a',function(){
            var $selectTarget = $(this),
                widgetid = $(this).data('widgetid');
                apiRequestData = widgetSystem.makeApiRequestForSingleWidget(widgetid);

            apiRequestData.then(function(result) {
                widgetSystem.showWidget(result);
            }).catch(function(e) {
                console.log('no way big error ' +e);
            });
        });
    },




    makeApiRequest: function(widgetid){

        return new Promise(function(resolve, reject) {
            $.ajax({
                method: "POST",
                url: "localhost",
                dataType: 'json',
                data: {
                    data: {
                       widgetId: widgetid
                    },
                    action: 'apiMethod'
                },
                error: function (jqXHR, textStatus, errorThrown) {
                    console.log(jqXHR);
                    console.log(textStatus);
                    console.log(errorThrown);
                    reject();
                },
                success: function (data) {
                    resolve(data);
                }
            });
        });
    },

    showWidget: function(data){
        $(data).appendTo('body');
        //this causes an exception in my apiRequestData.then function in listenForClick
    }

}

I am running un minified jquery and getting the following error in my console:

no way big error TypeError: context is undefined

absentx
  • 1,397
  • 4
  • 17
  • 31
  • what does it show when you write `console.log(data)` here `showWidget: function(data){...` – Hugo S. Mendes Jan 22 '16 at 22:15
  • It gives me a nice big object in the console, exactly as I would expect! Object { widget="
    \r\n
    – absentx Jan 22 '16 at 22:16
  • Not sure exactly where `context is undefined` is coming from, but I will say that this could actually be greatly simplified. `$.ajax` returns a promise itself, and both Promise results and Promise errors are pretty easy to convert into a new form (eg, you want to reduce a big JSON structure to an important identifier). `.then` returns a promise representing the return value of the function passed to `.then`, which is really handy. – Katana314 Jan 22 '16 at 22:17
  • did you try to invert that? `$('body').append(data);`? – Hugo S. Mendes Jan 22 '16 at 22:18
  • I know exactly why it isn't working. I need to turn data.widget into a jquery object, not data! My API returns an object containing the html I need. – absentx Jan 22 '16 at 22:19
  • you could just access the *widget* attribute of the object and append to the body :o – Hugo S. Mendes Jan 22 '16 at 22:22
  • @hugo, yes that is what I have done. – absentx Jan 22 '16 at 22:25
  • @charlietfl, It shows the same object I would expect it to, whether I console log it there or in the showWidget function. – absentx Jan 22 '16 at 22:25
  • 1
    did it work? like `$("body").append(data.widget)`? – Hugo S. Mendes Jan 22 '16 at 22:26
  • @hugo - yep sure did, thanks again. – absentx Jan 22 '16 at 22:33
  • okay. that's nice. :) – Hugo S. Mendes Jan 22 '16 at 22:34
  • There's no reason to use `new Promise` here. See [this answer](http://stackoverflow.com/a/31327725/1048572) for how to wrap it correctly. – Bergi Jan 22 '16 at 23:18
  • "*TypeError: context is undefined*" makes no sense given the code you've shown us. Please post the part of your code that makes use of a variable called `context`. – Bergi Jan 22 '16 at 23:20
  • @Bergi I can't! There is no variable in my script called context. I assume it is from the Jquery library? – absentx Jan 22 '16 at 23:38
  • @absentx: Then which line does the exception occur at? Try to log it as an object (`console.log('no way big error', e);`) and get us a stack trace, please. – Bergi Jan 22 '16 at 23:40
  • @Bergi TypeError: context is undefined if ( ( context.ownerDocument || context ) !== document ) { widget.js (line 98) widgetSystem.listenForClick/<()widget.js (line 99) e = Object { type="object"} – absentx Jan 23 '16 at 00:00
  • @absentx: That doesn't exactly look like jQuery, what is `widget.js`? (can you link it?) – Bergi Jan 23 '16 at 10:37

1 Answers1

1

I don't know exactly what your HTML looks like or how the API is set up, but assuming that the API is working correctly and the data sent via POST is correct, I was able to get it working using jsonplaceholder api with the following code (you can find it on JSbin).

var widgetSystem={       
  listenForClick: function(){
    $('div').on('click','a',function(){
      console.log('clicked');
      var $selectTarget = $(this);
      var widgetid = $(this).data('widgetid');


      widgetSystem.makeApiRequest(widgetid)
        .then(function(result) {
          widgetSystem.showWidget(result);
          return result;
        })
        .catch(function(e) {
          console.log('no way big error ' +e);
        });
    });
  },


  makeApiRequest: function(widgetid){
    return new Promise(function(resolve, reject) {
      var root = 'http://jsonplaceholder.typicode.com';
      $.ajax({
        method: "POST",
        url: root+'/posts/',
        dataType: 'json',
        data: {
          userId:1,
          title:"Havanagila",
          body:"Testing the greatness"
        },
        success: function(xData, status){
          resolve(xData);
          //reject('whoops');
        },
        error: function(xhr, status, error){
          reject(status);
        }
      });
    });
  },

  showWidget: function(data){
    $('#space').append(document.createTextNode(JSON.stringify(data)));
  }
}

widgetSystem.listenForClick()

I don't think there is an issue which how you are calling resolve(data) within the ajax success callback. There may be an issue with the data being sent to your API such that the error callback is called, which in turn calls reject and causes the callback passed to .catch to be called instead of the intended callback passed to .then.

James Choi
  • 1,078
  • 14
  • 14