如何通知父组件更改和刷新视图

问题描述 投票:0回答:2

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

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

怎么了:

  • place_component包含一个“list-post”指令,它显示所有帖子。
  • place_component包含一个模态,用于添加一个带有指令“new-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: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();}));
  }

行为完全一样。执行loadPosts函数,但视图未加载。

dart angular-dart
2个回答
1
投票

有时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
}

0
投票

我有以下设置:

  • 父组件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>
...

因此,子组件新帖需要通知子组件列表帖子,添加了新帖子,列表帖子应该重新获取与某个地点相关的所有帖子。

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

添加帖子后,执行_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()函数获取所有帖子。

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

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

© www.soinside.com 2019 - 2024. All rights reserved.