Passing data from service to Component --> Child Components

后端 未结 2 1423
甜味超标
甜味超标 2021-01-22 17:17

To be very short i am using this Plunker I have a scenario where i have to create controls dynamically by reading the elements data from a service. So when i read the data from

相关标签:
2条回答
  • 2021-01-22 17:28

    Looking at this example Angular.io - Dynamic Forms, it essentially builds a form from metadata at runtime.

    There's a couple of comments indicating that the example isn't quite finished.

    @Injectable()
    export class QuestionService {
    
      // Todo: get from a remote source of question metadata
      // Todo: make asynchronous
      getQuestions() {
      ...
    

    These are the steps I took to finish it off and clean out the error messages.


    question.service.ts

    Changed getQuestions to asynchronously return questions.

    Injectable()
    export class QuestionService {
    
      constructor(
        private http: Http
      ) {}
    
      getQuestions$() {
        const url = 'https://api.myjson.com/bins/d0srd';
        return this.http.get(url)
          .map(response => response.json())
          .map(questionMetadata => this.metadataToQuestions(questionMetadata))
          .map(questions => questions.sort((a, b) => a.order - b.order))
      }
    
      private metadataToQuestions(questionMetadata) {
        return questionMetadata.questions.map(this.toQuestion)
      }
    
      private toQuestion(elementData) {
        // expand for additional control types
        return new TextboxQuestion({
          key: elementData.elementname,
          label: elementData.displaytext,
          value: elementData.elementvalue,
          required: false,
          order: elementData.sortorder
        })
      }
    }
    


    app.component.ts

    Changed variable questions type to observable, added async pipe to template.

    @Component({
      ...
      template: `
        <div>
          <h2>Job Application for Heroes</h2>
          <app-dynamic-form [questions]="(questions$ | async)"></app-dynamic-form>
        </div>
      `,
      ...
    })
    export class AppComponent implements OnInit {
    
      questions$: Observable<any>;
    
      constructor(
        private questionService: QuestionService
      ) {}
    
      ngOnInit() {
        this.questions$ = this.questionService.getQuestions$();
      }
    }
    


    dynamic-form.component.ts

    Changed @Input variable questions to be set/get style, to handle initial null value.
    Changed hook where form is created from ngOnInit to ngOnChanges to handle async arrival of questions.

    export class DynamicFormComponent implements OnChanges {
    
      private _questions = [];
      @Input() 
      set questions(value: any[]) {
        this._questions = value || [];
      }
      get questions(): any[] {
        return this._questions;
      }
    
      ...
    
      ngOnChanges() {
        this.form = this.qcs.toFormGroup(this.questions);
      }
    
    }
    


    dynamic-form-question.component.ts

    Add additional check to isValid getter to ensure the control being validated exists.

    export class DynamicFormQuestionComponent {
      ...
      get isValid() { return this.form.controls[this.question.key] 
        ? this.form.controls[this.question.key].valid : true; }
    }
    
    0 讨论(0)
  • 2021-01-22 17:47

    I'm not sure that I have understand your problem but when I need to pass data from service to a component I use subscription in this way.

    Two component (a parent component and its children or other different component) can share a service whose interface enables bi-directional communication.

    Like in the Observer pattern, in this case the scope of the service instance is the notification from a component (Publisher) and other componentents (Subscriber).

    mycomponent.service.ts

    import { Injectable } from '@angular/core';
    import { Subject } from 'rxjs/Subject';
    
    @Injectable()
    export class MyComponentService{
        // Observable 
        private sampleObservable = new Subject<boolean>();
        // Observable boolean streams
        sampleSubscriber = this.sampleObservable.asObservable();
        // Event for notification from publisher to subscriber
        sampleEventChanged(value:boolean)
        {
            this.sampleObservable.next();
        }
    }
    

    In the component who wants to notify all subscribers a change of its state:

    mycomponent-publisher.ts

    import { Component } from '@angular/core';
    import { MyService } from './mycomponent.service';
    
    @Component({
      selector: 'app-my-control-publisher',
      template: `
      <h2>This is the publisher control</h2>
      <button (click)="announce()">Announce to subscriber</button>
      `,
      providers: [MyService]
    })
    
    export class MyControlPublisherComponent 
    {
      constructor(private myService: MyService) { }
    
      announce() 
      {
        this.myService.sampleEventChanged(true);
      }
    }
    

    In the subscriber component who want to get the notification.

    mycomponent-subscriber.ts

    import { Component, OnDestroy } from '@angular/core';
    import { MyService } from './mycomponent.service';
    import { Subscription } from 'rxjs/Subscription';
    
    @Component({
     selector: 'app-my-control-subscriber',
     template: `
     <h2>This is the subscriber control</h2>
     `,
    })
    
    export class MyControlSubscriberComponent 
    {
      // Subscriptions
      private componentSubscription: Subscription;
    
      constructor(private myService: MyService) 
      {
        // Subscription of the notifications
        this.componentSubscription= this.myService.sampleSubscriber.subscribe(value =>
        {
          // Put the code for manage the notification here
        }
      }
    
      ngOnDestroy()
      {
        // Release subscription to avoid memory leaks when the component is destroyed
        this.componentSubscription.unsubscribe();
      }
    }
    

    I hope that this can help you.

    0 讨论(0)
提交回复
热议问题