我只是想知道是否可以在服务中使用Subject来通知组件状态已更改。让我举个例子吧。 例如。我有一个组件adresses-list.component.ts 这只是地址列表。单击确定的地址后,其完整信息将在列表的右侧或模式中显示。它 将被称为“ edit-address.component.ts” 因此,用户可以在该组件中编辑地址并保存更改。 我当然知道,将会有一个后端要求对其进行更新。 但是,问题是我的adresses-list.component.ts不会知道此更改,因为它已订阅可观察的地址,而不是更改。 所以我的问题是: 这是正常的做法吗 在我的service.ts中:
addressesUpdated = new Subject();
editAddressById(id) {
// send info to DB
return this.http.patch().map(_ => {this.addressesUpdated.next())
}
在我的addresses-list.component.ts
中service.addressesUpdated.switchMap( _ => service.getAddresses())
.subscribe(...save data here)
在我看来,有一个更好的解决方案和一个更愚蠢的解决方案,但我不知道如何做得更好。
答案 0 :(得分:2)
嗯,您当然可以做到。 Angular的EventEmitter
也是(https://angular.io/api/core/EventEmitter)下的主题。但是,如果您觉得需要更频繁地执行此操作,我建议您查看一种状态管理解决方案,例如ngrx store:https://github.com/ngrx/platform
答案 1 :(得分:0)
使用Angular的方法是使用@Output EventEmitter进行双向模型绑定。您用于编辑地址的子组件是否从选择器标签上的attr绑定获取其视图模型?如果是这样,那么您就到了一半。这就是我要实现的目标的方式。
export class AddressModel {
public Street1: string;
public Street2: string;
public City: string;
public StateProvince: string;
public PostalCode: string;
public CountryCode: string;
}
export class ApiResponse {
public Success: boolean;
public ErrorMessage: string;
}
@Component({
selector: 'addressListComponent',
templateUrl: './addressList.html';
})
export class AddressListComponent implements OnInit {
addressList: AddressModel[];
addressSelected: boolean[];
constructor(private api: AddressApi){}
ngOnInit(): void {
this.AddressList = new AddressList();
this.api.GetAddressList()
.then(response: AddressModel[] => {
this.addressList = response.slice(0);
this.addressList.forEach(addr => {
this.addressSelected.push(false);
});
});
}
}
<div class="card" *NgFor="let address of addressList; let i = "index"; [attr.data-index]="i" (click)="addressSelected[i]=!addressSelected[i]">
<div class="card-body">
<label>{{address.Street1}}</label>
<label>{{address.Street2}}</label>
<label>{{address.City}}</label>
<label>{{address.StateProvince}}</label>
<label>{{address.PostalCode}}</label>
<label>{{address.Country}}</label>
</div>
<editAddressComponent *ngIf="addressSelected[i]" [(addressModel)]="addressList[i]"></editAddressComponent>
</div>
@Component({
selector: 'editAddressComponent',
templateUrl: './editAddress.html'
})
export class EditAddressComponent {
@Input() addressModel: AddressModel;
@Output() addressModelChanged: EventEmitter<AddressModel> = new EventEmitter<AddressModel>();
constructor(private api: AddressApi) { }
saveChanges(): void {
this.api.saveAddressChanges(this.addressModel)
.then(response: ApiResponse => {
if (response.Success === true) {
this.addressModelChanged.emit(this.addressModel);
} else {
alert(response.ErrorMessage);
}
});
}
}
<div class="card">
<div class="card-body">
<input [(ngModel)]="addressModel.Street1"/>
<input [(ngModel)]="addressModel.Street2"/>
<input [(ngModel)]="addressModel.City"/>
<input [(ngModel)]="addressModel.StateProvince"/>
<input [(ngModel)]="addressModel.PostalCode"/>
<input [(ngModel)]="addressModel.Country"/>
<button (click)="saveChanges()"></button>
</div>
</div>
请注意父视图上的[()]
语法。这就是魔术发生的地方。当您在组件上具有自定义@Input attr并通过[]
向其传递值时,这是一种绑定方式。
如果像我对[()]
所做的那样将自定义属性包装在addressModel
中,则它是
<editAddressComponent [addressModel]="addressList[i]" (addressModelChanged)="addressList[i] = $event;"></editAddressComponent>
这意味着,在后台Angular正在设置您的子组件以支持事件发射器,这就是()
模板语法所表示的。
参加
<button (click)="doStuff();"></button>
例如。
()
表示一个eventEmitter,您要为其分配发射事件时要执行的操作,在这种情况下,请执行doStuff()方法。
因此使用
<editAddressComponent [(addressModel)]="addressList[i]"></editAddressComponent>
您正在设置子组件以支持EventEmitter,现在只需要制作一个即可。
这就是@Output
所做的。它正在子组件中注册一个EventEmitter
类型的可用变量,该变量专门发出一个AddressModel
对象。
现在,当用户保存更改时,如果更改成功保存,则使用EventEmitter发出一个事件,该事件将更改后的addressModel作为要捕获的对象。
然后在父组件中捕获对象,并将其分配给索引i处的addressList。这将使您的父组件视图与子组件所做的更改保持同步。