angularform-submitangular-componentsangular-event-emitterng-submit

Angular - Submit form in one component to trigger action in seperate unrelated component


Prior to this question I made this question. Basiclly in that, I'm trying to make it so when a form in a seperate component is submitted it creates a new instance of a component with the passed in values from the form displayed on that instance of the component. These components are created when I add data to an array in app.component.ts.

I do have that working now thanks to an answer, but now I'm trying to make it so that these components are created when a form in a different component is submitted.

When data from the form is added to an array in app.component.ts, it creates one of these component instances, but I only want this to occur when a form is submitted via ngSubmit in a seperate component, namely add-status-box.component.ts.

add-status-box.component.html:

<form [formGroup]="AddStatusBoxForm" (ngSubmit)='addStatusBox()'>

add-status-box.component.ts:

    export class AddStatusBoxComponent implements OnInit, OnDestroy 
    {
    
      message!: string;
      subscripton!: Subscription;
    
      constructor(private Form: FormBuilder, private data: StatusBoxService) { }
    
      AddStatusBoxForm = this.Form.group({
        name: ['']
      });
    
      ngOnInit(): void 
      {
        this.subscripton = this.data.currentMessage.subscribe(name => this.name = name)
      }
    
      ngOnDestroy(): void 
      {
        this.subscripton.unsubscribe();
      }

    addStatusBox()
    {
        this.data.changeMessage(this.AddStatusBoxForm.get('name')?.value);
        this.dialogRef.close();
    }
  }

app.component.ts:

export class AppComponent implements OnInit, OnDestroy
{

  name!: string;
  subscription!: Subscription;
  myNames: any[] = [];

  constructor(private data: StatusBoxService) {}

  ngOnInit(): void 
  {
    this.subscription = this.data.currentName.subscribe(name => this.name = name)
    this.myNames.push(this.name);
  }

  ngOnDestroy(): void
  {
    this.subscription.unsubscribe();
  }

status-box.service.ts

export class StatusBoxService 
{
  private messageSource = new BehaviorSubject('defaulty');
  currentMessage = this.messageSource.asObservable();
  
  changeMessage(message: string)
  {
    this.messageSource.next(message);
  }
}

At the moment when I call the addStatusBox() attatched to the form ngSubmit in add-status-box.component.ts, the name field input is passed to the StatusBoxService via the changeMessage function.

Then in the ngInit() function in the app.component.ts we subscribe to the StatusBoxService and retrieve the passed in name value from the form. This is then assigned to the name property.

Finally we add that name to the myNames array, however I want this crucial step of adding an item to an array to only occur when I submit the same form in add-status-box.component.ts. Because as you can see at the moment I add items to this array during oninit().

I did find this, and it seems as though ngSubmit is an EventEmitter. And it looks like you can subscribe to EventEmitters. So prehaps I could subscribe to the ngSubmit in app-status-box.component.ts within the app.component.ts so that I only add items to the array when the ngSubmit occurs.

I'm not sure if this is correct and if it is, I'm not sure how I would implement it. I have used subscibe before when I retrieve the name value from the StatusBoxService, so maybe I could do something simular?

Any help would be appreciated.


Solution

  • To avoid further discussion in comments I try to give you some advices in an answer, although it probably won't be exhaustive. It's hard to grasp a clear view of your current situation and your requirements (putting together a working example would be helpful).

    Anyway:

    (1) It's not clear to me why you're trying to use dynamic components. If your requirement is to show a component for every item in myNames just use ngFor:

    <app-status-box *ngFor="let item in myNames"></app-status-box>
    

    (2) Take the time of getting a minimal understanding of how Observables work. The fact that you're subscribing to this.data.currentName in ngOnInit doesn't mean that your callback function gets called only once, as you seem to think. That function (the function you write within subscribe()) will fire every time this.data.currentName emits a new value. Only the subscription is done once.

    (3) You're getting an initial rendering of <app-status-box> before the form is submitted because of this line on StatusBoxService:

    private messageSource = new BehaviorSubject('defaulty');
    

    Again, take your time and read on the docs how BehaviorSubject works. Once subscribed it will emit its current value and since your defining 'defaulty' as initial value, that's the first value you get in your AppComponent, even before the form is submitted. To solve this issue you could pass null as initial value and add a check in your callback.

    Minimal example:

        // status-box.service.ts
        private messageSource = new BehaviorSubject(null);
        
        // app.component.ts
        ngOnInit(): void 
          {
            this.subscription = this.data.currentName.subscribe(name => {
            if (name) {
               this.name = name;
              this.myNames.push(this.name);
            }    
        });
      }