3

I am trying to create a separate component to deal with the presentation of a news feed. It works fine when I have everything within app.component.ts, but when I separate the code into its own component (news-feed.component.ts) it initially displays fine but when a menu button is clicked (e.g.: <button (click)="getNews('the-telegraph')">telegraph</button>) it is failing to recognise the function 'getNews' and the following error is generated:'EXCEPTION: Error in ./AppComponent class AppComponent - inline template:4:12 caused by: self.context.getNews is not a function'.

Please note - it is successfully running the getNews() function within the NewsFeedComponent when the site first loads.

Here is app.component.ts:

import {Component} from '@angular/core';
import {NewsService} from './news.service';
import {Observable} from 'rxjs/Rx';

import { NewsFeedComponent }  from './news-feed.component';

@Component({
  selector: 'news-app',
  template:`
  <h1>News Feed</h1>
  <nav>
    <button (click)="getNews('bbc-news')">bbc</button>
    <button (click)="getNews('the-telegraph')">telegraph</button>
    <button (click)="getNews('the-guardian-uk')">guardian</button>
    <button (click)="getNews('independent')">independent</button>
    <button (click)="getNews('financial-times')">financial times</button>
    <button (click)="getNews('the-economist')">the economist</button>
    <button (click)="getNews('sky-news')">sky news</button>
    <button (click)="getNews('the-new-york-times')">the new york times</button>
  </nav>
  <news-feed></news-feed>
  `,
  styleUrls: ['app/app.component.css']
})
export class AppComponent {

}

Here is news-feed.component.ts:

import {Component} from '@angular/core';
import {NewsService} from './news.service';
import {Observable} from 'rxjs/Rx'

@Component({
  selector: 'news-feed',
  template: `
    <ul>
      <li *ngFor="let article of news">
      hello2
        <a href="{{article.url}}" target="_bank"><h2>{{article.title}}</h2></a>
        <p>{{article.publishedAt}}</p>
        <img src="{{article.urlToImage}}" style="width: 200px;">
        <p>{{article.description}}</p>
      </li>
    </ul>
  `
})
export class NewsFeedComponent {
  // public news;

  constructor(private _newsService: NewsService) { }
  ngOnInit() {
    this.getNews('bbc-news');
  }

  getNews(source) {
    this._newsService.getNews(source).subscribe(
      // the first argument is a function which runs on success
      data => { 
        this.news = data['articles']
      },
       error => {
         //console.error("Error saving food!");
         return Observable.throw(error);
       }
    );
  }
}

Here is app.module.ts:

import { NgModule, CUSTOM_ELEMENTS_SCHEMA }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpModule }    from '@angular/http';
import {FormsModule} from '@angular/forms';
import {NewsService} from './news.service'

import { AppComponent }  from './app.component';

import { NewsFeedComponent }  from './news-feed.component';

@NgModule({
    imports: [BrowserModule,HttpModule,FormsModule],
    declarations: [
    	AppComponent,
    	NewsFeedComponent
    	 ],
    providers: [NewsService],
    schemas: [CUSTOM_ELEMENTS_SCHEMA],
    bootstrap: [AppComponent]
})
export class AppModule { }

Apologies for cutting and pasting in all this code. I have tried to get this working on Plunker and have failed due to being very stupid. Any help would be much appreciated.

3
  • I'm not sure but try adding this in your module: import { NewsFeedComponent } from './news-feed.component'; Commented Mar 28, 2017 at 12:31
  • You are calling getNews method inside app components template but your method is inside your child component. Commented Mar 28, 2017 at 12:33
  • The getNews is expected on your AppComponent class, because it is outside your news-feed Commented Mar 28, 2017 at 12:33

2 Answers 2

2

As commented at the question by @echonax and @devqon, you are calling getNews from AppComponent which is defined in your child component NewsFeedComponent. If this is the problem, try to move the function getNews to the AppComponent.


And, If you just want to call a child component's function, you can do it this way.

<nav>
  <button (click)="newsFeed.getNews('bbc-news')">bbc</button>
  // all the same
</nav>
<news-feed #newsFeed></news-feed>
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks. I used this and it now works. You have made a very stupid man very happy. You have no idea how long I have struggled with this!
@Stupid Glad that you make through it. And if this answered you, don't forget to mark it as an answer to let others easy to find.
1

You shouldn't be calling getNews function from your AppComponent html(as getNews isn't available in its context). Rather what you should be doing is, on click of button you should set some variable as like feedType = 'bbc-news' and pass it as input binding to your news-feed.

There it will receive type of feed dynamically using @Input binding and you can call the getNews method with selected appropriate feedType

<h1>News Feed</h1>
<nav>
    <button (click)="feedType = 'bbc-news'">bbc</button>
    <button (click)="feedType = 'the-telegraph'">telegraph</button>
    <button (click)="feedType = 'the-guardian-uk'">guardian</button>
    <button (click)="feedType = 'independent'">independent</button>
    <button (click)="feedType = 'financial-times'">financial times</button>
    <button (click)="feedType = 'the-economist'">the economist</button>
    <button (click)="feedType = 'sky-news'">sky news</button>
    <button (click)="feedType = 'the-new-york-times'">the new york times</button>
</nav>
<news-feed [feedType]="feedType"></news-feed>

Then add Input property binding in news-feed component

@Input() feedType;
constructor(private _newsService: NewsService) { }
//call getNews with selected `feedType`
ngOnInit() {
    this.getNews(this.feedType);
}

1 Comment

Thanks very much for this. Very clear answer. I will experiment with implementing this also.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.