Search code examples
autocompletefirefox-addoncustom-componentxpcom

Using a javascript XPCOM component to create a custom autocomplete box in a FireFox add-on


I've spent a few days reading over all manner of tutorials, MDN entries, and S.O. posts, and I've come to suspect that I'm missing something obvious, but I'm too inexperienced with XPCOM to spot it. I'm about 80% sure there error is somewhere in my custom component (components/fooLogin.js).

Problem: When the add-on initializes (when I call loadData() from chrome/content/foologin.js), I get an error saying:

TypeError: Components.classes['@foo.com/foologinautocomplete;1'] is undefined

Am I maybe trying to create the component before the class has been registered? Is there something else I need to do to register it? Any tips would be appreciated.

Relevant Code: (happy to supply any additional code, if need be)

components/fooLogin.js:

Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
function fooLoginAutoComplete(){
        this.wrappedJSObject = this;
}
fooLoginAutoComplete.prototype = {
        classID: Components.ID("loginac@foo.com"),
        contractID: "@foo.com/foologinautocomplete;1",
        classDescription: "Auto complete for foo",
        QueryInterface: XPCOMUtils.generateQI([]),
        complete: function(str){  // Autocomplete functionality will in this function
                return null;
        }
};
var NSGetFactory = XPCOMUtils.generateNSGetFactory([fooLoginAutoComplete]);

chrome/content/foologin.js:

let fooLogin = {
    dataLoaded : false,
    searchFilter = null,
    ...
    loadData : function(){
        ...
        try{
            alert(1);  // This alert fires
            this.searchFilter = Components.classes['@foo.com/foologinautocomplete;1']
                .getService().wrappedJSObject;
            alert(2);  // I get the error before this alert
        }catch(e){alert(e);}
        this.dataLoaded = true;
    }
}
window.addEventListener("load", function(){
    if(!fooLogin.dataLoaded) fooLogin.loadData();
}

chrome.manifest:

content foologin         chrome/content/
content foologin         chrome/content/ contentaccessible=yes
skin    foologin classic chrome/skin/
locale  foologin en-US   chrome/locale/en-US/

component loginac@foo.com                 components/fooLogin.js
contract  @foo.com/foologinautocomplete;1 loginac@foo.com

overlay chrome://browser/content/browser.xul chrome://foologin/content/foologin.xul

Solution

  • In your chrome.manifest, you have this:

    component loginac@foo.com components/fooLogin.js contract @foo.com/foologinautocomplete;1 loginac@foo.com

    and in fooLogin.js you have:

    classID: Components.ID("loginac@foo.com"),

    loginac@foo.com is not a valid class ID for a component.

    They have to be of the form:

    {00000000-0000-0000-0000-000000000000}

    Only add-ons can have a foo@bar.com format.