Link to home
Start Free TrialLog in
Avatar of chalie001
chalie001

asked on

app having error when starting

hi am having this error in my angular application
Uncaught Error: Template parse errors:
Can't bind to 'posts' since it isn't a known property of 'app-post-list'.
1. If 'app-post-list' is an Angular component and it has 'posts' input, then verify that it is part of this module.
2. If 'app-post-list' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.
3. To allow any property add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component. ("n>
<app-post-create (postCreated)="onPostAdded($event)"></app-post-create>
<app-post-list [ERROR ->][posts]="storedPosts"></app-post-list>
</main>

"): ng:///AppModule/AppComponent.html@4:19
at syntaxError (compiler.js:2175)
at TemplateParser.parse (compiler.js:11292)
at JitCompiler._parseTemplate (compiler.js:25837)
at JitCompiler._compileTemplate (compiler.js:25825)
at compiler.js:25769
at Set.forEach (<anonymous>)
at JitCompiler._compileComponents (compiler.js:25769)
at compiler.js:25682
at Object.then (compiler.js:2166)
at JitCompiler._compileModuleAndComponents (compiler.js:25681)
syntaxError @ compiler.js:2175
parse @ compiler.js:11292
_parseTemplate @ compiler.js:25837
_compileTemplate @ compiler.js:25825
(anonymous) @ compiler.js:25769
_compileComponents @ compiler.js:25769
(anonymous) @ compiler.js:25682
then @ compiler.js:2166
_compileModuleAndComponents @ compiler.js:25681
compileModuleAsync @ compiler.js:25643
compileModuleAsync @ platform-browser-dynamic.js:216
compileNgModuleFactory__PRE_R3__ @ core.js:33313
bootstrapModule @ core.js:33618
./src/main.ts @ main.ts:12
__webpack_require__ @ bootstrap:79
0 @ main.ts:13
__webpack_require__ @ bootstrap:79
checkDeferredModules @ bootstrap:45
webpackJsonpCallback @ bootstrap:32
(anonymous) @ main.js:1
2localhost/:1 Unchecked runtime.lastError: The message port closed before a response was received.
client:52 [WDS] Live Reloading enabled.
import { Component, OnInit, OnDestroy } from "@angular/core";
import { Subscription } from 'rxjs';
 
import { Post } from "../../post.model";
import { PostsService } from "../../posts.service";
 
@Component({
  selector: "app-post-list",
  templateUrl: "./post-list.component.html",
  styleUrls: ["./post-list.component.css"]
})
export class PostListComponent implements OnInit, OnDestroy {
  // posts = [
  //   { title: "First Post", content: "This is the first post's content" },
  //   { title: "Second Post", content: "This is the second post's content" },
  //   { title: "Third Post", content: "This is the third post's content" }
  // ];
  posts: Post[] = [];
  private postsSub: Subscription;
 
  constructor(public postsService: PostsService) {}
 
  ngOnInit() {
    this.posts = this.postsService.getPosts();
    this.postsSub = this.postsService.getPostUpdateListener()
      .subscribe((posts: Post[]) => {
        this.posts = posts;
      });
  }
 
  ngOnDestroy() {
    this.postsSub.unsubscribe();
  }
}
 ===
import { BrowserModule } from "@angular/platform-browser";
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
import { NgModule } from "@angular/core";
import { FormsModule } from "@angular/forms";
import {
  MatInputModule,
  MatCardModule,
  MatButtonModule,
  MatToolbarModule,
  MatExpansionModule
} from "@angular/material";
 
import { AppComponent } from "./app.component";
import {PostCreateComponent} from './posts/posts_create/post-create-components';
import { HeaderComponent } from "./header/header.component";
import { PostListComponent } from './posts/posts_create/post-list/post-list.component';
 
@NgModule({
  declarations: [
    AppComponent,
    PostCreateComponent,
    HeaderComponent,
    PostListComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    BrowserAnimationsModule,
    MatInputModule,
    MatCardModule,
    MatButtonModule,
    MatToolbarModule,
    MatExpansionModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule {}

User generated image
User generated image
Avatar of Julian Hansen
Julian Hansen
Flag of South Africa image

This sounds like you did this
<app-post-list [post]="post">...</app-post-list>

Open in new window

Without declaring post as an @Input on the app-post-component

import { Component, OnInit, OnDestroy, Input } from "@angular/core";
import { Subscription } from 'rxjs';
 
import { Post } from "../../post.model";
import { PostsService } from "../../posts.service";
@Component({
  selector: "app-post-list",
  templateUrl: "./post-list.component.html",
  styleUrls: ["./post-list.component.css"]
})
export class PostListComponent implements OnInit, OnDestroy {
@Input() post; // <==== MISSING

Open in new window


Show us how you are using <app-post-list>
Avatar of chalie001
chalie001

ASKER

this my app post list
import { Component, OnInit, OnDestroy } from "@angular/core";
import { Subscription } from 'rxjs';

import { Post } from "../../post.model";
import { PostsService } from "../../posts.service";

@Component({
  selector: "app-post-list",
  templateUrl: "./post-list.component.html",
  styleUrls: ["./post-list.component.css"]
})
export class PostListComponent implements OnInit, OnDestroy {
  // posts = [
  //   { title: "First Post", content: "This is the first post's content" },
  //   { title: "Second Post", content: "This is the second post's content" },
  //   { title: "Third Post", content: "This is the third post's content" }
  // ];
  posts: Post[] = [];
  private postsSub: Subscription;

  constructor(public postsService: PostsService) {}

  ngOnInit() {
    this.posts = this.postsService.getPosts();
    this.postsSub = this.postsService.getPostUpdateListener()
      .subscribe((posts: Post[]) => {
        this.posts = posts;
      });
  }

  ngOnDestroy() {
    this.postsSub.unsubscribe();
  }
}

Open in new window


my post create is
import { Component } from "@angular/core";
import { NgForm } from "@angular/forms";

import { PostsService } from "../posts.service";

@Component({
  selector: "app-post-create",
  templateUrl: "./posts-create-component.html",
  styleUrls: ["./post-create-components.css"]
})
export class PostCreateComponent {
  enteredTitle = "";
  enteredContent = "";

  constructor(public postsService: PostsService) {}

  onAddPost(form: NgForm) {
    if (form.invalid) {
      return;
    }
    this.postsService.addPost(form.value.title, form.value.content);
    form.resetForm();
  }
}

Open in new window

That is not what I asked

I wanted to know where you are using the <app-post-list> element.

You are showing me .ts code - you need to be showing me your template (.html code).

Somewhere you have an <app-post-list> in a template - that is what I need to see.
hi you mean this
<mat-accordion multi="true" *ngIf="posts.length > 0">
    <mat-expansion-panel *ngFor="let post of posts">
        <mat-expansion-panel-header>
        {{post.title}}
        </mat-expansion-panel-header>
       <p>{{post.content}}</p>
    </mat-expansion-panel>
</mat-accordion>
<p class="info-text mat-body-1" *ngIf="posts.length <= 0">no post added yet</p>


====
<mat-card>
    <form (submit)="onAddPost(postForm)" #postForm="ngForm">
      <mat-form-field>
        <input
          matInput
          type="text"
          name="title"
          ngModel
          required
          minlength="3"
          placeholder="Post Title"
          #title="ngModel">
        <mat-error *ngIf="title.invalid">Please enter a post title.</mat-error>
      </mat-form-field>
      <mat-form-field>
        <textarea
          matInput
          rows="4"
          name="content"
          ngModel
          required
          placeholder="Post Content"
          #content="ngModel"></textarea>
        <mat-error *ngIf="content.invalid">Please enter a post title.</mat-error>
      </mat-form-field>
      <button
        mat-raised-button
        color="accent"
        type="submit">Save Post</button>
    </form>
  </mat-card>
  

Open in new window

No I don't.

Let's start with this file AppComponent.html
And your Route definition.
this html
<!--The content below is only a placeholder and can be replaced.-->
<app-header></app-header>
<main>
    <app-post-create (postCreated)="onPostAdded($event)"></app-post-create>
    <app-post-list [posts]="storedPosts"></app-post-list>
</main>


my service is
import {Injectable } from '@angular/core';
import { Subject } from 'rxjs';

import {Post} from './post.model';

@Injectable({providedIn: 'root'})
export class PostsService{
    private posts: Post[] = [];
    private postsUpdated = new Subject<Post[]>();

    getPosts(){
        return [...this.posts];
    }

    getPostUpdateListener(){
        return this.postsUpdated.asObservable();
    }

    addPost(title: string, content: string){
        const post: Post = {title: title,content: content};
        this.posts.push(post);
        this.postsUpdated.next([...this.posts]);

    }
}
ASKER CERTIFIED SOLUTION
Avatar of Julian Hansen
Julian Hansen
Flag of South Africa image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
you mean this component
import { Component, OnInit, OnDestroy } from "@angular/core";
import { Subscription } from 'rxjs';

import { Post } from "../../post.model";
import { PostsService } from "../../posts.service";

@Component({
  selector: "app-post-list",
  templateUrl: "./post-list.component.html",
  styleUrls: ["./post-list.component.css"]
})
export class PostListComponent implements OnInit, OnDestroy {
  // posts = [
  //   { title: "First Post", content: "This is the first post's content" },
  //   { title: "Second Post", content: "This is the second post's content" },
  //   { title: "Third Post", content: "This is the third post's content" }
  // ];
  posts: Post[] = [];
  private postsSub: Subscription;

  constructor(public postsService: PostsService) {}

  ngOnInit() {
    this.posts = this.postsService.getPosts();
    this.postsSub = this.postsService.getPostUpdateListener()
      .subscribe((posts: Post[]) => {
        this.posts = posts;
      });
  }

  ngOnDestroy() {
    this.postsSub.unsubscribe();
  }
}

Open in new window

where must i add @Input: posts
where must i add @Input: posts
Are you familiar with inter-component communication techniques?

https://angular.io/api/core/Input

If not then I recommend you get up to speed on that.

If we want to pass data to a component from a parent component we can either use a component attribute (@Input) or a service.

There are pros and cons depending on the use case both have their place.

If you have a parent component that has - say a list of posts and you want to render that list out but don't want to include the template for each post in the parent template you can create a child template and pass the post object to the child using a bound attribute.

So in the parent you have
<app-post-list [posts]="storedPosts"></app-post-list>

Open in new window

This is telling Angular to create a component with the selector app-post-list and pass it the data stored in the variable storedPosts.

So far you have this - but on the component side we need to tell Angular to expect this incoming data

To do that we use the @Input decorator

This goes in the root of your class definition and specifies the incoming bound attributes
So in your code you would need to change a few things

1. You need to import the Import component to your component
2. You need to declare a posts input variable
3. You need to remove the posts variable you have defined as that is not required

// ***********==> Import Input
import { Component, OnInit, OnDestroy, Input } from "@angular/core";
import { Subscription } from 'rxjs';

import { Post } from "../../post.model";
import { PostsService } from "../../posts.service";

@Component({
  selector: "app-post-list",
  templateUrl: "./post-list.component.html",
  styleUrls: ["./post-list.component.css"]
})
export class PostListComponent implements OnInit, OnDestroy {
// ***********==>  Add an Input for your bound attribute
@Input() posts;
  // posts = [
  //   { title: "First Post", content: "This is the first post's content" },
  //   { title: "Second Post", content: "This is the second post's content" },
  //   { title: "Third Post", content: "This is the third post's content" }
  // ];

// ***********==> Remove the posts variable you had before
//  posts: Post[] = [];
  private postsSub: Subscription;

  constructor(public postsService: PostsService) {}

  ngOnInit() {
    // ***********==> If you are passing posts INTO your component - you don't need to get them
    // ***********==> from the service.
    /*
    this.posts = this.postsService.getPosts();
    this.postsSub = this.postsService.getPostUpdateListener()
      .subscribe((posts: Post[]) => {
        this.posts = posts;
      });
    */
  }

 // You don't need onDestroy anymore as you are getting posts from the parent and not subscribing to anything in this component
  ngOnDestroy() {
//    this.postsSub.unsubscribe();
  }
}

Open in new window

am geting this error
User generated image
import { Component, OnInit, OnDestroy } from "@angular/core";
import { Subscription } from 'rxjs';

import { Post } from "../../post.model";
import { PostsService } from "../../posts.service";

@Component({
  selector: "app-post-list",
  templateUrl: "./post-list.component.html",
  styleUrls: ["./post-list.component.css"]
})
export class PostListComponent implements OnInit, OnDestroy {
  @Input() posts;
  // posts = [
  //   { title: "First Post", content: "This is the first post's content" },
  //   { title: "Second Post", content: "This is the second post's content" },
  //   { title: "Third Post", content: "This is the third post's content" }
  // ];
 // posts: Post[] = [];
  private postsSub: Subscription;

  constructor(public postsService: PostsService) {}

  ngOnInit() {
    /*
    this.posts = this.postsService.getPosts();
    this.postsSub = this.postsService.getPostUpdateListener()
      .subscribe((posts: Post[]) => {
        this.posts = posts;
      });
      */
  }

 // ngOnDestroy() {
   // this.postsSub.unsubscribe();
 // }
}

Open in new window

1. You have commented out ngDestroy but your class still says it implements this interface you have to remove the onDestroy from the implementation list

export class PostListComponent implements OnInit

Open in new window



2. You have not imported Input
am geting this error now
User generated image
From my last post
You have not imported Input
From my post before that and the one before that (https://www.experts-exchange.com/questions/29171382/app-having-error-when-starting.html?anchorAnswerId=43022036#a43022036)
import { Component, OnInit, OnDestroy, Input } from "@angular/core";

Open in new window