0

Hi I am using below jQuery.ajax call, in my onBeforeRendering() Method:

onBeforeRendering: function() {
jQuery.ajax({
            url: "/prototype/OnlineQuestionnaire/getQuestionsAndResponseChoices.xsjs?questionnaireResponseId=" + escape(
                questionnaireResponseId) + "&password=" + escape(
                password),
            //  url: "/prototype/OnlineQuestionnaire/submitAndCreateQuestionnaire.xsjs",
            method: "GET",
            dataType: "json",
            complete: this.onSuccess,
            error: this.onErrorCall
        });
console.log(output);   //Gives undefined
}
onSuccess: function(jqXHR, textStatus) {
        output = jqXHR.responseText;
        output = JSON.parse(output);
        console.log(output)  //Gives me my JSON object from my response.
        return;
    },

Why does my console.log(output) gives me undefined in my onBeforeRendering function ? I want to get the output result in my onBeforeRendering so that I can perform some validation here before rendering. At the moment I got a work around I perform my validations in the onSuccess function after I receive my output. But I want to do it after my ajax call in onBeforeRendering(). But I tried console.log(output) its undefined. How can access the output from my complete property of ajax call?

loki
  • 590
  • 15
  • 28
  • 1
    `output = JSON.parse(output);` is unnecessary. You've already specified `dataType: "json"` so the result should be retrievable as `output = jqXHR.responseJSON;`. But anyway, the call that's returning undefined does so because that code runs _before_ the ajax call returns a result - because ajax runs asynchronously. Therefore at that moment `output` does not exist yet, or at least does not have any content. It's probably out of scope as well, depending how you've defined your variables. – ADyson Jun 12 '17 at 10:36
  • @ADyson thank you for your reply. I understand that code runs before ajax call returns. But I need to run validate the output as soon as the ajax call is complete. But before my html is rendered. How do I do it? I thought about using jQuery.ajaxComplete(). – loki Jun 12 '17 at 11:44
  • then you have to do your validation within your "success" function which is triggered by the return from the ajax call. – ADyson Jun 12 '17 at 12:16
  • @ADyson yes that is the workaround I am using by my validation has a lot of code so i thought maybe get the data in output variable and then validate this output data in different function. But as I get output undefined due to asynchronous execution as you clarified I am not able to do this approach. – loki Jun 12 '17 at 12:27
  • 1
    what you're doing isn't a workaround, it's the only way it can be done. You haven't got the data until the ajax completes, therefore you can't do anything with the data until the ajax completes. There's no alternative. To use an analogy, you can't start building your house until the bricks are delivered. – ADyson Jun 12 '17 at 12:29
  • @ADyson :D hehe nice quote. Thank you for your replies and help. Got my concept clear. – loki Jun 12 '17 at 12:56

1 Answers1

5

A couple of remarks

  • Don't use escape(). This function has been deprecated ages ago. It's broken und there is not a single good reason to use it anywhere, ever. Forget that it exists.
  • If you must escape URL parameters manually, use encodeURIComponent().
  • However, with jQuery Ajax you do not have to escape URL parameters manually. Pass an object with keys and values and jQuery will do the right thing on its own.
  • jQuery also parses the response JSON for you automatically when the server sets Content-Type: application/json.
  • When the server sends the proper Content-Type header you don't need to specify any "json" options in your request and can use $.get() instead of the more verbose $.ajax().
  • The response data is the first argument for your success callback, not jqXHR.
  • I recommend getting into the habit of using jQuery's promised-based interface for Ajax requests.

With this we can reduce your code into a much more readable form:

onBeforeRendering: function () {   
    jQuery.get("/prototype/OnlineQuestionnaire/getQuestionsAndResponseChoices.xsjs", {
        questionnaireResponseId: questionnaireResponseId
        password: password
    }).done(function (data) {
        console.log(data);
    });
}
Tomalak
  • 306,836
  • 62
  • 485
  • 598
  • Thank you very much for the remarks, I would make the changes accordingly. Learnt alot through your comment many thanks. – loki Jun 12 '17 at 11:42
  • Omg I used this and it got so much easier no need to escape URL parameters passing them as objects makes it more readable. Many thanks. Wish I could give you 10 votes up :D – loki Jun 14 '17 at 07:09
  • That's good to hear, thank you for the feedback! :) Keep your eyes open, jQuery is full of little things like this. – Tomalak Jun 14 '17 at 07:41
  • 1
    @loki There you are missing `var` keywords. You *must* declare all variables with `var`. Otherwise they will be top-level global variables and you don't want that, that's almost always a bug waiting to happen. In fact, there is no need for variables at all. Just use the parameter object directly. `{ questionnaireResponseId: jQuery.sap.storage.get("QuestionnaireResponseId"), password: jQuery.sap.storage.get("Password") }`. – Tomalak Jun 14 '17 at 07:51
  • Oh yes I can do this tweak also. Right I don't need them to be global as I am using them only for the mentioned purpose. I will consider this. – loki Jun 14 '17 at 07:52
  • I tried the following with your reply and but I keep getting the error: this.checkData is not a function. `onBeforeRendering: function() { jQuery.get("/prototype/OnlineQuestionnaire/getQuestionsAndRe‌​sponseChoices.xsjs", { questionnaireResponseId: jQuery.sap.storage.get("QuestionnaireResponseId"), password: jQuery.sap.storage.get("Password") }).done(function(data){ this.checkData(data); });}, checkData: function(xsjsInput){ console.log('Hi', xsjsInput); }` Why can't I call another function from the .done(function(data){check(data)}) and pass the data to this next function? – loki Jun 14 '17 at 08:00
  • 1
    Because of the way how `this` works in JavaScript. That's not a topic we can discuss sensibly here in the comments. As of now, there are roughly 14,000,000 questions on Stack Overflow. I estimate 100,000 of them are a variant of *"How does the `this` keyword work in JS?"*. The issue you see is one of the most common issues for JS beginners, you will find a host of threads that discuss exactly this problem. – Tomalak Jun 14 '17 at 08:58
  • 1
    Thank you very much for all the time and comments. I would try searching regarding this. :) Hope to move from beginner to atleast intermediate level in javascript in coming days and start helping people like you are doing. – loki Jun 14 '17 at 09:06
  • 1
    One of the higher-voted threads dedicated to the `this` topic. https://stackoverflow.com/questions/3127429/how-does-the-this-keyword-work (in any case a very good one, go read it!) – Tomalak Jun 14 '17 at 09:07
  • I would check it out. Also can you provide me with your linkedin profile link, would love to work as an intern in future if I get an opportunity as you are a good teacher. – loki Jun 14 '17 at 09:28
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/146630/discussion-between-loki-and-tomalak). – loki Jun 14 '17 at 09:33
  • 1
    That's very flattering of you. I'm sorry to say, I don't even have a LinkedIn Profile and my company does not provide internships :( – Tomalak Jun 14 '17 at 09:50
  • 1
    I'm a regular in javascript/node, regex, xml, python and a few other topics here on SO, we might cross paths again. – Tomalak Jun 14 '17 at 10:03
  • 1
    Thank you again I somewhat understood the why I was not able to access the method checkData() using this because this is representing the current object. And the checkData() is defined in my controller. So i needed to get the id of my controller to access this method which I failed to get but I got a workaround. I used a new var that = this ; now that has my window object. and I accessed the checkData() in following way: `that.OnlineQuestionnaire.controller.Questionnaire.prototype.checkData();` – loki Jun 16 '17 at 08:02
  • 1
    That's one of the ways to get a fixed object reference into a JS function. Here is a way to think about it: JS does not have classes. This is the most important point. Consequence: It does not have class methods, either. What it has is *functions* that are assigned to *object properties*. The functions exist on their on, just like the value 4 exists on its own when you assign it to an object property. `this` will point to whatever object a function is *called on*. Not to the object it "belongs to", because functions do not "belong" to objects in JS, they are just stored there. – Tomalak Jun 16 '17 at 08:12
  • 1
    `foo.bar()` - call the function `bar` on the object `foo`. `baz.bar()` - call the function `bar` on the object `baz`. `foo.bar.call(baz)` - call the function `foo.bar` on the object `baz`. `test = foo.bar; test()` - call the function `foo.bar` on no object; in which case `this` inside this function will resolve to the global object. The last case is what can happens in callback scenarios. Storing `that = this` will retain the desired object reference. – Tomalak Jun 16 '17 at 08:17
  • I understood a little bit of it. So in my case the checkData property of an Object has the function assigned to it. But this function exist on their own. But I need to get this Object to access this function. I am unable to get this object or figure out what it is because of the framework (SAPUI5). Trying process your comments a bit difficult to me because I am not so good in Javascript. – loki Jun 16 '17 at 08:24
  • It will take some time to wrap your head around it. It's not really difficult, but first you need to stop thinking in Java terms about JS. Let's wrap this here. We have created a huge wall of text that nobody is ever going to read, it's effectively a waste. Long discussions in the comments are discouraged for a reason on Stack Overflow. – Tomalak Jun 16 '17 at 09:11
  • :D yes haha but this discussion was really beneficial for me. You earned a new follower on twitter :) – loki Jun 16 '17 at 09:12
  • I don't tweet much technichal stuff though, if at all. – Tomalak Jun 16 '17 at 09:23