【问题标题】:ngShow expression is evaluated too earlyngShow 表达式的评估过早
【发布时间】:2018-05-19 12:47:29
【问题描述】:

我有一个像这样的角度组件和控制器:

export class MyController{

    static $inject = [MyService.serviceId];

    public elements: Array<string>;
    public errorReceived : boolean;

    private elementsService: MyService;

    constructor(private $elementsService: MyService) {
        this.errorReceived = false;
        this.elementsService= $elementsService;
    }

    public $onInit = () => {
        this.elements =  this.getElements();
        console.log("tiles: " + this.elements);
    }


    private getElements(): Array<string> {
        let result: Array<string> = [];
        this.elementsService.getElements().then((response) => {
            result = response.data;
            console.log(result);
        }).catch(() => {
            this.errorReceived = true;
        });
        console.log(result);
        return result;
    }
}

export class MyComponent implements ng.IComponentOptions {
    static  componentId = 'myId';

    controller = MyController;
    controllerAs = 'vm';

    templateUrl = $partial => $partial.getPath('site.html');
}

MyService 实现如下所示:

export class MyService {

    static serviceId = 'myService';

    private http: ng.IHttpService;

    constructor(private $http: ng.IHttpService) {
        this.http = $http;
    }

    public getElements(): ng.IPromise<{}> {
        return this.http.get('./rest/elements');
    }

}

我面临的问题是数组元素在调用 onInit() 后包含一个空数组。但是,后来,我看到由于调用了 getELements() 中的成功函数并将元素写入控制台,因此收到了数据。

我在模板中使用的元素来决定是否应显示特定元素:

<div>
    <elements ng-show="vm.elements.indexOf('A') != -1"></elements>
</div>

现在的问题是 vm.elements 首先包含一个空数组,然后才用实际值填充该数组。但是模板中的这个表达式已经被计算过了。我该如何改变呢?

【问题讨论】:

  • 是否要在值发生变化后强制进行变化检测,也可以使用 Observables 在 temaptate 中的变量更改值后自动触发变化检测
  • 在您的控制器中 getElements() 是错误的。实现毫无意义
  • 没有“Angular 1.5”。只有 AngularJS 1.5。让我们不要用懒惰的名字让一个令人困惑的场景变得更加混乱。

标签: angularjs typescript angularjs-directive es6-promise angularjs-ng-show


【解决方案1】:

您当前的实现没有意义。您需要了解 Promise 和异步构造如何在该语言中工作以实现您的目标。幸运的是,这并不难。

您当前实现的问题是您的 init 方法立即返回一个空数组。它不返回服务调用的结果,因此控制器中的属性只是再次绑定到一个空数组,这不是您想要的。

请考虑以下情况:

export class MyController {
   elements: string[] = [];

   $onInit = () => {
     this.getElements()
       .then(elements => {
         this.elements = elements;
       });
  };

  getElements() {
    return this.elementsService
      .getElements()
      .then(response => response.data)
      .catch(() => {
        this.errorReceived = true;
      });
   } 
}

您可以利用 async/await 使其更具可读性

export class MyController {
   elements: string[] = [];

   $onInit = async () => {
     this.elements = await this.getElements();
   };

   async getElements() {
     try {
       const {data} = await this.elementsService.getElements();
       return data;
     } 
     catch {
       this.errorReceived = true;
     }
   } 
}

请注意上述如何启用标准try/catch 语法。这是async/await 的众多优势之一。

还有一点值得注意的是,您的数据服务应该解开响应,data 属性,并返回它,以便您的控制器不关心 HTTP 服务的语义。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-29
    • 2023-02-15
    • 1970-01-01
    相关资源
    最近更新 更多