Proper Use of Streams in AngularDart

Issue

I’m having difficulties using Streams to update my views.

Currently have a view that displays all of the posts, and a form to create posts. Once a post is submitted, a console.log() displays the newly created post, but the view does not render it. It is most likely the misuse of streams.

This is the current code

post_create_component.dart:

class PostCreateComponent {
  final PostListService postListService;

  PostCreateComponent(this.postListService);

  onAddPost(NgForm form) {
    Post post = Post(form.value["title"], form.value["content"]);
    this.postListService.addPost(post);
  }
}

post_list_component.dart

class PostListComponent implements OnInit, OnDestroy {
  final PostListService postListService;
  StreamSubscription<List<Post>> _postsSubscription;
  List<Post> postList = [];

  PostListComponent(this.postListService);

  @override
  ngOnInit() {
    this.postList = this.postListService.getPostList();
    this._postsSubscription = this
        .postListService
        .getPostUpdateListener
        .listen((List<Post> posts) => this.postList = posts);
  }

  ngOnDestroy() {
    _postsSubscription.cancel();
  }
}

post_list_service.dart

@Injectable()
class PostListService {
  List<Post> _postList = <Post>[Post("hello", "world")];
  final _postUpdated = new StreamController<List<Post>>();

  List<Post> getPostList() {
    return List.from(this._postList);
  }

  @Output()
  Stream<List<Post>> get getPostUpdateListener {
    return _postUpdated.stream;
  }

  addPost(Post post) {
    this._postList.add(post);
    this._postUpdated.add(List.from(this._postList));
    window.console.log(List.from(this._postList));
  }
}

and the console.log displays the following:

(2) [s…l.P…t.new, s…l.P…t.new]
0: src__post_model.Post.new {Symbol(Post.title): "hello", Symbol(Post.content): "world"}
1: src__post_model.Post.new {Symbol(Post.title): "world", Symbol(Post.content): "hello"}
length: 2
Symbol(dartx.first): (...)
Symbol(dartx.hashCode): (...)
Symbol(dartx.isEmpty): (...)
Symbol(dartx.isNotEmpty): (...)
Symbol(dartx.iterator): (...)
Symbol(dartx.last): (...)
Symbol(dartx.length): (...)
Symbol(dartx.reversed): (...)
Symbol(dartx.runtimeType): (...)
Symbol(dartx.single): (...)
__proto__: Array

Any advice is greatly appreciated.

UPDATE

So my post_list_component.html, post_create_component.html, app_component.html files are as follows:
post_list_component.html

<section *ngIf="postList.isNotEmpty">
    <material-expansionpanel *ngFor="let post of postList" name="{{post.title}}" [showSaveCancel]="false">
        {{post.content}}
    </material-expansionpanel>
</section>

<material-expansionpanel *ngIf="postList.isEmpty" name="No messages" [showSaveCancel]="false" disabled>
    No Messages :(
</material-expansionpanel>

post_create_component.html this component might need fixing but right now I want to focus on getting the implementation correctly first

<section class="data-entry">
  <h2>Post Comments</h2>
  <div class="mdc-card demo-size">
    <form #postForm="ngForm" (ngSubmit)="onAddPost(postForm)">
      <material-input
        autoFocus
        label="Title"
        floatingLabel
        class="wide"
        ngControl="title"
        required
        name="title"
        ngModel
        #title
        requiredErrorMsg="Enter a title"
      >
      </material-input>
      <material-input
        label="Content"
        floatingLabel
        class="wide"
        ngControl="content"
        required
        name="content"
        ngModel
        #content
        requiredErrorMsg="Enter a message"
      >
      </material-input>
      <div class="mdc-card__actions">
        <div class="mdc-card__action-buttons">
          <material-button
            raised
            type="submit"
            [disabled]="!postForm.form.valid"
            (trigger)="onAddPost(postForm)"
            >Save Post</material-button
          >
        </div>
      </div>
    </form>
  </div>
</section>

app_component.html

<app-header></app-header>
<div class="app-body">
    <app-post-create></app-post-create>
    <app-post-list></app-post-list>
</div>

UPDATE 2

app_component.dart

@Component(
  selector: 'my-app',
  styleUrls: ['app_component.css'],
  templateUrl: 'app_component.html',
  directives: [PostCreateComponent, PostListComponent, HeaderComponent],
  providers: [ClassProvider(PostListService), materialProviders],
)
class AppComponent {}

Solution

If someone comes across this in the future the problem was that the providers were set on both components which actually creates new instances of the service itself. So it wasn’t sharing the same service between the two components. The solution was to move the provider to higher up in the component tree.

Answered By – Ted Sander

Answer Checked By – David Goodson (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *