Search code examples
javascriptjquerywidgettypeerroruncaught-exception

Uncaught TypeError: Can not set propery 'FUNCTION_NAME' of undefined for widget implementation


I am trying to develop a jQuery widget which can be embedded on any site. Following is the script code:

(function($) {
    var jQuery;
    if (window.jQuery === undefined || window.jQuery.fn.jquery !== '1.6.2')
    {
        var script_tag = document.createElement('script');
        script_tag.setAttribute("type","text/javascript");
        script_tag.setAttribute("src","http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js");
        script_tag.onload = scriptLoadHandler;
        script_tag.onreadystatechange = function () 
        { 
            if (this.readyState == 'complete' || this.readyState == 'loaded')
                scriptLoadHandler();
        };
        (document.getElementsByTagName("head")[0] || document.documentElement).appendChild(script_tag);
    }
    else 
    {
        jQuery = window.jQuery;
        main();
    }
    function scriptLoadHandler() 
    {
        jQuery = window.jQuery.noConflict(true);
        main();
    }
    function main() {
        jQuery(document).ready(function($) {
            var css = $("<link>", { rel: "stylesheet", type: "text/css", href: "http://mysite.com/my_css_path.css" });
            css.appendTo('head');
        });
        $.fn.fetchfeed = function(options) {
            var defaults = {
                //default params;
            };
            var opts = $.extend(defaults, options);

            var myURL = "http://mysite.com/"+opts.user+".json?";
            var params = "&callback=?"
            var jsonp_url = myURL + encodeURIComponent(params);

            $.getJSON(jsonp_url, function(data) {
                //build widget html
            })
            .error(function() {
                //show error
            });
        }
    }
})(jQuery);

And following is the code which need to be placed on User's site:

 <script id='mywidgetscript' src='http://my_site.com/javascripts/widget.js'></script>
 <div id='my-widget-container'></div>
 <script>$('#my-widget-container').fetchfeed({/*parameters*/});</script>

When I put this code on other site and try to load the widget it gives me the Uncaught TypeError: Can not set property 'fetchfeed' of undefined error and fails to load the widget. What could be wrong?

Surprisingly this widget code is working on my site on localhost!!!


Solution

  • Okay, after countless attempts I solved it and got to learn many things. Still I'm unclear about many things. Do correct me by editing this answer or please comment if you find anything wrong.

    First $.fn was null (or value being passed to it was null/undefined). Reason, the script was getting executed after <script>$('#my-widget-container').fetchfeed({/*parameters*/});</script> being called. So .fetchfeed({...}) was undefined.

    Then I moved the code in window.onload it gave me error can not call method fetchfeed on null. It must be because it was not getting the element (i.e. $('#my-widget-container')) also script was not able to recognize $.

    Again after few tweaks making $.fn.fetchfeed to function fetchfeed() {...} gave me error undefined fetchfeed. This was because function fetchfeed was inside another function.

    Also encoding &callback=? parameter gives Access-Control-Allow-Origin error. This should be passed in url as is.

    After some research I modified the code as below and now working correctly.

    function fetchfeed(options) {
        var o = options;
        var jQuery;
        if (window.jQuery === undefined || window.jQuery.fn.jquery !== '1.6.2')
        {
            var script_tag = document.createElement('script');
            script_tag.setAttribute("type","text/javascript");
            script_tag.setAttribute("src","http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js");
            script_tag.onload = scriptLoadHandler;
            script_tag.onreadystatechange = function () 
            { 
                if (this.readyState == 'complete' || this.readyState == 'loaded')
                    scriptLoadHandler();
            };
            (document.getElementsByTagName("head")[0] || document.documentElement).appendChild(script_tag);
        }
        else 
        {
            jQuery = window.jQuery;
            ff(jQuery, o);
        }
        function scriptLoadHandler() 
        {
            jQuery = window.jQuery.noConflict(true);
            ff(jQuery, o);
        }
        function ff($, options) {
            var defaults = {
                ...
            };
            var opts = $.extend(defaults, options);
    
            var jsonp_url = "http://mysite.com/?callback=?";            
            $.getJSON(jsonp_url, function(data) {
                //success
            })
            .error(function() {
                //fail
            });
        }
    }
    

    Code on user's site/blog will be

    <div id='my-widget-container'></div>
    <script id='my_widget_script' src='https://PATH_OF_SCRIPT/FILE_NAME.js'></script>
    <script type='text/javascript'>
        fetchfeed({/*params*/});
    </script>
    

    The function will be executed when page load completes.