Utilize Angular 2 to associate form context with ngTemplateOutlet

Currently, I am working on defining a Component that consists of a dynamic Form using ReactiveForms. The goal is to allow users to add or delete Controls within the form. These Controls can vary in structure and need to be defined externally to the Component. This is why I believe that TemplateRef would be the most suitable approach for this scenario.

My main challenge lies in connecting the externally defined Control to the internal Form using formControlName.

Below is the initial implementation:

// expandable.component.ts

[...]
@Component({
  selector: 'expandable',
  templateUrl: 'app/component/common/expandable/expandable.component.html',
  styleUrls: ['app/component/common/expandable/expandable.component.css']
})
export class ExpandableComponent {
  @ContentChild('childTemplate') childTemplate: TemplateRef<any>;

  @Input() children: Array<any>;
  public form: FormGroup;

  constructor(private _changeDetector: ChangeDetectorRef,
              private _formBuilder: FormBuilder) {
    this.children = [];
  }

  public ngOnInit(): void {
    this.form = this._formBuilder.group({
      children: this._formBuilder.array([])
    });

    const arrayControl = <FormArray>this.form.controls['children'];
    this.children.forEach(child => {
      const group = this.initChildForm();
      arrayControl.push(group);
    });
  }

  private initChildForm(): AbstractControl {
    return this._formBuilder.group({
      key: ['Initial Key', [Validators.required]],
      value: ['Initial Value', [Validators.required]]
    });
  }

  public addChild(): void {
    const control = <FormArray>this.form.controls['children'];
    control.push(this.initChildForm());
    this._changeDetector.detectChanges();
  }
}

-

<!-- expandable.component.html -->

<form [formGroup]="form">
  <div class="form-group">
    <div formArrayName="children">
      <div *ngFor="let child of form.controls.children.controls; let i=index">
        <div [formGroupName]="i">
          <template 
             [ngTemplateOutlet]="childTemplate" 
             [ngOutletContext]="{ $implicit: child }"></template>
        </div>
      </div>
    </div>
  </div>
  <a (click)="addChild()">Add Child</a>
</form>

Attempting to define the template externally:

  <expandable>
    <template #childTemplate>
      <input class="form-control" 
        formControlName="value" />
      </template>
  </expandable>

I have attempted to bind the formControlName to the context passed from the outer , but unfortunately, I keep receiving an error "Cannot find control with name: 'value'". Ideally, I would prefer to handle the formControlName binding within the expandable.component.html file, but I haven't found a way to accomplish this either. Any insights or suggestions would be greatly appreciated.

Answer №1

Achieving this is entirely feasible:

To make it work, you must incorporate the ControlValueAccessor interface that gets injected with ngModel and formControlName. Here's how you can do it:

@Directive({
  selector: 'control',
  providers: [
    {provide: NG_VALUE_ACCESSOR, multi: true, useExisting: SwitchControlComponent}
  ]
})
export class SwitchControlComponent implements ControlValueAccessor {
  isOn: boolean;
  _onChange: (value: any) => void;

  writeValue(value: any) {
    this.isOn = !!value;
  }

  registerOnChange(fn: (value: any) => void) {
    this._onChange = fn;
  }

  registerOnTouched() {}

  toggle(isOn: boolean) {
    this.isOn = isOn;
    this._onChange(isOn);
  }
}

html:

  <expandable>
    <template #childTemplate>
      <div [formGroup]="form">
         <input control class="form-control" 
           formControlName="value" />
         </template>
      </div>
  </expandable>

For further insights:

Problems regarding adding inputs from child components in new forms api without additional form tags

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Angular 2 Release Candidate 1 introduces a powerful router that allows for URL rewriting capabilities

Since updating to routing rc 1, my application is encountering issues when the URL includes query string parameters. Below is the setup of the routes in the app component: import {Component, OnInit, OnDestroy } from '@angular/core'; import {RO ...

The v-model in Vue does not function correctly when used with a single index within an array

I am encountering a situation with a series of input fields, including a checkbox and a dropdown button in each row. Additionally, there is a button to add a new row of inputs. When the checkbox is checked, it should disable the dropdown menu and make it ...

Stop the animation when the mouse is moved

Below is the code I am working with: $(source) .on('mouseenter', start) .on('mouseleave', stop) .on('mousemove', zoom.move); Within this code, I have attached several mouse event listeners. When the 'mouseenter' ev ...

Changing the type of an object's property in TypeScript on the fly

I am working on a TypeScript function that is designed to dynamically modify the property of an object. Here is the function: const updateProperty = (value: any, key: keyof Type1, obj: Type1) => { obj[key] = value; } Below is the definition of "Typ ...

Encountering a problem with the scope of child_process in Node

When utilizing the child_process module in Node.js with the fork method, I am able to send data to a specific file and receive a response. However, I am not logging this data to the console after receiving it from the execution process. The code in first. ...

Utilizing a hidden file-input, IE10 is able to transmit a FormData object via ajax

I'm encountering difficulties when trying to send a form that includes a display:none file-input via ajax. It works fine in Chrome (46.0.2490.71), but not in IE10 (10.0.9200.17492). I've tried various solutions without success, and it's cruc ...

The functionality of Ionic Cordova is currently inaccessible

Currently utilizing the Ionic Native Calendar plugin in version 3.9.2 of Ionic framework. The module has been successfully installed and included in the app module. Below is the snippet where the calendar is being called: import { Component } from ' ...

When developing an Angular 2 application using Webpack 2, encountering template parse errors such as 'app' not being a recognized element can occur during deployment

I have encountered an issue with my Angular (v2.4) application using angularfire2. Everything works perfectly in the development environment with the Express server. However, when I build the app using "npm run build", Webpack2 creates a 'target' ...

Using AngularJS to link a model referenced in the view (ng-bind) to a $resource obtained from an API

I'm currently facing a challenge in Angular where I need to establish a connection between a database object displayed in the html view and its corresponding instance through a json API. While I have a functioning api and $resource, I am struggling t ...

Both Google Chrome and Firefox are recognizing the Binance WSS api url as an HTTPS connection

My attempt to execute the code from my Chrome browser was unsuccessful. import io from 'socket.io-client'; const socket = io('wss://stream.binance.com:9443'); socket.on('connect', () => { console.log('binance [so ...

Tips for validating and retrieving data from a radio button paired with an input box in reactjs

I'm diving into the world of React and facing a challenge with multiple radio buttons that have associated input fields, like in this image: https://i.stack.imgur.com/Upy3T.png Here's what I need: If a user checks a radio button with a ...

Firefox users may notice that the pop-up video player appears in unusual locations on their screen

I'm encountering an issue with a pop-up video player that is triggered by an "onClick" event in HTML elements. The problem arises when there are multiple video players on the same page - in Firefox, the first video loads at the bottom of the page, req ...

I am looking to manage user-related data in the comment model using mongoose and express

I have a user, post, and comment modal This is my comment modal import mongoose from "mongoose"; const CommentSchema = new mongoose.Schema({ postId: { type: mongoose.Schema.Types.ObjectId, ref: "Post", }, userId: { t ...

Utilizing jQuery to eliminate a script function from an external webpage

Currently, I am utilizing a ColdFusion script to load an external page within the container tag. This external page contains a sorting function defined as: function sorting(sortid). However, this function's sorting criteria constantly leads to errors ...

Setting the height of a div tag in CSS/HTML5 to match the current height of the browser window

Is there a way to make the height of my div tag always equal to the height of the browser's window, so it adjusts automatically when the browser is resized? I have tried using .class { height: 100%; } But this doesn't work. I've learne ...

In the ajax call, an empty JSON array object is sent as the data

Utilizing JSON data as a parameter for an ajax call: var startDate = dateFormatForSave($("#start_date").val().trim()); var arrayOfStudentsInfo = []; var table = $("#selected_students"); table.find('tr').each(function(i, el) { var rowId = $( ...

Monitoring of access controls on Safari during uploads to S3

Safari 10.1.2 Encountering an issue intermittently while attempting to upload PDF files to S3 using a signed request with the Node aws-sdk. Despite working smoothly 90% of the time, have been pulling my hair out trying to resolve this problem. Could it be ...

Making React function properly on GitHub Pages

I have followed all the steps and even consulted multiple tutorials that all say the same thing, but when I try to run "npm run deploy" I encounter an error and nothing happens. This is the error message: [email protected] deploy A:\Documents&bs ...

Is there a way to customize the appearance of an unordered list by setting it to display as an image instead of default bullets? I want to

I have been attempting to achieve this desired outcome. However, my efforts to reproduce it resulted in the check marks being rendered at a smaller size than intended due to using an SVG file. An example of this issue can be seen in the following image: I ...

Press the toggle button to switch the image display

Currently learning HTML and attempting to design a dashboard. I want to display the status (ON, OFF, OPEN, or CLOSED) of a room or door using an icon. I have images for open/close doors and lightbulbs. Need assistance in adding an element to all the exist ...