【问题标题】:can not read get property of undefined angular 2 error无法读取未定义角度 2 错误的获取属性
【发布时间】:2016-07-20 05:41:43
【问题描述】:

您好,我正在尝试从 google api 获取城市名称,但下面的错误是我的代码

应用组件类

 import {Component, OnInit} from 'angular2/core';
    import {marketComponent} from './market.component';
    import {RouteConfig, ROUTER_DIRECTIVES} from 'angular2/router';
    import {introComponent} from './intro.component';
    import {geoService} from './service.geo';
    import {JSONP_PROVIDERS}  from 'angular2/http';
    declare var google: any;
    @Component({
        selector: 'my-app',
        templateUrl: 'app/app.component.html',
        directives: [ROUTER_DIRECTIVES],
        providers: [JSONP_PROVIDERS, geoService]
     })
    @RouteConfig([
        { path: '/intro', name: 'Intro', component: introComponent,      useAsDefault: true },
        { path: '/market', name: 'Market', component: marketComponent },
    ])
    export class AppComponent  {
    constructor(private _http: geoService) { }

    public maps;
    public cat_error: Boolean = false;
    public xml_Latitude :string;
    public xml_Lang: string;

    ngOnInit() {
        if (navigator.geolocation) {
            navigator.geolocation.getCurrentPosition(this.showPosition);
        } else {
            alert("Geolocation is not supported by this browser.");
        }
        var input: any = document.getElementById('google_places_ac');
        var autocomplete = new google.maps.places.Autocomplete(input, {});
        google.maps.event.addListener(autocomplete, 'place_changed', function  ()     {
            var place = autocomplete.getPlace();
            console.log(place)
        });
    }

    showPosition(position) {
        this.xml_Latitude = position.coords.latitude;
        this.xml_Lang = position.coords.longitude;

        this._http.getPlaces(this.xml_Latitude, this.xml_Lang).subscribe(
            data => { this.maps = data },
            err => { this.cat_error = true }
        );

        var result = this.maps.results;
        var city = result[0].address_components[4].long_name + "," + result[0].address_components[6].long_name;
        alert(city);


    }  
}

和地理服务文件

 import {Injectable} from 'angular2/core';
    import { Response, Jsonp} from 'angular2/http';
    import 'rxjs/add/operator/map';

    @Injectable()
    export class geoService {

    constructor(private http: Jsonp) { }

    public xml_Latitude: string;
    public xml_Lang: string;

    public getPlaces(xml_Latitude, xml_Lang) {
        return this.http.get(`http://maps.googleapis.com/maps/api/geocode/json?latlng=
                            '${this.xml_Latitude}','${this.xml_Lang}'&sensor=true`)
                .map((res: Response) => res.json())
                .catch(this.handleError);
        }

    private handleError(error: Response) {
            console.error(error);
            return error.json().error || 'Server error';
        }
    }

错误还说 getplaces 不是函数,我想我遗漏了一些东西但不知道是什么......

【问题讨论】:

  • 什么属性未定义?请添加具体的错误消息。

标签: api google-maps-api-3 typescript maps angular


【解决方案1】:

我认为您应该将 result 块移动到与 getPlaces 方法调用关联的订阅回调中:

showPosition(position) {
    this.xml_Latitude = position.coords.latitude;
    this.xml_Lang = position.coords.longitude;

    this._http.getPlaces(this.xml_Latitude, this.xml_Lang).subscribe(
        data => {
          this.maps = data;

          var result = this.maps.results; // <----------
          var city = result[0].address_components[4].long_name + "," + result[0].address_components[6].long_name;
          alert(city);
        },
        err => { this.cat_error = true }
    );
}

这是因为this.maps 在调用回调之前是未定义的。并且您尝试在 (this.maps.results) 之前获取 result 属性。

编辑

我还在navigator.geolocation.getCurrentPosition 行看到了一个问题。你可以这样重构你的代码:

if (navigator.geolocation) {
  navigator.geolocation.getCurrentPosition((position) => { // <----
    this.showPosition(position);
  });
} else {
  alert("Geolocation is not supported by this browser.");
}

【讨论】:

  • 移动它没有用。而不是jsonp同样的问题
  • 哦,还有另一个问题:navigator.geolocation.getCurrentPosition。我更新了我的答案...
  • 实际上这将再次产生“这个”问题我只是将其更改为 res=>{then 函数并在其中 res.coord.lat ...} ...但感谢您的帮助...
  • 真的吗? showPosition 方法现在在组件的上下文中执行(this == 组件实例)。所以这个方法中的this._http 现在不是未定义的......
  • 是的,原因是我没有将它用于导航器实例,因此它不会与组件实例冲突。它是javascript问题,您应该阅读上面的解释。
【解决方案2】:

除了 Thierry 确定的回调排序问题之外,您在这一行还有一个丢失的 this 上下文:

navigator.geolocation.getCurrentPosition(this.showPosition);

问题

您遇到了称为不正确的this 上下文 的经典JavaScript 问题。 this keyword in JavaScript 的行为与其他语言(如 C# 和 Java)中的行为不同。

this 的工作原理

函数中的this关键字是这样确定的: * 如果函数是通过调用.bind 创建的,则this 值是提供给bind 的参数 * 如果函数是通过方法调用调用的,例如expr.func(args),那么this 就是expr * 否则 * 如果代码在strict modethis就是undefined * 否则,thiswindow(在浏览器中)

让我们看看这在实践中是如何工作的:

class Foo {
    value = 10;
    doSomething() {
        // Prints 'undefined', not '10'
        console.log(this.value);
    }
}
let f = new Foo();
window.setTimeout(f.doSomething, 100);

此代码将打印undefined(或者,在严格模式下,抛出异常)。 这是因为我们最终进入了上面决策树的最后一个分支。 调用了doSomething 函数,该函数不是bind 调用的结果,也不是在方法语法位置调用的。

我们看不到setTimeout 的代码来查看其调用的样子,但我们不需要。 需要意识到的是,所有doSomething 方法都指向同一个函数对象。 换句话说:

let f1 = new Foo();
let f2 = new Foo();
// 'true'
console.log(f1.doSomething === f2.doSomething);

我们知道setTimeout只能看到我们传递给它的函数,所以当它调用那个函数时, 它无法知道要提供哪个thisthis 上下文由于我们引用该方法而没有调用它。

红旗

一旦您了解this 的问题,就很容易发现它们:

class Foo {
    value = 10;
    method1() {
        doSomething(this.method2); // DANGER, method reference without invocation
    }   
    method2() {
        console.log(this.value);
    }
}

解决方案

这里有几个选项,每个选项都有自己的取舍。 最佳选择取决于从不同调用站点调用相关方法的频率。

类定义中的箭头函数

不要使用普通的方法语法,而是使用arrow function 来初始化每个实例的成员。

class DemonstrateScopingProblems {
    private status = "blah";

    public run = () => {
        // OK
        console.log(this.status);
    }
}
let d = new DemonstrateScopingProblems();
window.setTimeout(d.run); // OK
  • 好/坏:这会为类的每个实例的每个方法创建一个额外的闭包。如果这个方法通常只用在常规的方法调用中,那就大材小用了。但是,如果它在回调位置大量使用,则类实例捕获this 上下文会更有效,而不是每个调用站点在调用时创建一个新的闭包。
  • 很好:外部调用者不可能忘记处理 this 上下文
  • 好:TypeScript 中的类型安全
  • 很好:如果函数有参数,则无需额外工作
  • 错误:派生类无法调用使用super. 以这种方式编写的基类方法
  • 错误:哪些方法是“预绑定”的,哪些方法不会在您的类与其使用者之间创建额外的非类型安全契约的确切语义。

参考点的函数表达式

出于说明原因,此处显示了一些虚拟参数:

class DemonstrateScopingProblems {
    private status = "blah";

    public something() {
        console.log(this.status);
    }

    public run(x: any, y: any) {
        // OK
        console.log(this.status + ': ' + x + ',' + y);
    }
}
let d = new DemonstrateScopingProblems();
// With parameters
someCallback((n, m) => d.run(n, m));
// Without parameters
window.setTimeout(() => d.something(), 100);
  • 好/坏:与第一种方法相比,内存/性能权衡相反
  • 好:在 TypeScript 中,这具有 100% 的类型安全性
  • 好:在 ECMAScript 3 中工作
  • 很好:您只需键入一次实例名称
  • 错误:您必须输入两次参数
  • 不好:不容易使用可变参数

【讨论】:

  • 哇 .. 感谢您的精彩解释,我会试一试并告诉您
  • 哇,你刚刚解决了我的问题,我更改了函数,现在它可以工作并得到响应,唯一的问题是我无法提取结果,即这条线不起作用你能建议什么吗? var 结果 = this.maps.results; //
  • 请提出一个新问题。评论不适用于后续问题。
  • 嗨,你能帮我解决这个问题吗?我没有得到任何答案.. stackoverflow.com/questions/36386414/…
猜你喜欢
  • 2023-03-30
  • 2022-01-08
  • 2018-07-19
  • 2023-03-29
  • 2018-08-10
  • 2019-04-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多