11

I am working on a application which contains a search functionality.

Right now I have 2 components in application 1. Navbar 2. SearchGridList

Navbar component contains a text box, in which you type in a search query and hit enter and this component will make a api call and get the data. When the data comes back, I want to populate this data in an array in SearchGridList component.

I am having a tough time understanding passing data within components in Angular, can someone please take a look at my code and guide me.

navbar.component.ts

import { Component, OnInit, Input, Output } from '@angular/core';
import {DataService} from '../../services/data.service';
import {SearchResults} from '../class/search.class';
import {SearchGridListComponent} from '../search-grid-list/search-grid-list.component';
import { EventEmitter } from '@angular/core';

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

  searchQuery : String;
  //searchResultList : Array<any> = [];

  constructor(private dataService :  DataService) { }

  doSearch () : any
  {
    this.dataService.doSQLSearch(this.searchQuery)
    .then ((data:any)=>{
      for (var i =0; i<data.Results.length;i++){
        let searchObj = new SearchResults(data.Results[i]);
        //I want to push data into array from SearchGrid like this 
        resultGridList.push(searchObj);

      }
    });
   }

  ngOnInit() {
  }
}

navbar.component.html

<mat-toolbar class="main-header">
  <a href="/">
  <img src="../../../assets/vms-header-logo.png" id= "header-logo">
  </a>
    <form class="search-box">
      <mat-form-field  class="search-box-full-width">
        <input id ="search-textbox" matInput placeholder="Enter a Barcode, DSID or any search term" name="Search" [(ngModel)]="searchQuery" (keyup.enter)="doSearch()" autocomplete="off">
      </mat-form-field>
    </form>
</mat-toolbar>

search-grid.component.ts

import { Component, OnInit, Input } from '@angular/core';
import {NavbarComponent} from '../navbar/navbar.component';

@Component({
  selector: 'app-search-grid-list',
  templateUrl: './search-grid-list.component.html',
  styleUrls: ['./search-grid-list.component.css'],
})
export class SearchGridListComponent implements OnInit {
  resultGridList : Array <any> = [];
  constructor() { }

  ngOnInit() {
  }

}
4
  • how looks html/js code of parent component which contains grid and navbar? Commented Mar 12, 2019 at 15:51
  • 1
    Please be more specific. What from this specifically do you not understand? Commented Mar 12, 2019 at 15:52
  • 1
    Please, take a look in this link angular.io/guide/… If the components are parent and child you may use the input binding If they are not, the best solution is using a service, as the link is explaning Commented Mar 12, 2019 at 15:55
  • @KamilKiełczewski - right - that would be the third component that was not mentioned - the App component. Commented Mar 12, 2019 at 15:55

4 Answers 4

7

You can create a BehaviorSubject in your DataService

private messageSource = new BehaviorSubject<string>('service');

You can refer this demo for passing data between component.

https://stackblitz.com/edit/behavior-subject-2019

Sign up to request clarification or add additional context in comments.

1 Comment

yes .. I can recommend BehaviourSubject also. So for example I use this for auth state .. I wrote a post about this: medium.com/@fransyozef/…
6

You need to add to navbar following @Output event:

export class NavbarComponent implements OnInit {
   ...
   @Output() public found = new EventEmitter<any>();
   ...
   doSearch () : any
   {
    this.dataService.doSQLSearch(this.searchQuery) .then ((data:any)=>{
      for (var i =0; i<data.Results.length;i++){
        let searchObj = new SearchResults(data.Results[i]);

        this.found.emit(searchObj);  // !!!! here emit event
                                     // however emitting events in loop looks strange... better is to emit one evet

      }
    });
   }
   ...
}

Ok in your grid component use @Input as resultGridList parameter

export class SearchGridListComponent implements OnInit {

  @Input() public resultGridList : Array <any> = [];
  ...
}

Ok and now in your App component join this two in following way

App template html:

<app-navbar (found)="handleResults($event)"></app-navbar>

<app-search-grid-list [resultGridList]="data"></app-search-grid-list>

And in App ts file:

data = [];
...

handleResults(searchObj) {
  this.data = searchObj
}

4 Comments

This helped me solve my issue. Just a quick question, is this the proper way to do it ? I understand that I can create a Service and inject it, but I do not want to create service that is just going to be used once in the application.
@KshitijAnilRangari usually application have N services (depends on resources/requests in restfulapi, db-backend-domain) and that set of services is used by K components where usually K>N. I dont know how your domain looks. My solution is standard way to do it, however solution proposed by Hien is also interesting (and more advance) alternative.
@KamilKiełczewski what if I don't want to have search in navbar on other component ? If we do <app-navbar (found)="handleResults($event)"></app-navbar> , it need to added in every component. If not it will throw NullInjector error. In this case what will be the solution ?
@NoobCoder this is separate question which you can ask on stackoverflow. However I will do it using some singleton service with global events
0

@Input is used to define an input property, to achieve component property binding. @Inoput decorator is used to passing data (property binding) from parent to child component.
The component property should be annotated with @Input decorator to act as input property.

Comments

-3

Simply inject dataService in search-grid component as well. Services are singletons, you can share them across components.

In one component :

dataService.test = "hello";

in another component :

console.log(dataService.test); // "hello"

That's what services are for.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.