0

I'm working on project which has on the left side of the screen categories, and by pressing on each categoriy in the middle of screen should be displayed articles/products which belong to selected category.

I fectched categories on the left very simple like this:

category: Category[];

ngOnInit() {
    this.category= this._activatedRoute.snapshot.data['category'];
}

And in my template .html file I just displayed them and attached event on each:

<div class="tab-content categories-tab-content">
  <div class="tab-pane" id="food">
    <ul>
        <li *ngFor="let c of category;">
          <button type="button" data-toggle="" data-target="" class="btn categories-btn" (click)="getArticlesByCategory(c.id)">
            {{subgroup.title | uppercase}}
          </button>
        </li>
    </ul>
  </div>
</div>

As you can see getArticlesByCategory method is located there like this: (click)="getArticlesByCategory(c.id) So when users clicks on each categorie this method is called:

getArticlesByCategory(selectedCategoryId: string) {
this._articleService.getArticlesByCategory(selectedCategoryId).subscribe(articles => {
  this.category= category;
});

And articles are fetched, I've tried console.log and they are there..

Here is my second component whicih should display that articles:

import { Component, OnInit, Input } from '@angular/core';
import { Article } from '../../models/article';

@Component({
  selector: 'app-main-article',
  templateUrl: './article.component.html',
  styleUrls: ['./article.component.css']
})
export class ArticleComponent implements OnInit {

// Here I've created `@Input` because I think it needs to receive this list of articles

 @Input() category: Article[];
 constructor() { }

  ngOnInit() {
  }
}

This is template file of my component which should receive and display articles:

<div *ngFor="let product of products ;" class="article-holder">
  <div id="article1" class="article">
     <p class="article-price">product.price</p>
     <p class="article-title">product.title</p>
   </div>
</div>

As you can see in my template file code is ready to loop that list, but I don't know how to get it, could anyone please explain me how to do this?

Thanks Cheers

Roxy'Pro
  • 4,216
  • 9
  • 40
  • 102
  • better use a shared service in your both components.And @Input decorator will only work if you are passing data from parent to child. – lpd Jun 26 '18 at 11:57
  • There's a working plunker demonstrating how this can be done in this answer to a similar question: https://stackoverflow.com/a/48368909/7840778 – Steve Land Jun 26 '18 at 12:01
  • @Steveland83 can you please check for my edit. I came up to the solution but one part executes twice for each click..(check for link you provide me to see full code) And is this in general and in this case better solution than using @ Input @ Output? And could you explain me why? Thanks a lot – Roxy'Pro Jun 26 '18 at 13:43
  • @Roxy'Pro difficult to say without seeing the full code, but there are a few things to check: 1. Make sure you are unsubscribing from your observables on page navigation etc. 2. Are there multiple components that have this logic (or is one component being repeated)? - if so then you need to distinguish between each component and send your calls with arguments. – Steve Land Jun 26 '18 at 13:59
  • @Steveland83 How can I check this : " Make sure you are unsubscribing from your observables on page navigation etc." Where to look ? I don't understand this very well yet :/ – Roxy'Pro Jun 26 '18 at 14:01
  • @Steveland83 And what is more interesting.. after clicking for a while instead of repeating this for a two times : console.log("THIS CONSOLE LOG EXECUTES TWICE! FOR EACH CLICK!"); , now it started to repeat it for 3 times.. somehow it increased... how come? this isn't so secured :S – Roxy'Pro Jun 26 '18 at 14:18
  • This article covers why you need to unsubscribe and how to handle it: http://brianflove.com/2016/12/11/anguar-2-unsubscribe-observables/ The best way to learn about observables is to create a simple page where you can mess around with them - always remember that a subscription is for life, not just once off, unless you specify a limit :) – Steve Land Jun 26 '18 at 14:29
  • @Steveland83 I've found solution. It was all about a place where it's provided (this service), moved it out of module to component directly and now it's ok... Interesting... ( if you want I can post a code ). – Roxy'Pro Jun 26 '18 at 14:56
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/173837/discussion-between-roxypro-and-steveland83). – Roxy'Pro Jun 26 '18 at 17:24

3 Answers3

1

There are various methods of sending data from one component to another. I would suggest trying a service

ng generate service article.service.ts

Then use that service to share data between the two

It would look something like this:

Component 1: componentOneData: any;

constructor(private articleService: ArticleService) {}

ngOnInit() {
  getData() {
    const data = http.get....
    this.articleService.data = data;
    this.componentOneData = data;
  }
}

Component 2:

componentTwoData: any;

constructor(private articleService: ArticleService) {}

ngOnInit() {
  this.data = this.articleService.data; // Now I can access the data
}

Service:

@Injectable()
export class ArticleService {
  data: any;
}

Thus, the service is just helping share the data between the two components. You are basically storing the data in the service so that it can be accessed by more than one component.

David Anthony Acosta
  • 4,766
  • 1
  • 19
  • 19
  • Can you provide at least example of how data might be added to an service ? – Roxy'Pro Jun 26 '18 at 11:43
  • your second component is not reloading that is why your template is not updating,Better pass button id from 1st component to 2nd component, inside 2nd component invoke your respective service – lpd Jun 26 '18 at 12:30
  • @LaxmipriyaDas its true template is not updating, what is your suggestion here? – Roxy'Pro Jun 26 '18 at 12:43
  • my suggestion is pass this ( getArticlesByGroupId(g.id) ) particular button id to 2nd component , inside 2nd component call servicegetArticlesByGroupId(selectedCategoryId: string) { this._articleService.getArticlesByGroupId(selectedCategoryId).subscribe(articles => { this.articles = articles; }); – lpd Jun 26 '18 at 12:52
0

you can use a Singleton service that has one instance, put some date in it and get them everywhere you need. create a shared module after that create a sharedService and import your that shared modules in your main module and dashboard module

you can use ModuleWithProviders and forRoot to Provide a singleton service

import { SharedService } ...
...
export class SharedModule {
static forRoot(): ModuleWithProviders {
    return {
        ngModule: SharedModule,
        providers: [SharedService]
    }
}}

and you can import it that way:

imports: [
    SharedModule.forRoot(),
],

reference

https://angular-2-training-book.rangle.io/handout/modules/shared-modules-di.html

Abhishek Ekaanth
  • 2,511
  • 2
  • 19
  • 40
0

It could be a good idea to pass across a service like :

@Injectable()
export class CategoryService {
    categoryEmitter: EventEmitter<any> = new EventEmitter();

    // you can add function and data
}

Import it inside your module and your components :

//Module
   providers:[SearchService]
//component
constructor(private catService : CategoryService ){}

and call on change =>

this.catService.categoryEmitter.emit(data);

and subscribe in the component you need to listen the change (middle component)=>

this.catService.categoryEmitter.subscribe((data)=>{
     // logic
});

See : https://angular.io/tutorial/toh-pt4

I hope it could help you!