Angular 窗口未定义错误

标签 angular typescript authentication restful-authentication

我正在尝试构建一个 Angular 应用程序,虽然应用程序没有任何问题,但我注意到控制台中出现运行时错误。

错误:未定义窗口

这就是应用程序无法正常运行的原因。

为了便于分析,这里是我的 app.componenet.ts 上的代码:

import {Component} from 'angular2/core';

import {Contact} from './contact';
import {ContactDetailComponent} from './contact-detail.component';

import * as force from './force';

interface Contact {
    Id: string;
    Name: string;
};

@Component({
    selector: 'my-app',
    template: `
        <header><h1>Salesforce Contacts</h1></header>
        <div class="content">
            <ul class="contacts">
                <li *ngFor="#contact of contacts" (click)="onSelect(contact)" [class.selected]="contact === selectedContact">
                    {{contact.FirstName}} {{contact.LastName}}
                </li>
            </ul>
            <contact-detail [contact]="selectedContact"></contact-detail>
        </div>`,
    styles:[`
        header {background-color:#03A9F4; padding:14px; margin-bottom:12px; box-shadow:0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24)}
        h1 {font-weight:300}
        header > h1 {font-weight:300; font-size:24px; margin:0; color: #FFFFFF}
        .content {display:flex}
        .contacts {list-style-type: none; width: 220px; margin: 0 24px 0 -24px}
        .contacts li {padding:4px 8px; cursor:pointer}
        .contacts li:hover {color:#369; background-color:#EEE}
        .selected { background-color:#EEE; color:#369}
    `],
    directives: [ContactDetailComponent]
})

export class AppComponent {

    public contacts:Contact[];
    public selectedContact:Contact;

    constructor() {

        force.init({
            appId: "3MVG9sG9Z3Q1Rlbc4tkIx2fI3ZUDVyYt86Ypl8ZqBXTpzPbQNHxq7gpwKcN75BB.fpgHxzSWgwgRY6nVfvBUe",
            proxyURL: "https://dev-cors-proxy.herokuapp.com/"
        });
        force.login().then(() => {
            force.query("select id, firstname, lastname, phone from contact").then(result => this.contacts = (<any>result).records);
        });
    }

    onSelect(contact: Contact) {
        this.selectedContact = contact;
    }

}

您还会在下面找到我在应用程序文件夹下添加的 force.ts 文件。 Error screenshot

Force.ts 文件:

/**
 * ForceJS - REST toolkit for Salesforce.com
 * Author: Christophe Coenraets @ccoenraets
 * Version: 0.7.2
 */
"use strict";

let window:any = this.window;

let // The login URL for the OAuth process
    // To override default, pass loginURL in init(props)
        loginURL = 'https://login.salesforce.com',

// The Connected App client Id. Default app id provided - Not for production use.
// This application supports http://localhost:8200/oauthcallback.html as a valid callback URL
// To override default, pass appId in init(props)
        appId = '3MVG9fMtCkV6eLheIEZplMqWfnGlf3Y.BcWdOf1qytXo9zxgbsrUbS.ExHTgUPJeb3jZeT8NYhc.hMyznKU92',

// The force.com API version to use.
// To override default, pass apiVersion in init(props)
        apiVersion = 'v35.0',

// Keep track of OAuth data (access_token, refresh_token, and instance_url)
        oauth,

// By default we store fbtoken in sessionStorage. This can be overridden in init()
        tokenStore:any = {},

// if page URL is http://localhost:3000/myapp/index.html, context is /myapp
        context = window.location.pathname.substring(0, window.location.pathname.lastIndexOf("/")),

// if page URL is http://localhost:3000/myapp/index.html, serverURL is http://localhost:3000
        serverURL = window.location.protocol + '//' + window.location.hostname + (window.location.port ? ':' + window.location.port : ''),

// if page URL is http://localhost:3000/myapp/index.html, baseURL is http://localhost:3000/myapp
        baseURL = serverURL + context,

// Only required when using REST APIs in an app hosted on your own server to avoid cross domain policy issues
// To override default, pass proxyURL in init(props)
        proxyURL = baseURL,

// if page URL is http://localhost:3000/myapp/index.html, oauthCallbackURL is http://localhost:3000/myapp/oauthcallback.html
// To override default, pass oauthCallbackURL in init(props)
        oauthCallbackURL = baseURL + '/oauthcallback.html',

// Reference to the Salesforce OAuth plugin
        oauthPlugin,

// Whether or not to use a CORS proxy. Defaults to false if app running in Cordova, in a VF page,
// or using the Salesforce console. Can be overriden in init()
        useProxy = (window.cordova || window.SfdcApp || window.sforce) ? false : true;

/*
 * Determines the request base URL.
 */
let getRequestBaseURL = () => {

    let url;

    if (useProxy) {
        url = proxyURL;
    } else if (oauth.instance_url) {
        url = oauth.instance_url;
    } else {
        url = serverURL;
    }

    // dev friendly API: Remove trailing '/' if any so url + path concat always works
    if (url.slice(-1) === '/') {
        url = url.slice(0, -1);
    }

    return url;
};

let parseQueryString = queryString => {
    let qs = decodeURIComponent(queryString),
            obj = {},
            params = qs.split('&');
    params.forEach(param => {
        let splitter = param.split('=');
    obj[splitter[0]] = splitter[1];
});
    return obj;
};

let toQueryString = obj => {
    let parts = [],
            i;
    for (i in obj) {
        if (obj.hasOwnProperty(i)) {
            parts.push(encodeURIComponent(i) + "=" + encodeURIComponent(obj[i]));
        }
    }
    return parts.join("&");
};

let refreshTokenWithPlugin = () => {

    return new Promise((resolve, reject) => {
                oauthPlugin.authenticate(
                    function (response) {
                        oauth.access_token = response.accessToken;
                        tokenStore.forceOAuth = JSON.stringify(oauth);
                        resolve();
                    },
                    function () {
                        console.error('Error refreshing oauth access token using the oauth plugin');
                        reject();
                    }
            );
});

};

let refreshTokenWithHTTPRequest = () => new Promise((resolve, reject) => {

    if (!oauth.refresh_token) {
    console.log('ERROR: refresh token does not exist');
    reject();
    return;
}

let xhr = new XMLHttpRequest(),

        params = {
            'grant_type': 'refresh_token',
            'refresh_token': oauth.refresh_token,
            'client_id': appId
        },

        url = useProxy ? proxyURL : loginURL;

url = url + '/services/oauth2/token?' + toQueryString(params);

xhr.onreadystatechange = () => {
    if (xhr.readyState === 4) {
        if (xhr.status === 200) {
            console.log('Token refreshed');
            let res = JSON.parse(xhr.responseText);
            oauth.access_token = res.access_token;
            tokenStore.forceOAuth = JSON.stringify(oauth);
            resolve();
        } else {
            console.log('Error while trying to refresh token: ' + xhr.responseText);
            reject();
        }
    }
};

xhr.open('POST', url, true);
if (!useProxy) {
    xhr.setRequestHeader("Target-URL", loginURL);
}
xhr.send();

});

let refreshToken = () => {
    if (oauthPlugin) {
        return refreshTokenWithPlugin();
    } else {
        return refreshTokenWithHTTPRequest();
    }
};

let joinPaths = (path1, path2) => {
    if (path1.charAt(path1.length - 1) !== '/') path1 = path1 + "/";
    if (path2.charAt(0) === '/') path2 = path2.substr(1);
    return path1 + path2;
}

/**
 * Initialize ForceJS
 * @param params
 *  appId (optional)
 *  loginURL (optional)
 *  proxyURL (optional)
 *  oauthCallbackURL (optional)
 *  apiVersion (optional)
 *  accessToken (optional)
 *  instanceURL (optional)
 *  refreshToken (optional)
 */
export let init = params => {

    if (params) {
        appId = params.appId || appId;
        apiVersion = params.apiVersion || apiVersion;
        loginURL = params.loginURL || loginURL;
        oauthCallbackURL = params.oauthCallbackURL || oauthCallbackURL;
        proxyURL = params.proxyURL || proxyURL;
        useProxy = params.useProxy === undefined ? useProxy : params.useProxy;

        if (params.accessToken) {
            if (!oauth) oauth = {};
            oauth.access_token = params.accessToken;
        }

        if (params.instanceURL) {
            if (!oauth) oauth = {};
            oauth.instance_url = params.instanceURL;
        }

        if (params.refreshToken) {
            if (!oauth) oauth = {};
            oauth.refresh_token = params.refreshToken;
        }
    }

    console.log("useProxy: " + useProxy);

};

/**
 * Discard the OAuth access_token. Use this function to test the refresh token workflow.
 */
export let discardToken = () => {
    delete oauth.access_token;
    tokenStore.forceOAuth = JSON.stringify(oauth);
};

/**
 * Login to Salesforce using OAuth. If running in a Browser, the OAuth workflow happens in a a popup window.
 * If running in Cordova container, it happens using the Mobile SDK 2.3+ Oauth Plugin
 */
export let login = () => {
    if (window.cordova) {
        return loginWithPlugin();
    } else {
        return loginWithBrowser();
    }
};

export let loginWithPlugin = () => new Promise((resolve, reject) => {
    document.addEventListener("deviceready", () => {
    oauthPlugin = window.cordova.require("com.salesforce.plugin.oauth");
if (!oauthPlugin) {
    console.error('Salesforce Mobile SDK OAuth plugin not available');
    reject('Salesforce Mobile SDK OAuth plugin not available');
    return;
}
oauthPlugin.getAuthCredentials(
        function (creds) {
            // Initialize ForceJS
            init({
                accessToken: creds.accessToken,
                instanceURL: creds.instanceUrl,
                refreshToken: creds.refreshToken
            });
            resolve();
        },
        function (error) {
            console.log(error);
            reject(error);
        }
);
}, false);
});

export let loginWithBrowser = () => new Promise((resolve, reject) => {

console.log('loginURL: ' + loginURL);
console.log('oauthCallbackURL: ' + oauthCallbackURL);

let loginWindowURL = loginURL + '/services/oauth2/authorize?client_id=' + appId + '&redirect_uri=' + oauthCallbackURL + '&response_type=token';

document.addEventListener("oauthCallback", (evt) => {

    let event:any = evt;
    // Parse the OAuth data received from Salesforce
    let url = event.detail,
    queryString,
    obj;

if (url.indexOf("access_token=") > 0) {
    queryString = url.substr(url.indexOf('#') + 1);
    obj = parseQueryString(queryString);
    oauth = obj;
    tokenStore.forceOAuth = JSON.stringify(oauth);
    resolve();
} else if (url.indexOf("error=") > 0) {
    queryString = decodeURIComponent(url.substring(url.indexOf('?') + 1));
    obj = parseQueryString(queryString);
    reject(obj);
} else {
    reject({status: 'access_denied'});
}

});

window.open(loginWindowURL, '_blank', 'location=no');

});

/**
 * Gets the user's ID (if logged in)
 * @returns {string} | undefined
 */
export let getUserId = () => (typeof(oauth) !== 'undefined') ? oauth.id.split('/').pop() : undefined;

/**
 * Get the OAuth data returned by the Salesforce login process
 */
export let getOAuthResult = () => oauth;

/**
 * Check the login status
 * @returns {boolean}
 */
export let isAuthenticated = () => (oauth && oauth.access_token) ? true : false;

/**
 * Lets you make any Salesforce REST API request.
 * @param obj - Request configuration object. Can include:
 *  method:  HTTP method: GET, POST, etc. Optional - Default is 'GET'
 *  path:    path in to the Salesforce endpoint - Required
 *  params:  queryString parameters as a map - Optional
 *  data:  JSON object to send in the request body - Optional
 */
export let request = obj => new Promise((resolve, reject) => {

    console.log(oauth);

if (!oauth || (!oauth.access_token && !oauth.refresh_token)) {
    reject('No access token. Please login and try again.');
    return;
}

let method = obj.method || 'GET',
        xhr = new XMLHttpRequest(),
        url = getRequestBaseURL();

// dev friendly API: Add leading '/' if missing so url + path concat always works
if (obj.path.charAt(0) !== '/') {
    obj.path = '/' + obj.path;
}

url = url + obj.path;

if (obj.params) {
    url += '?' + toQueryString(obj.params);
}

xhr.onreadystatechange = () => {
    if (xhr.readyState === 4) {
        if (xhr.status > 199 && xhr.status < 300) {
            resolve(xhr.responseText ? JSON.parse(xhr.responseText) : undefined);
        } else if (xhr.status === 401 && oauth.refresh_token) {
            refreshToken()
            // Try again with the new token
                    .then(() => request(obj).then(data => resolve(data)).catch(error => reject(error)))
        .catch(() => {
                console.error(xhr.responseText);
            let error = xhr.responseText ? JSON.parse(xhr.responseText) : {message: 'Server error while refreshing token'};
            reject(error);
        });
        } else {
            let error = xhr.responseText ? JSON.parse(xhr.responseText) : {message: 'Server error while executing request'};
            reject(error);
        }
    }
};

xhr.open(method, url, true);
xhr.setRequestHeader("Accept", "application/json");
xhr.setRequestHeader("Authorization", "Bearer " + oauth.access_token);
if (obj.contentType) {
    xhr.setRequestHeader("Content-Type", obj.contentType);
}
if (useProxy) {
    xhr.setRequestHeader("Target-URL", oauth.instance_url);
}
xhr.send(obj.data ? JSON.stringify(obj.data) : undefined);

});

/**
 * Convenience function to execute a SOQL query
 * @param soql
 */
export let query = soql => request(
        {
            path: '/services/data/' + apiVersion + '/query',
            params: {q: soql}
        }
);

/**
 * Convenience function to retrieve a single record based on its Id
 * @param objectName
 * @param id
 * @param fields
 */
export let retrieve = (objectName, id, fields) => request({
            path: '/services/data/' + apiVersion + '/sobjects/' + objectName + '/' + id,
            params: fields ? {fields: fields} : undefined
        }
);

/**
 * Convenience function to retrieve picklist values from a SalesForce Field
 * @param objectName
 */
export let getPickListValues = objectName => request({
            path: '/services/data/' + apiVersion + '/sobjects/' + objectName + '/describe'
        }
);

/**
 * Convenience function to create a new record
 * @param objectName
 * @param data
 */
export let create = (objectName, data) => request({
            method: 'POST',
            contentType: 'application/json',
            path: '/services/data/' + apiVersion + '/sobjects/' + objectName + '/',
            data: data
        }
);

/**
 * Convenience function to update a record. You can either pass the sobject returned by retrieve or query or a simple JavaScript object.
 * @param objectName
 * @param data The object to update. Must include the Id field.
 */
export let update = (objectName, data) => {

    let id = data.Id || data.id,
            fields = JSON.parse(JSON.stringify(data));

    delete fields.attributes;
    delete fields.Id;
    delete fields.id;

    return request({
                method: 'POST',
                contentType: 'application/json',
                path: '/services/data/' + apiVersion + '/sobjects/' + objectName + '/' + id,
                params: {'_HttpMethod': 'PATCH'},
                data: fields
            }
    );
};

/**
 * Convenience function to delete a record
 * @param objectName
 * @param id
 */
export let del = (objectName, id) => request({
            method: 'DELETE',
            path: '/services/data/' + apiVersion + '/sobjects/' + objectName + '/' + id
        }
);

/**
 * Convenience function to upsert a record
 * @param objectName
 * @param externalIdField
 * @param externalId
 * @param data
 */
export let upsert = (objectName, externalIdField, externalId, data) => request({
            method: 'PATCH',
            contentType: 'application/json',
            path: '/services/data/' + apiVersion + '/sobjects/' + objectName + '/' + externalIdField + '/' + externalId,
            data: data
        }
);

/**
 * Convenience function to invoke APEX REST endpoints
 * @param pathOrParams
 */
export let apexrest = pathOrParams => {

    let params;

    if (pathOrParams.substring) {
        params = {path: pathOrParams};
    } else {
        params = pathOrParams;

        if (params.path.charAt(0) !== "/") {
            params.path = "/" + params.path;
        }

        if (params.path.substr(0, 18) !== "/services/apexrest") {
            params.path = "/services/apexrest" + params.path;
        }
    }

    return request(params);
};

/**
 * Convenience function to invoke the Chatter API
 * @param pathOrParams
 */
export let chatter = pathOrParams => {

    let basePath = "/services/data/" + apiVersion + "/chatter";
    let params;

    if (pathOrParams && pathOrParams.substring) {
        params = {path: joinPaths(basePath, pathOrParams)};
    } else if (pathOrParams && pathOrParams.path) {
        params = pathOrParams;
        params.path = joinPaths(basePath, pathOrParams.path);
    } else {
        return new Promise((resolve, reject) => reject("You must specify a path for the request"));
    }

    return request(params);

};

最佳答案

你需要施法窗口。 不需要声明变量窗口。

(<any>window) 

关于 Angular 窗口未定义错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48071314/

相关文章:

javascript - 如何修复 ' Argument of type ' 数字“无法分配给类型 'string | RegExp' 的参数”

twitter-bootstrap-3 - 如何在 Angular2 中实现可折叠侧边栏?

javascript - Angular 4 上的 Chartist 破坏了我的应用程序

javascript - 在javascript中计算iso时间格式的时差?

typescript - 有没有办法强制 Set<T> 构造函数的调用者提供类型参数?

python-3.x - 为什么我的current_user不通过flask-login进行身份验证?

php - 在 PHP 脚本中保护 MySQL 密码

json - Angular 如何检查 HttpRequest 对象以为 header 设置正确的内容类型?

node.js - 在 Jest 的不同环境中运行相同的测试

c# .net - 身份验证过早过期