0

I got it to work with everyone's help. I change the 'context:' to 'this' from 'this.parentNode'. I still get confused with the 'this' context. With limited testing it appears to have fixed my problem with running multiple instances. Thanks for your help. The new code is shown below.

I am new to jQuery and Javascript. I am creating a general object to navigate database tables (NavDb). It works perfectly if I create 1 instance. When I run multiple instances it fails. I traced the problem to how I use 'this'. One routine that initializes/handles ajax requests fails. A form can have any number of selectors (autocomplete or drop-downs). The routine recursively performs ajax requests until all the selectors have been initialized. The 'this' variable refers to the ajax object when entering the 'success:' function. I need a reference to the parent object so I created a $this on line 2. The problem is it creates a closure and messes up the second instance (I believe that is what is happening). How do I get a reference to the parent object inside the success function? Can I bind the ajax request to the parent object? I need something like this:

var $this = this.parent;

Hopefully I explained this clearly.

New code

NavDb.prototype.getSelData = function () {
    if (this.curSelector >= this.selectors.length) {
        return;
    }
    else {
        var sql = this.selectors[this.curSelector].sql;
        $.ajax({
            url: 'php/select.php',
            type: 'POST',
            context: this,    // Only needed 'this' not this.parentNode.
            dataType: 'json',
            data: {
                'sql': sql
            }
        }).done(function (data) {
            if (data.success) {
                if (data.v.length > 0) {
                    this.selectors[this.curSelector].data = data;
                    if (this.selectors[this.curSelector].type == "autoComp") {
                        this.initAC();
                    };
                    if (this.selectors[this.curSelector].type == "dropDown") {
                        this.initDD();
                    };
                }
            }
            this.curSelector++;
            this.getSelData();
        }).fail(function (XHR, textStatus, errorThrown) {
            $("#status").html(getErrorText(XHR.responseText));
        });
    };
};

Old code

   NavDb.prototype.ajaxSelData = function () {
        var $this = this;
        if (this.curSelector >= this.selectors.length) {
            $this = null;
            return;
        }
        else {
            var sql = $this.selectors[$this.curSelector].sql;
            $.ajax({
                url: 'php/select.php',
                type: 'POST',
                dataType: 'json',
                data: {
                    'sql': sql
                },
                success: function (data) {
                    if (data.success) {
                        if (data.v.length > 0) {
                            $this.selectors[$this.curSelector].data = data;
                            if ($this.selectors[$this.curSelector].type == "autoComp") {
                                $this.initAC();
                            };
                            if ($this.selectors[$this.curSelector].type == "dropDown") {
                                $this.initDD();
                            };
                        }
                    } else {
                        alert(data.error);
                    }
                    $this.curSelector++;
                    $this.ajaxSelData();
                }
            });
        };
    };
user2970483
  • 323
  • 5
  • 14
  • You can try using `context` in your ajax call. `context: this,` then use `this` in your callbacks as the object. – Musa Nov 08 '13 at 21:29

2 Answers2

0

The closure your code creates is unique to each instance (it creates a separate closure for each instance) so your theory that the closure was messing up the second instance is not correct.

So, creating your separate variable as you were doing with:

var $this = this;

is a perfectly fine thing to do and will not cause problems.


But, if you want the parent node, then perhaps you should be doing this:

var parent = this.parent;    

and then refer to the parent variable inside your ajax function.


You could also just pass the context argument to your ajax call and that will set the this parameter as desired in the success handler callback.

       $.ajax({
            url: 'php/select.php',
            type: 'POST',
            dataType: 'json',
            context: this.parent,        // add this line
            data: {
                'sql': sql
            },
           success: function (data) {
                // now the this pointer is set as desired in your callback here
                if (data.success) {
jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • I tried these techniques and they don't seem to work on prototype objects. When I console.log this.parentNode it returns undefined. Any other ideas. – user2970483 Nov 09 '13 at 02:08
  • @user2970483 - I thought you were using DOM objects. What kind of objects do you have? And what properties does it have? If it has a `.parent` property, then you can use that instead of the `.parentNode` that DOM objects use. I've shown you the general technique. You need to know enough about the types of objects you have to use the right properties. Your issue should have nothing to do with prototypes unless your issue is that you aren't creating a proper object (code you haven't disclosed so we couldn't have any idea). – jfriend00 Nov 09 '13 at 05:23
  • @user2970483 - do you understand that you don't usually run code on prototype objects. You define properties on a prototype so that those properties will be present on an actual object of that type when you create one (which is usually done with the `new` operator). And, then once you've properly created an object with that prototype, you can then use the properties/methods on that object and it will have all the right properties. – jfriend00 Nov 09 '13 at 05:26
  • @user2970483 - how are you creating each instance of your object? – jfriend00 Nov 09 '13 at 05:48
  • First, I want to thank you for taking time to help me. I included a cut down version of what I am doing. I am creating an object with the new operator. – user2970483 Nov 09 '13 at 15:25
  • First, I want to thank everyone for taking time to help me. I am creating an object with the new operator. var navWkOrder = new NavDb(wkOrders); navWkOrder.init(); wkOrders is a Javascript data structure with info about selector. This function only gets the data from db and saves it in a var. It does not interact with DOM. initAC/initDD interact with DOM using the data. I cut down a sample of code for you but I am limited to a few characters here. Not sure how to properly post it. @r-oosterholt – user2970483 Nov 09 '13 at 15:44
  • @user2970483 - you use the edit button to add the code to your question and then you post a comment that tells us what you added. Multiple lines of code don't work in comments, only in your question or an answer. FYI, when you say you're trying to get the `parent`, what parent is this? Is that a property of your object? – jfriend00 Nov 09 '13 at 18:04
  • @user2970483 - at this point I can't really tell what your question is. Is the problem that `.parent` is `undefined`? Does your object have that property? – jfriend00 Nov 09 '13 at 18:22
0

For correct context scope see this answer.

You can ensure correct context in several ways:

  • use context

    $.ajax({
         url: 'php/select.php',
         type: 'POST',
         context: this.parentNode,
         dataType: 'json',
         data: {
             sql: sql
         },
         success: function (data) {
             // 'this' is parentNode
         }
    })
    
  • use closure

    var parentNode = this.parentNode;
    success: function (data) {
        //you can now use 'parentNode'
    }
    
  • use $.proxy

    $.proxy(function(data){
        // 'this' is parentNode
    }, this.parentNode);
    
Community
  • 1
  • 1
R. Oosterholt
  • 7,720
  • 2
  • 53
  • 77
  • Neither of these techniques appear to work with prototype objects. I am getting the same error. TypeError: this.curSelector is undefined this.selectors[this.curSelector].data = data; – user2970483 Nov 09 '13 at 01:28
  • After checking the property parentNode does not appear to exist in prototype objects. If I console.log it it says undefined. – user2970483 Nov 09 '13 at 01:57
  • well, than I need more info. What is `NavDb` and how do you construct it? `this` in prototype should work as expected. – R. Oosterholt Nov 09 '13 at 08:26