views:

309

answers:

2

I'm using a javascript autocomplete () in a greasemonkey script. On itself it works correctly but I wan't to add JSONP because I want the data from another domain. The code (snippet):

function autosuggest(url)
{
    this.suggest_url = url;
    this.keywords = [];

    return this.construct();
};

autosuggest.prototype = 
{
    construct: function()
    {   
        return this;
    },

    preSuggest: function()
    {
        this.CreateJSONPRequest(this.suggest_url + "foo");
    },

    CreateJSONPRequest: function(url)
    {
        var headID = document.getElementsByTagName("head")[0];         
        var newScript = document.createElement('script');
        newScript.type = 'text/javascript';
        newScript.src = url +'&callback=autosuggest.prototype.JSONCallback';
        //newScript.async = true;
        newScript.onload = newScript.onreadystatechange = function() {          
            if (newScript.readyState === "loaded" || newScript.readyState === "complete")
            {
                //remove it again
                newScript.onload = newScript.onreadystatechange = null;
                if (newScript && newScript.parentNode) {
                    newScript.parentNode.removeChild(newScript);
                }
            }
        }

        headID.appendChild(newScript);  
    },  

    JSONCallback: function(data)
    {
        if(data)
        {
            this.keywords = data;
            this.suggest();
        }
    },

    suggest: function()
    {
        //use this.keywords
    }
};

//Add suggestion box to textboxes
window.opera.addEventListener('AfterEvent.load', function (e)
{
    var textboxes = document.getElementsByTagName('input');
    for (var i = 0; i < textboxes.length; i++) 
    {
        var tb = textboxes[i];
        if  (tb.type == 'text')
        {       
            if (tb.autocomplete == undefined || 
                tb.autocomplete == '' ||
                tb.autocomplete == 'on')
            {
                //we handle autosuggestion
                tb.setAttribute('autocomplete','off');      
                var obj1 = new autosuggest("http://test.php?q=");               
            }
        }
    }
}, false);

I removed not relevant code. Now when 'preSuggest' is called, it add a script to the header and circumvent the crossdomain problem. Now when the data is received back 'JSONcallback' is called. I can use the data, but when 'Suggest' is I can't use the this.keywords array or this.suggest_url. I think this is because 'JSONcallback' and 'Suggest' are called in a different context.

How can I get this working?

A: 

When you call a function on the prototype directly, there is no context for this, therefore when the JSONP call is returned, it is calling autosuggest.prototype.JSONCallback but that function can't call this.suggest().

Instead, I'd suggest creating a wrapper function:

function JSONCallback(data) {
    var as = new autosuggest();
    as.keywords = data;
    as.suggest();
}

or, create a single global autosuggest object and use that as the callback:

var globalAS = new autosuggest("http://example/?q=");

// inside the CreateJSONPRequest function, change this line:
newScript.src = url +'&callback=globalAS.JSONCallback';
nickf
Your first example creates a new autosuggest object but I want to keep my 'old' object for other data such as suggest_url. I'm creating multiple autosuggest objects for each input element on the page. Is there any other solution?
PoweRoy
short of creating global variables for each object you require and then letting them know a name so they can reference themselves (eg: `var as1 = new autosuggest(); as1.name = 'as1';` then I can't really think of anything right now. Perhaps could you re-architect so that you don't need persistent AS objects?
nickf
A: 

thank you, it helped me a lot!

paslanmaz