如何通知父组件更改和刷新视图 [英] How to notify parent component of change and refresh view

查看:23
本文介绍了如何通知父组件更改和刷新视图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想从子组件通知父组件更新父组件中的视图.我正在使用 @Output 注释来做到这一点.

在父组件中实际调用了函数loadPosts()",但视图并未更新.有人知道为什么吗?

发生了什么:

  • place_component 包含一个list-post"指令,用于显示所有帖子.
  • place_component 包含一个模态,用于添加一个带有指令new-post"的新帖子
  • 当一个新帖子被保存时,一条消息通过@output 解析回模态中的new-post"指令:(doneIt)="loadPosts()"
  • loadPosts() 函数被执行,但list-post"指令不会重新加载.

父组件:

place_component.dart:

@Component(选择器:'我的地方',指令:[核心指令,形式指令,发布新组件,PostList组件,材质按钮组件,材质对话框组件,模态组件,MaterialTabPanel 组件,MaterialTabComponent],templateUrl: 'place_component.html',styleUrls: ['place_component.css'],提供者:[materialProviders])类 PlaceComponent 实现 OnActivate, OnInit {地方;最终的 PlaceService _placeService;最终位置_location;最终 ChangeDetectorRef cdRef;int_id;bool showBasicDialog = false;final tabLabels = const ['帖子','图片','待处理的邀请'];PlaceComponent(this._placeService, this._location, this.cdRef);@覆盖未来<void>onActivate(_, RouterState current) async {_id = path.getId(current.parameters);loadPosts();}@覆盖未来<void>ngOnInit() 异步 {打印(初始化执行");}未来<void>loadPosts() 异步 {if (_id != null) place = await (_placeService.get(_id));cdRef.detectChanges();print("加载的帖子$_id");}void goBack() =>_location.back();未来<void>保存()异步{等待 _placeService.update(place);回去();}}

place_component.html:

<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" raise>最新帖子</material-button>

<div class="col-2-3"><div class="module"><material-tab-panel class="tab-panel" [activeTabIndex]="0"><material-tab label="帖子"><div class="posts"><div class="post"><list-posts [place]="place"></list-posts>

</material-tab><material-tab label="图片">图片</material-tab><material-tab label="视频">视频</material-tab></material-tab-panel><div class="divider10"></div>

<modal [visible]="showBasicDialog"><material-dialog class="basic-dialog"><h1 header>新帖子</h1><div class="new-post"><new-post (doneIt)="loadPosts()" [place]="place"></new-post>

<div页脚><material-button autoFocus clear-size (trigger)="showBasicDialog = false" class="close-button">关闭</material-button>

</material-dialog></modal>

子组件

post_new_component.dart:

@Component(选择器:'新帖子',指令:[核心指令,形式指令,文件上传器,材料输入指令,MaterialButtonComponent],templateUrl: 'post_new_component.html',styleUrls: ['post_new_component.css'],提供者:[ClassProvider(PostService)])类 PostNewComponent {最终 PostService _postService;最终 _onDone = 新 StreamController.broadcast();字符串 postText;发帖;@输入()地方;@输出()流完成它 =>_onDone.stream;PostNewComponent(this._postService);未来<void>保存()异步{await _postService.create(postText,place.id).then(((_) => _onDone.add(1)));}}

post_new_component.html:

<div><材料输入floatingLabel多行行=2"maxRows="4"label="在此处添加新帖子...."[(ngModel)]="postText"类=后文本"></材料输入>

<div class="post-buttons"><file-uploader class="file-uploader"></file-uploader><div><material-button (trigger)="save()" raise class="send-button">Post</material-button></div>

<div class="clear-float"></div>

我现在还根据此示例尝试使用 EventBus:AngularDart:如何将事件从子组件传递到二级父组件

 PlaceComponent(this._placeService, this._location, this._postEvent, this.cdRef) {_postEvent.onEventStream.listen((int id) => loadPosts().then((_){cdRef.markForCheck();}));}

行为完全相同.执行了 loadPosts 函数,但未加载视图.

解决方案

我有以下设置:

为了解决我的问题,我必须不将事件发送到父组件,而是发送到另一个子组件.所以@Output 不会起作用.我只是将 EventBus 连接到另一个子组件.

所以父组件的html简而言之是这样的:

<预><代码>...<div><new-post [place]="place"></new-post></div><div><list-posts [place]="place"></list-posts></div>...

所以子组件 new-post 需要通知子组件 list-posts,一个新的帖子已经被添加,并且 list-posts 应该重新获取与一个地方相关的所有帖子.

post_event.dart(事件总线服务)

事件总线服务设置在 post_new_component 和 post_list_component 之间.

我正在将一个 int 传递给 Stream (int id),现在这并不重要,因为我只需要检查,是否触发了事件,您还可以解析字符串、对象或其他任何内容,如果您需要随事件发送数据.

@Injectable()类 PostEvent {最终 StreamController_onEventStream = new StreamController.broadcast();流onEventStream = null;静态最终 PostEvent _singleton = new PostEvent._internal();工厂 PostEvent() {返回_单例;}PostEvent._internal() {onEventStream = _onEventStream.stream;}onEvent(int id) {_onEventStream.add(id);}}

post_new_component.dart

添加帖子后,执行_postEvent.onEvent(1).如上所述,1"并不重要,因为我只想知道是否触发了事件.

@Component(选择器:'新帖子',指令:[核心指令,形式指令,文件上传器,材料输入指令,MaterialButtonComponent],templateUrl: 'post_new_component.html',styleUrls: ['post_new_component.css'],提供者:[ClassProvider(PostService), ClassProvider(PostEvent)])类 PostNewComponent {最终 PostService _postService;最终的 PostEvent _postEvent;字符串 postText;发帖;@输入()地方;PostNewComponent(this._postService, this._postEvent);//保存一个新帖子未来<void>保存()异步{//创建一个新的帖子,然后触发一个帖子事件来通知帖子列表组件更新自己.await _postService.create(postText,place.id).then(((_) => _postEvent.onEvent(1)));}}

post_list_component.dart

我在组件的构造函数中设置了事件监听器,它监听来自新组件后的事件更改.每次收到事件时,我都会通过 _getPosts() 函数获取所有帖子.

@Component(选择器:'列表帖子',指令:[coreDirectives,formDirectives],templateUrl: 'post_list_component.html',styleUrls: ['post_list_component.css'],提供者:[ClassProvider(PostService), ClassProvider(PostEvent)])类 PostListComponent 实现 OnInit {最终 PostService _postService;最终的 PostEvent _postEvent;列表<帖子>职位;@输入()地方;PostListComponent(this._postService, this._postEvent) {//监听 postEvents,如果收到重新获取帖子_postEvent.onEventStream.listen((int id) => _getPosts());}//页面第一次加载时获取所有帖子void ngOnInit() =>_getPosts();//获取与某个地点相关的所有帖子的函数未来<void>_getPosts() 异步 {帖子 = 等待 _postService.getPostsByPlace(place.id);}}

如果有人知道更好的方法,请以任何方式纠正我,因为我对框架还不太熟悉,并且很难理解这些概念.文档涵盖了很多内容,但是如果有人对框架完全陌生,比如我,我会遗漏一些信息.对英雄文档的扩展将不胜感激,它涵盖了更复杂的主题,例如子组件之间的通信,以及子组件与父组件之间的通信,但不确定是否在某处解释过,我只是错过了.

I want to notify a parent component from a child component to update a view in the parent component. I'm using the @Output annotation to do that.

In the parent component the function "loadPosts()" is actually invoked, but the view is not updated. Does anybody know why?

What happens:

Parent Component:

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>

Child Component

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>

I have now additionally also tried with an EventBus according to this example: AngularDart: How do you pass an event from a Child component to a second level parent

  PlaceComponent(this._placeService, this._location, this._postEvent, this.cdRef) {
    _postEvent.onEventStream.listen((int id) => loadPosts().then((_){cdRef.markForCheck();}));
  }

The behaviour is exactly the same. The loadPosts function is executed, but the view is not loading.

解决方案

I had following setup:

To solve my problem I had to send the event not to the Parent Component, but to the other child component. So @Output wouldn't have worked. I just hooked up the EventBus to the other child component.

So the html of the parent component in short looked like this:

...
<div><new-post [place]="place"></new-post></div>
<div><list-posts [place]="place"></list-posts></div>
...

So the child component new-post needs to notify the child component list-posts, that a new post has been added and list-posts should re-fetch all posts related to a place.

post_event.dart (Event Bus Service)

The Event Bus service is setup between the post_new_component and the post_list_component.

I'm passing an int to the Stream (int id), this is not important right now, as I only need to check, if an event has fired, you could also parse a string, an object or anything else, if you need to send data with the event.

@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

After the post has been added, _postEvent.onEvent(1) is executed. As explained above "1" is not important, as I only want to know, if an event was fired.

@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

I setup the event listener in the constructor of the component, that listens for event changes from the post-new component. Each time an event is received, I fetch all posts through the _getPosts() function.

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

If anybody knows a better way to do it, by any means correct me, as I'm not that familiar with the framework yet, and have a hard time to understand the concepts. The documentation covers much, but if somebody is totally new to the framework, like me, I'm missing some info. An extension to the Hero Documentation would be appreciated, that covers the more complex topics, such as communication between child components, and child to parent, but not sure, if this is explained somewhere, and I just missed it.

这篇关于如何通知父组件更改和刷新视图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
其他开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆