如何通知父组件更改和刷新视图
How to notify parent component of change and refresh view
我想从子组件通知父组件更新父组件中的视图。我正在使用 @Output 注释来做到这一点。
在父组件中实际调用了函数"loadPosts()",但是视图没有更新。有人知道为什么吗?
会发生什么:
- place_component 包含一个 "list-post" 指令,显示所有 post。
- place_component 包含模态,添加新的 post 和指令 "new-post"
- 当一个新的 post 被保存时,一条消息通过 @output 被解析回模式中的 "new-post" 指令:(doneIt)="loadPosts()"
- 执行了 loadPosts() 函数,但 "list-post" 指令没有重新加载。
父组件:
place_component.dart:
@Component(
selector: 'my-place',
directives: [coreDirectives,
formDirectives,
PostNewComponent,
PostListComponent,
MaterialButtonComponent,
MaterialDialogComponent,
ModalComponent,
MaterialTabPanelComponent,
MaterialTabComponent],
templateUrl: 'place_component.html',
styleUrls: ['place_component.css'],
providers: [materialProviders]
)
class PlaceComponent implements OnActivate, OnInit {
Place place;
final PlaceService _placeService;
final Location _location;
final ChangeDetectorRef cdRef;
int _id;
bool showBasicDialog = false;
final tabLabels = const <String>[
'Posts',
'Pictures',
'Pending Invitations'
];
PlaceComponent(this._placeService, this._location, this.cdRef);
@override
Future<void> onActivate(_, RouterState current) async {
_id = paths.getId(current.parameters);
loadPosts();
}
@override
Future<void> ngOnInit() async {
print("init executed");
}
Future<void> loadPosts() async {
if (_id != null) place = await (_placeService.get(_id));
cdRef.detectChanges();
print("loaded posts $_id");
}
void goBack() => _location.back();
Future<void> save() async {
await _placeService.update(place);
goBack();
}
}
place_component.html:
<div *ngIf="place != null">
<h2>{{place.name}}</h2>
<div class="grid">
<div class="col-1-3">
<div class="module">
<material-button class="open-post-button" (trigger)="showBasicDialog = true" [disabled]="showBasicDialog" raised>
New Post
</material-button>
</div>
</div>
<div class="col-2-3">
<div class="module">
<material-tab-panel class="tab-panel" [activeTabIndex]="0">
<material-tab label="Posts">
<div class="posts">
<div class="post">
<list-posts [place]="place"></list-posts>
</div>
</div>
</material-tab>
<material-tab label="Pictures">
Pictures
</material-tab>
<material-tab label="Videos">
Videos
</material-tab>
</material-tab-panel>
<div class="divider10"></div>
</div>
</div>
</div>
</div>
<modal [visible]="showBasicDialog">
<material-dialog class="basic-dialog">
<h1 header>New Post</h1>
<div class="new-post">
<new-post (doneIt)="loadPosts()" [place]="place"></new-post>
</div>
<div footer>
<material-button autoFocus clear-size (trigger)="showBasicDialog = false" class="close-button">
Close
</material-button>
</div>
</material-dialog>
</modal>
子组件
post_new_component.dart:
@Component(
selector: 'new-post',
directives: [coreDirectives,
formDirectives,
FileUploader,
materialInputDirectives,
MaterialButtonComponent],
templateUrl: 'post_new_component.html',
styleUrls: ['post_new_component.css'],
providers: [ClassProvider(PostService)]
)
class PostNewComponent {
final PostService _postService;
final _onDone = new StreamController.broadcast();
String postText;
Post post;
@Input()
Place place;
@Output()
Stream get doneIt => _onDone.stream;
PostNewComponent(this._postService);
Future<void> save() async {
await _postService.create(postText,place.id).then(((_) => _onDone.add(1)));
}
}
post_new_component.html:
<div class="post-new-component">
<div>
<material-input floatingLabel
multiline
rows="2"
maxRows="4"
label="Add a new post here...."
[(ngModel)]="postText"
class="post-text">
</material-input>
</div>
<div class="post-buttons">
<file-uploader class="file-uploader"></file-uploader>
<div><material-button (trigger)="save()" raised class="send-button">Post</material-button></div>
</div>
<div class="clear-float"></div>
</div>
我现在还根据这个例子尝试了 EventBus:
PlaceComponent(this._placeService, this._location, this._postEvent, this.cdRef) {
_postEvent.onEventStream.listen((int id) => loadPosts().then((_){cdRef.markForCheck();}));
}
行为完全相同。执行了 loadPosts 函数,但未加载视图。
有时Angular在异步调用后不会触发变化检测,你需要使用ChangeDetectorRef
强制它
final ChangeDetectorRef cdRef;
PlaceComponent(this.cdRef);
Future<void> loadPosts() async {
if (_id != null) place = await (_placeService.get(_id));
////
cdRef.markForCheck();
// or
cdRef.detectChanges();
/// actually I don't know what is the best here
}
我有以下设置:
- 父组件 places_component
- 子组件post_new_component
- 子组件post_list_component
为了解决我的问题,我不得不将事件发送给另一个子组件而不是父组件。所以 @Output 不会起作用。我刚刚将 EventBus 连接到另一个子组件。
所以简而言之,父组件的 html 看起来像这样:
...
<div><new-post [place]="place"></new-post></div>
<div><list-posts [place]="place"></list-posts></div>
...
所以子组件new-post需要通知子组件list-posts,新增了一个post和list-post s 应该重新获取与某个地点相关的所有 posts。
post_event.dart(事件总线服务)
事件总线服务在 post_new_component 和 post_list_component 之间设置。
我正在将一个 int 传递给 Stream (int id),这现在并不重要,因为我只需要检查,如果一个事件已经触发,您还可以解析一个字符串、一个对象或任何东西否则,如果您需要随事件发送数据。
@Injectable()
class PostEvent {
final StreamController<int> _onEventStream = new StreamController.broadcast();
Stream<int> onEventStream = null;
static final PostEvent _singleton = new PostEvent._internal();
factory PostEvent() {
return _singleton;
}
PostEvent._internal() {
onEventStream = _onEventStream.stream;
}
onEvent(int id) {
_onEventStream.add(id);
}
}
post_new_component.dart
添加post后,执行_postEvent.onEvent(1)。如上所述,“1”并不重要,因为我只想知道是否触发了事件。
@Component(
selector: 'new-post',
directives: [coreDirectives,
formDirectives,
FileUploader,
materialInputDirectives,
MaterialButtonComponent],
templateUrl: 'post_new_component.html',
styleUrls: ['post_new_component.css'],
providers: [ClassProvider(PostService), ClassProvider(PostEvent)]
)
class PostNewComponent {
final PostService _postService;
final PostEvent _postEvent;
String postText;
Post post;
@Input()
Place place;
PostNewComponent(this._postService, this._postEvent);
// Save a new post
Future<void> save() async {
// Create a new post and then fire a post event to notify the post list component to update itself.
await _postService.create(postText,place.id).then(((_) => _postEvent.onEvent(1)));
}
}
post_list_component.dart
我在组件的构造函数中设置了事件侦听器,用于侦听来自 post-new 组件的事件更改。每次收到事件时,我都会通过 _getPosts() 函数获取所有 post。
@Component(
selector: 'list-posts',
directives: [coreDirectives, formDirectives],
templateUrl: 'post_list_component.html',
styleUrls: ['post_list_component.css'],
providers: [ClassProvider(PostService), ClassProvider(PostEvent)]
)
class PostListComponent implements OnInit {
final PostService _postService;
final PostEvent _postEvent;
List<Post> posts;
@Input()
Place place;
PostListComponent(this._postService, this._postEvent) {
// listen for postEvents, if received re-fetch posts
_postEvent.onEventStream.listen((int id) => _getPosts());
}
// Get all posts when page loads the first time
void ngOnInit() => _getPosts();
// Function to get all the posts related to a place
Future<void> _getPosts() async {
posts = await _postService.getPostsByPlace(place.id);
}
}
如果有人知道更好的方法,请务必纠正我,因为我还不太熟悉该框架,并且很难理解这些概念。该文档涵盖了很多内容,但如果有人像我一样对框架完全陌生,我会遗漏一些信息。英雄文档的扩展将不胜感激,它涵盖了更复杂的主题,例如子组件之间的通信以及子组件与父组件之间的通信,但不确定是否在某处对此进行了解释,我只是错过了它。
我想从子组件通知父组件更新父组件中的视图。我正在使用 @Output 注释来做到这一点。
在父组件中实际调用了函数"loadPosts()",但是视图没有更新。有人知道为什么吗?
会发生什么:
- place_component 包含一个 "list-post" 指令,显示所有 post。
- place_component 包含模态,添加新的 post 和指令 "new-post"
- 当一个新的 post 被保存时,一条消息通过 @output 被解析回模式中的 "new-post" 指令:(doneIt)="loadPosts()"
- 执行了 loadPosts() 函数,但 "list-post" 指令没有重新加载。
父组件:
place_component.dart:
@Component(
selector: 'my-place',
directives: [coreDirectives,
formDirectives,
PostNewComponent,
PostListComponent,
MaterialButtonComponent,
MaterialDialogComponent,
ModalComponent,
MaterialTabPanelComponent,
MaterialTabComponent],
templateUrl: 'place_component.html',
styleUrls: ['place_component.css'],
providers: [materialProviders]
)
class PlaceComponent implements OnActivate, OnInit {
Place place;
final PlaceService _placeService;
final Location _location;
final ChangeDetectorRef cdRef;
int _id;
bool showBasicDialog = false;
final tabLabels = const <String>[
'Posts',
'Pictures',
'Pending Invitations'
];
PlaceComponent(this._placeService, this._location, this.cdRef);
@override
Future<void> onActivate(_, RouterState current) async {
_id = paths.getId(current.parameters);
loadPosts();
}
@override
Future<void> ngOnInit() async {
print("init executed");
}
Future<void> loadPosts() async {
if (_id != null) place = await (_placeService.get(_id));
cdRef.detectChanges();
print("loaded posts $_id");
}
void goBack() => _location.back();
Future<void> save() async {
await _placeService.update(place);
goBack();
}
}
place_component.html:
<div *ngIf="place != null">
<h2>{{place.name}}</h2>
<div class="grid">
<div class="col-1-3">
<div class="module">
<material-button class="open-post-button" (trigger)="showBasicDialog = true" [disabled]="showBasicDialog" raised>
New Post
</material-button>
</div>
</div>
<div class="col-2-3">
<div class="module">
<material-tab-panel class="tab-panel" [activeTabIndex]="0">
<material-tab label="Posts">
<div class="posts">
<div class="post">
<list-posts [place]="place"></list-posts>
</div>
</div>
</material-tab>
<material-tab label="Pictures">
Pictures
</material-tab>
<material-tab label="Videos">
Videos
</material-tab>
</material-tab-panel>
<div class="divider10"></div>
</div>
</div>
</div>
</div>
<modal [visible]="showBasicDialog">
<material-dialog class="basic-dialog">
<h1 header>New Post</h1>
<div class="new-post">
<new-post (doneIt)="loadPosts()" [place]="place"></new-post>
</div>
<div footer>
<material-button autoFocus clear-size (trigger)="showBasicDialog = false" class="close-button">
Close
</material-button>
</div>
</material-dialog>
</modal>
子组件
post_new_component.dart:
@Component(
selector: 'new-post',
directives: [coreDirectives,
formDirectives,
FileUploader,
materialInputDirectives,
MaterialButtonComponent],
templateUrl: 'post_new_component.html',
styleUrls: ['post_new_component.css'],
providers: [ClassProvider(PostService)]
)
class PostNewComponent {
final PostService _postService;
final _onDone = new StreamController.broadcast();
String postText;
Post post;
@Input()
Place place;
@Output()
Stream get doneIt => _onDone.stream;
PostNewComponent(this._postService);
Future<void> save() async {
await _postService.create(postText,place.id).then(((_) => _onDone.add(1)));
}
}
post_new_component.html:
<div class="post-new-component">
<div>
<material-input floatingLabel
multiline
rows="2"
maxRows="4"
label="Add a new post here...."
[(ngModel)]="postText"
class="post-text">
</material-input>
</div>
<div class="post-buttons">
<file-uploader class="file-uploader"></file-uploader>
<div><material-button (trigger)="save()" raised class="send-button">Post</material-button></div>
</div>
<div class="clear-float"></div>
</div>
我现在还根据这个例子尝试了 EventBus:
PlaceComponent(this._placeService, this._location, this._postEvent, this.cdRef) {
_postEvent.onEventStream.listen((int id) => loadPosts().then((_){cdRef.markForCheck();}));
}
行为完全相同。执行了 loadPosts 函数,但未加载视图。
有时Angular在异步调用后不会触发变化检测,你需要使用ChangeDetectorRef
final ChangeDetectorRef cdRef;
PlaceComponent(this.cdRef);
Future<void> loadPosts() async {
if (_id != null) place = await (_placeService.get(_id));
////
cdRef.markForCheck();
// or
cdRef.detectChanges();
/// actually I don't know what is the best here
}
我有以下设置:
- 父组件 places_component
- 子组件post_new_component
- 子组件post_list_component
为了解决我的问题,我不得不将事件发送给另一个子组件而不是父组件。所以 @Output 不会起作用。我刚刚将 EventBus 连接到另一个子组件。
所以简而言之,父组件的 html 看起来像这样:
...
<div><new-post [place]="place"></new-post></div>
<div><list-posts [place]="place"></list-posts></div>
...
所以子组件new-post需要通知子组件list-posts,新增了一个post和list-post s 应该重新获取与某个地点相关的所有 posts。
post_event.dart(事件总线服务)
事件总线服务在 post_new_component 和 post_list_component 之间设置。
我正在将一个 int 传递给 Stream (int id),这现在并不重要,因为我只需要检查,如果一个事件已经触发,您还可以解析一个字符串、一个对象或任何东西否则,如果您需要随事件发送数据。
@Injectable()
class PostEvent {
final StreamController<int> _onEventStream = new StreamController.broadcast();
Stream<int> onEventStream = null;
static final PostEvent _singleton = new PostEvent._internal();
factory PostEvent() {
return _singleton;
}
PostEvent._internal() {
onEventStream = _onEventStream.stream;
}
onEvent(int id) {
_onEventStream.add(id);
}
}
post_new_component.dart
添加post后,执行_postEvent.onEvent(1)。如上所述,“1”并不重要,因为我只想知道是否触发了事件。
@Component(
selector: 'new-post',
directives: [coreDirectives,
formDirectives,
FileUploader,
materialInputDirectives,
MaterialButtonComponent],
templateUrl: 'post_new_component.html',
styleUrls: ['post_new_component.css'],
providers: [ClassProvider(PostService), ClassProvider(PostEvent)]
)
class PostNewComponent {
final PostService _postService;
final PostEvent _postEvent;
String postText;
Post post;
@Input()
Place place;
PostNewComponent(this._postService, this._postEvent);
// Save a new post
Future<void> save() async {
// Create a new post and then fire a post event to notify the post list component to update itself.
await _postService.create(postText,place.id).then(((_) => _postEvent.onEvent(1)));
}
}
post_list_component.dart
我在组件的构造函数中设置了事件侦听器,用于侦听来自 post-new 组件的事件更改。每次收到事件时,我都会通过 _getPosts() 函数获取所有 post。
@Component(
selector: 'list-posts',
directives: [coreDirectives, formDirectives],
templateUrl: 'post_list_component.html',
styleUrls: ['post_list_component.css'],
providers: [ClassProvider(PostService), ClassProvider(PostEvent)]
)
class PostListComponent implements OnInit {
final PostService _postService;
final PostEvent _postEvent;
List<Post> posts;
@Input()
Place place;
PostListComponent(this._postService, this._postEvent) {
// listen for postEvents, if received re-fetch posts
_postEvent.onEventStream.listen((int id) => _getPosts());
}
// Get all posts when page loads the first time
void ngOnInit() => _getPosts();
// Function to get all the posts related to a place
Future<void> _getPosts() async {
posts = await _postService.getPostsByPlace(place.id);
}
}
如果有人知道更好的方法,请务必纠正我,因为我还不太熟悉该框架,并且很难理解这些概念。该文档涵盖了很多内容,但如果有人像我一样对框架完全陌生,我会遗漏一些信息。英雄文档的扩展将不胜感激,它涵盖了更复杂的主题,例如子组件之间的通信以及子组件与父组件之间的通信,但不确定是否在某处对此进行了解释,我只是错过了它。