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);
}
}