Search code examples
javascriptjqueryhttpxmlhttprequest

Uncaught TypeError: Cannot set property 'response' of undefined


So, I've got this old code I wrote in 2015, it worked fine then, but now it's not -- any ideas to whats' wrong? It appears to be in the request function when using ajax, I get an error:

VM3641:326 Uncaught TypeError: Cannot set property 'response' of undefined
at Object.success (<anonymous>:326:48)
at i (jquery.min.js:2)
at Object.fireWith [as resolveWith] (jquery.min.js:2)
at y (jquery.min.js:4)
at XMLHttpRequest.c (jquery.min.js:4) 

Specific segment of code where the error persists:

        if ($canUsejQuery) {
            // Make Request with jQuery
            console.log('jQuery');
            jQuery.ajax({
                type: this.RequestData.type,
                data: {},
                url: this.RequestData.link,
                success: function (response) {
                    console.log(response);
                    this.ResponseData.response = response;
                },
                error: function (err, errCode, errMessage) {
                    this.ResponseData.response = '';
                    this.ResponseData.hasErrors = true;
                    console.log('error');
                }
            });
        }

It's a weird one, it gives the response, I try to assign it as ResponseData, but it fails to do that, and says it's undefined, but if I alert the response, it works fine and it's not undefined?

Entire Code:

/**
 * @version     1.0.1
 * @copyright   Copyright (C) 2015. All rights reserved.
 * @author      Curtis <[removed]@gmail.com>
 * @license     SEE END OF FILE FOR LICENSE
 * @github      [removed]
 */

/**
 * @section Configuration
 */

/**
 * @name $httpconfiguration
 * @desc These are all the changable settings for the $HttpLib library by Curtis <[removed]@gmail.com>
 * @type {Object}
 * @public
 */
var $httpconfiguration = {
    /**
     * @name upgradeHTTP
     * @desc Should we upgrade non-secure requests (HTTP:) to secure (HTTPS:)?
     * @default true
     * @note Most browsers won't allow non-secure requests to load when using HTTPs
     */
    upgradeHTTP: true,
    /**
     * @name downgradeHTTPs
     * @desc Should we downgrade secure requests to non-secure requests? (HTTPS: to HTTP:)
     * @default false
     * @note It is not advised you change this setting, you should ALWAYS use HTTPS (secure) requests, however this is left in here for testing.
     */
    downgradeHTTPs: false
};

/**
 * @endsection
 */

// DO NOT MODIFY BELOW THIS LINE

/**
 * @name $HttpLib
 * @desc Define the $HttpLib variable
 * @type {mixcase}
 */
var $HttpLib;

/**
 * @section Code for $HttpLib
 */

/**
 * @name $HttpLib
 * @desc The core of the $Http library, includes all functionality and logical operations for making reasonable, fast, efficient web requests
 * @type {Object} $HttpLib
 * @protected
 */
$HttpLib = {
    /**
     * @name triggerError
     * @desc Trigger an error, and determine the logging level based upon the code (severity) supplied.
     * @type {function}
     * @param {Object} $ErrorInformation
     */
    triggerError: function ($ErrorInformation) {
        var code = $ErrorInformation.code;
        /**
         * @schema code
         * @code 1 {Fatal}
         * @code 2 {Warning}
         * @code 3 {Debug}
         */
        switch (code) {
            case 1:
                alert('[' + $ErrorInformation.errorFunc + ']' + $ErrorInformation.message);
                break;
            case 2:
                console.log('[' + $ErrorInformation.errorFunc + ']' + $ErrorInformation.message);
                break;
            case 3:
                console.log('[Debug message from ' + $ErrorInformation.errorFunc + ']' + $ErrorInformation.message);
                break;
            default:
                console.log('[' + $ErrorInformation.errorFunc + ']' + $ErrorInformation.message);
                break;
        }
    },
    /**
     * @name determineBrowser
     * @desc Get the browser Name, Version, and return {object} $Browser to the requesting function
     * @returns {{name: string, version: string}} $Browser
     */
    determineBrowser: function () {
        var nVer = navigator.appVersion;
        var nAgt = navigator.userAgent;
        var browserName = navigator.appName;
        var fullVersion = '' + parseFloat(navigator.appVersion);
        var majorVersion = parseInt(navigator.appVersion, 10);
        var nameOffset, verOffset, ix;

        // In Opera 15+, the true version is after "OPR/"
        if ((verOffset = nAgt.indexOf("OPR/")) != -1) {
            browserName = "Opera";
            fullVersion = nAgt.substring(verOffset + 4);
        }
        // In older Opera, the true version is after "Opera" or after "Version"
        else if ((verOffset = nAgt.indexOf("Opera")) != -1) {
            browserName = "Opera";
            fullVersion = nAgt.substring(verOffset + 6);
            if ((verOffset = nAgt.indexOf("Version")) != -1)
                fullVersion = nAgt.substring(verOffset + 8);
        }
        // In MSIE, the true version is after "MSIE" in userAgent
        else if ((verOffset = nAgt.indexOf("MSIE")) != -1) {
            browserName = "Microsoft Internet Explorer";
            fullVersion = nAgt.substring(verOffset + 5);
        }
        // In Chrome, the true version is after "Chrome"
        else if ((verOffset = nAgt.indexOf("Chrome")) != -1) {
            browserName = "Chrome";
            fullVersion = nAgt.substring(verOffset + 7);
        }
        // In Safari, the true version is after "Safari" or after "Version"
        else if ((verOffset = nAgt.indexOf("Safari")) != -1) {
            browserName = "Safari";
            fullVersion = nAgt.substring(verOffset + 7);
            if ((verOffset = nAgt.indexOf("Version")) != -1)
                fullVersion = nAgt.substring(verOffset + 8);
        }
        // In Firefox, the true version is after "Firefox"
        else if ((verOffset = nAgt.indexOf("Firefox")) != -1) {
            browserName = "Firefox";
            fullVersion = nAgt.substring(verOffset + 8);
        }
        // In most other browsers, "name/version" is at the end of userAgent
        else if ((nameOffset = nAgt.lastIndexOf(' ') + 1) <
            (verOffset = nAgt.lastIndexOf('/'))) {
            browserName = nAgt.substring(nameOffset, verOffset);
            fullVersion = nAgt.substring(verOffset + 1);
            if (browserName.toLowerCase() == browserName.toUpperCase()) {
                browserName = navigator.appName;
            }
        }
        // trim the fullVersion string at semicolon/space if present
        if ((ix = fullVersion.indexOf(";")) != -1)
            fullVersion = fullVersion.substring(0, ix);
        if ((ix = fullVersion.indexOf(" ")) != -1)
            fullVersion = fullVersion.substring(0, ix);

        majorVersion = parseInt('' + fullVersion, 10);
        if (isNaN(majorVersion)) {
            fullVersion = '' + parseFloat(navigator.appVersion);
            majorVersion = parseInt(navigator.appVersion, 10);
        }
        var $Browser = {
            name: browserName,
            version: fullVersion
        };
        return $Browser;
    },
    /**
     * @name determineHTTPMethod
     * @desc Determine the HTTP method used (ie: http or https), and return {string}
     * @param {string} $URLString
     * @returns {string}
     */
    determineHTTPMethod: function ($URLString) {
        /**
         * @task Check if the {string} $URLString is not a string, and if so, throw an error
         * @success continue
         * @error triggerError(); return;
         */
        if (typeof($URLString) != "string") {
            this.triggerError({
                errorFunc: 'determineHTTPMethod',
                message: 'Failed to determine the HTTP method in the {string} $URLString, as the type of $URLString does not appear to be a valid string. Assuming HTTPS',
                code: '2'
            });
            return 'https';
        }
        else {
            if ($URLString.indexOf('http://') > -1) {
                return 'http';
            }
            else if ($URLString.indexOf('https://') > -1) {
                return 'https';
            }
        }
    },
    /**
     * @name hasExternalLibraries
     * @desc Does the web page have external libraries we can use/rely on? If so, log them so we know.
     * @returns {Boolean} $ExternalLibraries
     */
    hasExternalLibraries: function () {
        var $ExternalLibraries = false;
        /**
         * @task Check for known external libraries we can use
         */
        if (typeof(jQuery) != "undefined" || typeof($) != "undefined") {
            return true;
        }
        /**
         * @task Return the result of {Array} $ExternalLibraries
         */
        return $ExternalLibraries;
    },
    /**
     * @name upgradeHttpMethod
     * @desc Should we upgrade HTTP to HTTPS?
     * @param {string} $URLString
     * @returns {String} $URLString
     */
    upgradeHttpMethod: function ($URLString) {
        if ($httpconfiguration.upgradeHTTP) {
            return $URLString.replace('http:', 'https:');
        }
        return $URLString;
    },
    /**
     * @name downgradeHttpsMethod
     * @desc Should we downgrade HTTPs to HTTP?
     * @param {string} $URLString
     * @returns {string} $URLString
     */
    downgradeHttpsMethod: function ($URLString) {
        if ($httpconfiguration.downgradeHTTPs) {
            console.error('It is not recommended to downgrade HTTPs to HTTP, however the site administrator has enforced the HTTPs downgrade method.');
            return $URLString.replace('https:', 'http:');
        }
        return $URLString;
    },
    /**
     * @name RequestData & ResponseData
     * @desc Request, Response data
     */
    RequestData: {},
    ResponseData: {},
    /**
     * @name request
     * @desc The code to make the proper request, determine what browser, etc. and choose the fastest, best method to obtain the content
     * @param {object} $RequestData
     * @returns {object} $ResponseData
     */
    request: function ($RequestData) {
        /**
         * @name RequestData
         * @desc The request data to set in the {object} this.RequestData
         * @type {string} $ResponseData
         */
        this.RequestData = $RequestData;
        this.ResponseData = this.RequestData;
        /**
         * @name $Browser
         * @desc Obtain the Browser details from {function} determineBrowser
         * @type {Object} $Browser
         */
        var $Browser = this.determineBrowser();
        /**
         * @name $ExternalLibraries
         * @desc Obtain the details of any/all external libraries used that we look for (ie: DownloadJS, jQuery, etc)
         * @type {Array} $ExternalLibraries
         */
        var $ExternalLibraries = this.hasExternalLibraries();

        /**
         * @task Check if {Boolean} $ExternalLibraries is empty or invalid type of {mixcase} instead of {array}
         */
        if ($ExternalLibraries === '' || typeof($ExternalLibraries) != "boolean") {
            /**
             * @task Set {Boolean} $ExternalLibraries to an error since it's not or it's invalid
             * @type {Boolean}
             */
            $ExternalLibraries = false;
        }

        /**
         * @task Determine if we have jQuery
         */
        /**
         * @name $canUsejQuery
         * @desc {boolean} to determine if we can use jQuery or not
         * @type {boolean}
         */
        var $canUsejQuery = true;

        if (!$ExternalLibraries) {
            $canUsejQuery = false;
        }

        console.log($canUsejQuery);
        console.log($ExternalLibraries);

        /**
         * @task Check RequestData to see if we should upgrade, and check our configuration
         */
        if ($RequestData.httpLibUpgrade) {
            $httpconfiguration.upgradeHTTP = $RequestData.httpLibUpgrade;
        }

        $RequestData.link = this.upgradeHttpMethod($RequestData.link);
        $RequestData.link = this.downgradeHttpsMethod($RequestData.link);
        var $httpMethod = this.determineHTTPMethod($RequestData.link);

        if ($httpMethod.indexOf('http:') > -1) {
            console.error('This request to ' + $RequestData.link + ' is considered insecure because it is using http:, soon browsers will block http: requests entirely for security, please enforce an upgrade to HTTPs for security');
        }

        /**
         * @task Make request
         */

        if ($canUsejQuery) {
            // Make Request with jQuery
            console.log('jQuery');
            jQuery.ajax({
                type: this.RequestData.type,
                data: {},
                url: this.RequestData.link,
                success: function (response) {
                    console.log(response);
                    this.ResponseData.response = response;
                },
                error: function (err, errCode, errMessage) {
                    this.ResponseData.response = '';
                    this.ResponseData.hasErrors = true;
                    console.log('error');
                }
            });
        }
        else {
            // Make Request using old way for older browsers/customs browsers/browsers we couldn't detect reliably
            var $xmlHttp = new XMLHttpRequest();
            $xmlHttp.onreadystatechange = function () {
                if ($xmlHttp.readyState == "4" && $xmlHttp.status == 200) {
                    this.ResponseData.response = $xmlHttp.responseText;
                    console.log('success');
                }
                else if ($xmlHttp.readyState == "4" && $xmlHttp.status == 500 || $xmlHttp.readyState == "4" && $xmlHttp.status == 403 || $xmlHttp.readyState == "4" && $xmlHttp.status == 404 || $xmlHttp.readyState == "4" && $xmlHttp.status == 503) {
                    this.ResponseData.response = '';
                    this.ResponseData.hasErrors = true;
                    console.log('error');
                }
            };
            $xmlHttp.open(this.RequestData.type, this.RequestData.link, true);
            $xmlHttp.send(null);
        }

        return this.ResponseData;
    }
};

/**
 * @endsection
 */

/**
 * @section License
 */

/**
 * The code written by Curtis <[removed]@gmail.com> hereinby referred to as "the code" or "code" or "logical functionality"
 * The author Curtis hereinby referred to as "the author" or "author" or "code creator"
 * -------------------------------------------------------------------------------------------------------------------------
 * The author reserves all rights to the code written by the author, however the code is available for all to use, as long as they leave the proper license credits.
 * The author reverses the right to change this license without prior notification.
 * The author permits usage of Http.js for commercial businesses, corporates, enterprises, and businesses of any size.
 * The author permits usage of Http.js for personal/private websites/projects, as long as the license is not violated.
 * The user of the code must leave the license as-in without modification, and must give creation credits if the code is modified in any way/shape/form.
 */

/**
 * @endsection
 */


Solution

  • That is because this inside success and error callbacks is not the same this outside it. So ResponseData happens to be undefined hence it can't have response property. Try using bind():

    success: function (response) {
        console.log(response);
        this.ResponseData.response = response;
    }.bind(this),
    error: function (err, errCode, errMessage) {
        this.ResponseData.response = '';
        this.ResponseData.hasErrors = true;
        console.log('error');
    }.bind(this)
    

    bind() will make the callback's scopes to be set to your previous this.