Angular 2和TypeScript承诺

Angular 2和TypeScript承诺,typescript,angular,Typescript,Angular,我正在尝试为我的应用程序中的某个组件使用routercandactivate功能。使用它的简单方法如下: routerCanDeactivate() { return confirm('Are you sure you want to leave this screen?'); } 我唯一的问题是它很难看。它只使用浏览器生成的确认提示。我真的想使用一个自定义模式,比如引导模式。我让引导模式根据他们单击的按钮返回真值或假值。我正在实现的routerCanDeactivate可以接受真/假

我正在尝试为我的应用程序中的某个组件使用
routercandactivate
功能。使用它的简单方法如下:

routerCanDeactivate() {
    return confirm('Are you sure you want to leave this screen?');
}
我唯一的问题是它很难看。它只使用浏览器生成的确认提示。我真的想使用一个自定义模式,比如引导模式。我让引导模式根据他们单击的按钮返回真值或假值。我正在实现的
routerCanDeactivate
可以接受真/假值或解析为真/假的承诺

以下是具有
routerCanDeactivate
方法的组件的代码:

export class MyComponent implements CanDeactivate {
    private promise: Promise<boolean>;

    routerCanDeactivate() {
        $('#modal').modal('show');
        return this.promise;
    }

    handleRespone(res: boolean) {
        if(res) {
            this.promise.resolve(res);
        } else {
            this.promise.reject(res);
        }
    }
}
以及
handleResponse
功能:

handleResponse(res: boolean) {
    console.log('res: ', res);
    this.promise.then(res => {
        console.log('res: ', res);
    });
}
它仍然不能正常工作,但是模态显示并等待响应。当你说“是”离开时,它停留在组件上。此外,记录的第一个
res
是从组件返回的正确值,但
中的值。然后
函数与传递给
HandlerResponse
函数的值不同

更多更新

在进一步阅读之后,似乎在
promise
声明中,它设置了
resolve
值,而
promise
无论如何都具有该值。因此,即使稍后我调用
.then
方法,它也不会更改
promise
的值,并且我无法使其变为真并切换组件。有没有办法使
承诺
不具有默认值,并且必须等到its
方法被调用后才能执行

更新功能:

private promise: Promise<boolean> = new Promise((resolve, reject) => resolve(false) );

handleResponse(res: any) {
    this.promise.then(val => {
        val = res;
    });
}
当我传入
null
、一个
string
或一个
boolean
时,也会发生同样的情况。试图在
Deferred
类中提供
catch
函数无效

延期班

导出类延迟{
承诺:承诺;
决议:(价值?:T |承诺)=>无效;
拒绝:(原因?:任何)=>无效;
构造函数(){
this.promise=新承诺((解决、拒绝)=>{
this.resolve=resolve;
这个。拒绝=拒绝;
});
}
}
有没有一个原因可以解释为什么在承诺中没有“解决”属性是错误的

是的,而且tsc无法找到
es6 promise
的正确输入。为了避免ng2项目中的这种类型问题和其他类型问题,您需要显式地包括

///<reference path="node_modules/angular2/typings/browser.d.ts"/>
相当于

resolve(false);  //always false
*注意:这(可能)是暂时的,在以后的测试版/发行版中不需要

更新以回应您的评论:

我似乎不知道如何等待HandlerResponse函数运行并等待响应

我仍然不清楚您想在这里做什么,但一般来说,您希望
handleResponse
返回自己的承诺,然后:

private promise: Promise<boolean> = new Promise((resolve, reject) => {
  handlePromise.then(resultOfHandleResult => {
    //assuming you need to process this result somehow (otherwise this is redundant) 
    const res = doSomethingWith(resultOfHandleResult); 
    resolve(res); 
  })
});

handleResponse(res: any) {
    this.promise.then(val => {
        val = res;
    });
}

我不熟悉bootstrap模式api,但我希望在创建关闭事件时会有一种绑定到关闭事件的方法

export class MyComponent implements CanDeactivate {

  routerCanDeactivate(): Promise<boolean> {
    let $modal = $('#modal').modal();
    return new Promise<boolean>((resolve, reject) => {
      $modal.on("hidden.bs.modal", result => {
        resolve(result.ok);
      });
      $modal.modal("show");
    });
  }

}

这是一个对我有用的技巧。它与@iliachory的答案非常相似,但使用了模态组件而不是jQuery模态。这使得它有点“角度2”的方法。我相信这仍然与你的问题有关

首先,为模型构建一个角度组件:

import {Component, Output, EventEmitter} from '@angular/core;
@Component({
    selector: 'myModal',
    template: `<div class="myModal" [hidden]="showModal">
          <!-- your modal HTML here... -->
          <button type="button" class="btn" (click)="clickedYes()">Yes</button>
          <button type="button" class="btn" (click)="clickedNo()">No</button>
        </div>
    `
})

export class MyModal{
    private hideModal: boolean = true;
    @Output() buttonResultEmitter = new EventEmitter();
    constructor(){}
    openModal(){
        this.hideModal = false;
    }
    closeModal(){
        this.hideModal = true;
    }
    clickedYes(){
        this.buttonResultEmitter.emit(true);
    }
    clickedNo(){
        this.buttonResultEmitter.emit(false);
    }
}
在类别代码中:

private myModal: MyModal;
创建一个返回承诺的方法,该承诺订阅给myModal上的eventEmitter:

userClick(): Promise<boolean> {
    var prom: new Promise<boolean>((resolve, reject) => {
        this.myModal.buttonResultEmitter.subscribe(
            (result) => {
                if (result == true){
                    resolve(true);
                } else {
                    reject(false);
                }
         });
     });
     return prom;
}


正如@drewmoore所提到的,在Angular 2中使用可观测值是首选,但A)这不是你的问题,B)routerCanDeactivate钩子解析为布尔承诺,因此这种方法对我来说似乎更自然。

因为每个人都在谈论可观测值,我想我会看看@petryuno1的答案并以此为基础

从his的
ModalComponent
开始:

import {Component, Output, ViewChild} from '@angular/core;
@Component({
    selector: 'myModal',
    template: `<div class="myModal" [hidden]="showModal">
          <!-- your modal HTML here... -->
          <button type="button" class="btn" (click)="clickedYes($event)">Yes</button>
          <button type="button" class="btn" (click)="clickedNo($event)">No</button>
        </div>
    `
})

export class MyModal{
    private hideModal: boolean = true;
    private clickStream = new Subject<boolean>();
    @Output() observable = this.clickStream.asObservable();

    constructor(){}
    openModal(){
        this.hideModal = false;
    }
    closeModal(){
        this.hideModal = true;
    }
    clickedYes(){
        this.clickStream.next(true);
    }
    clickedNo(){
        this.clickStream.next(false);
    }
}
import { Component, ViewChild} from '@angular/core';
import {MyModal} from './myModal';
import {Subscription} from "rxjs";

@Component({
    ....
    directives: [MyModal]
})

export class AppComponent {
    @ViewChild(ConfirmModal) confirmModal: ConfirmModal;
    constructor(){...};

    public showModal(){
        this.myModal.openModal();
        this.subscription = this.myModal.observable.subscribe(x => {
            console.log('observable called ' + x)
// unsubscribe is necessary such that the observable doesn't keep racking up listeners
            this.subscription.unsubscribe();
        });
    }
}

观察的优雅之处在于,我们现在可以编写更少的代码来做同样的事情。

也可以在Angular2+世界中使用s:

导出类MyComponent{
私人主体:主体;
routerCanDeactivate():PromiseLike{
$('#model')。model('show');
返回此.subject.toPromise();
}
handleRespone(res:boolean){
本.主题.下一个(res);
}
}

我可能错了,因为我不知道typescript,但你不应该先初始化
这个。答应我吧
?更准确地说,你不应该返回一个承诺,并保留其
解析
&
拒绝
函数的引用,然后调用这些函数吗?@Amit你是对的,我更新了原始帖子。调用句柄响应的是什么?@iliachory这是一个在关闭模式时调用的函数。这是我做的一个角度2模态分量的输出。我还确认它被正确调用,并且得到了响应。这不是对你问题的回答,但你的承诺定义非常冗长。它可以是
private promise=new promise((解析,拒绝)=>resolve(false))因此,当我开始进行更多的挖掘时,我意识到我将其设置为始终为false,但似乎不清楚如何等待
handleResponse
函数运行并等待响应,然后再解决承诺。另外,我认为错误是由于没有正确初始化promise实例,我相信我已经修复了它。@pjlamb12请参见编辑。。。这就是你想要的吗?我确实需要一种方法使
routerCanDeactivate
方法等待根据
handleResult
方法解析为true或false,我只是不确定最好的方法。上面的
Deferred
类的答案几乎有效,但是当承诺被解析为虚假或被拒绝时出现了一个错误,因此它不起作用。感谢您的建议!这真的很接近工作。由于某种原因,延迟。拒绝错误,如果你用false解决,它也会有点反常,所以我必须弄清楚
var promise = handleResult() //returns an observable
                .map(resultOfHandleResult => doSomethingWith(resultOfHandleResult))
export class MyComponent implements CanDeactivate {

  routerCanDeactivate(): Promise<boolean> {
    let $modal = $('#modal').modal();
    return new Promise<boolean>((resolve, reject) => {
      $modal.on("hidden.bs.modal", result => {
        resolve(result.ok);
      });
      $modal.modal("show");
    });
  }

}
class Deferred<T> {

  promise: Promise<T>;
  resolve: (value?: T | PromiseLike<T>) => void;
  reject:  (reason?: any) => void;

  constructor() {
    this.promise = new Promise<T>((resolve, reject) => {
      this.resolve = resolve;
      this.reject  = reject;
    });
  }
}

export class MyComponent implements CanDeactivate {

    private deferred = new Deferred<boolean>();

    routerCanDeactivate(): Promise<boolean> {
        $("#modal").modal("show");
        return this.deferred.promise;
    }

    handleRespone(res: boolean): void {
        if (res) {
            this.deferred.resolve(res);
        } else {
            this.deferred.reject(res);
        }
    }
}
import {Component, Output, EventEmitter} from '@angular/core;
@Component({
    selector: 'myModal',
    template: `<div class="myModal" [hidden]="showModal">
          <!-- your modal HTML here... -->
          <button type="button" class="btn" (click)="clickedYes()">Yes</button>
          <button type="button" class="btn" (click)="clickedNo()">No</button>
        </div>
    `
})

export class MyModal{
    private hideModal: boolean = true;
    @Output() buttonResultEmitter = new EventEmitter();
    constructor(){}
    openModal(){
        this.hideModal = false;
    }
    closeModal(){
        this.hideModal = true;
    }
    clickedYes(){
        this.buttonResultEmitter.emit(true);
    }
    clickedNo(){
        this.buttonResultEmitter.emit(false);
    }
}
import {MyModal} from './myModal';
@Component({
    ....
    directives: [MyModal]
})
private myModal: MyModal;
userClick(): Promise<boolean> {
    var prom: new Promise<boolean>((resolve, reject) => {
        this.myModal.buttonResultEmitter.subscribe(
            (result) => {
                if (result == true){
                    resolve(true);
                } else {
                    reject(false);
                }
         });
     });
     return prom;
}
routerCanDeactivate(next: ComponentInstruction, prev: ComponentInstruction) {
    this.myModal.openModal();
    return this.userClick().catch( function(){return false;} );
}
import {Component, Output, ViewChild} from '@angular/core;
@Component({
    selector: 'myModal',
    template: `<div class="myModal" [hidden]="showModal">
          <!-- your modal HTML here... -->
          <button type="button" class="btn" (click)="clickedYes($event)">Yes</button>
          <button type="button" class="btn" (click)="clickedNo($event)">No</button>
        </div>
    `
})

export class MyModal{
    private hideModal: boolean = true;
    private clickStream = new Subject<boolean>();
    @Output() observable = this.clickStream.asObservable();

    constructor(){}
    openModal(){
        this.hideModal = false;
    }
    closeModal(){
        this.hideModal = true;
    }
    clickedYes(){
        this.clickStream.next(true);
    }
    clickedNo(){
        this.clickStream.next(false);
    }
}
import { Component, ViewChild} from '@angular/core';
import {MyModal} from './myModal';
import {Subscription} from "rxjs";

@Component({
    ....
    directives: [MyModal]
})

export class AppComponent {
    @ViewChild(ConfirmModal) confirmModal: ConfirmModal;
    constructor(){...};

    public showModal(){
        this.myModal.openModal();
        this.subscription = this.myModal.observable.subscribe(x => {
            console.log('observable called ' + x)
// unsubscribe is necessary such that the observable doesn't keep racking up listeners
            this.subscription.unsubscribe();
        });
    }
}
export class MyComponent {
  private subject: Subject<boolean>;

  routerCanDeactivate(): PromiseLike<boolean> {
    $('#modal').modal('show');
    return this.subject.toPromise();
  }

  handleRespone(res: boolean) {
    this.subject.next(res);
  }
}