Search code examples
javascriptangularjsng-controllerangularjs-ng-formangularjs-forms

Publishing an Input outside the Form to the Form via name programmatically with Angularjs


I need to publish an Input to a Form, while the Input sits outside the form. I managed to add the input, but the result is not what I excactly need (see the console output)

So I basically adding the outer input element to the form via form.$addControl(outerInput)

const MyApp = angular.module('app', []);

MyApp.controller('formCtrl', ['$scope', '$element', function($scope, $element){
  
    $scope.dataModel = {
      name: 'robert arschfick',
      email: 'blabla',
      age: 25,
      text: 'text'
    };
  
  
    $scope.addOuterInputToForm = function(form, inputID){
      // annoying as hell, I am retrieving the input element;
      var input = angular.element(document.getElementById(inputID))[0];
      
      form.$addControl(input);
      console.log(form);
    };
}]);
<script src="//unpkg.com/angular/angular.js"></script>
<div ng-app="app" ng-controller="formCtrl">
  <form ng-submit="" name="testForm">
    <input type="name" ng-model="dataModel.name" name="name" required>
    <input type="email" ng-model="dataModel.email" name="email" required>
    <input type="number" ng-model="dataModel.age">
   
  </form>
  
  <!-- I need to add this input the same way the inner inputs name 
       and email are published to the form, so that it is addressable
       via its name in the form and that it is part of the form.controls
  -->
  <input type="text" required id="inputToAdd" name="text"
         ng-model="dataModel.text">
  <button ng-click="addOuterInputToForm(testForm, 'inputToAdd')">
     Add Control
  </button>
</div>

The input is added as a control, but the object looks different and has not all the ng $validators on it. Also I need to add it by name as a property to the form like "email" and "name" are:

This is the outside input added to the form. It misses all the ng-form attributes see the image after

enter image description here

This is the inside email input added to the form somehow internally. It has all the ng form properties like $untouched, $prestine etc.

enter image description here

So what I need is now to somehow fake this internal adding of the outer input programmatically so that the outer input is contained the same way by the form as the inner inputs "email" and "name"

Sorry for my english skills and I hope I was clear enough. Thanks in advance :)


Solution

  • The $addControl method needs the ngModelController of the <input>, not the <input> element itself.

    To get the ngModelController of the element, enclose it in a div that has an ng-form directive:

      <div ng-form="other">
         <input type="text" required id="inputToAdd" name="text"
                ng-model="dataModel.text">
      </div>
      <button ng-click="testForm.$addControl(other.text)">
         Add Control
      </button>
    

    The DEMO

    const MyApp = angular.module('app', []);
    
    MyApp.controller('formCtrl', ['$scope', '$element', function($scope, $element){
      
        $scope.dataModel = {
          name: 'robert arschfick',
          email: 'blabla',
          age: 25,
          text: 'text'
        };
      
    }]);
    <script src="//unpkg.com/angular/angular.js"></script>
    <div ng-app="app" ng-controller="formCtrl">
      <form ng-submit="" name="testForm">
        <input type="name" ng-model="dataModel.name" name="name" required>
        <input type="email" ng-model="dataModel.email" name="email" required>
        <input type="number" ng-model="dataModel.age">
       
      </form>
      
      <!-- I need to add this input the same way the inner inputs name 
           and email are published to the form, so that it is addressable
           via its name in the form and that it is part of the form.controls
      -->
      <div ng-form="other">
         <input type="text" required id="inputToAdd" name="text"
                ng-model="dataModel.text">
      </div>
      <button ng-click="testForm.$addControl(other.text)">
         Add Control
      </button>
    </div>