1

I need to create a simple form with validations like this - https://jsfiddle.net/rohansh20/k7omkz7p/2/

<div ng-app="module1" ng-controller="ctrl1 as vm">
  <form novalidate name="vm.form1" class="css-form">
    <label>Name:
      <input type="text" name="Name" ng-model="vm.user.name" required />
    </label>
    <br />
    <label>E-mail:
      <input type="email" name="Email" ng-model="vm.user.email" required />
    </label>
    <br />
    <input type="submit" ng-click="vm.save(vm.form1, vm.user)" value="Save" />
  </form>
  <div>
    {{vm.result}}
  </div>  
  <pre>form = {{vm.form1 | json}}</pre>
</div>


angular.module('module1', []);

angular.module('module1').controller('ctrl1', function() {
  this.save = function(form, user) {
    if(form.$invalid) {
        this.result = 'Please correct the data entered';
      return;
    }
    this.result = 'User ' + user.name + ' with email ' + user.email + ' saved successfully';
  };
});

But I need to dynamically generate the input fields. So I have made a directive that transforms into any type of input field - https://jsfiddle.net/rohansh20/hdxj0np6/3/

<div ng-app="module1" ng-controller="ctrl1 as vm">
  <form novalidate name="vm.form1" class="css-form">
    <custom-input name="Name" type="text" model="vm.user.name" required="true">
    </custom-input>
    <br />
    <custom-input name="Email" type="email" model="vm.user.email" required="true">
    </custom-input>
    <br />
    <input type="submit" ng-click="vm.save(vm.form1, vm.user)" value="Save" />
  </form>
  <div>
    {{vm.result}}
  </div>
  <pre>form = {{vm.form1 | json}}</pre>
</div>

var app = angular.module('module1', []);

app.controller('ctrl1', function() {
  this.save = function(form, user) {
    if(form.$invalid) {
        this.result = 'Please correct the data entered';
      return;
    }  
    this.result = 'User ' + user.name + ' with email ' + user.email + ' saved successfully';
  };
});

app.directive('customInput', function($compile) {
  return {
    restrict: 'E',
    link: function(scope, element, attributes) {
      var labelElement = angular.element('<label/>'),
        name = attributes.name,
        type = attributes.type,
        ngModelString = attributes.model,
        required = attributes.required,
        inputElement = angular.element('<input/>');
      inputElement.attr('ng-model', ngModelString);
      inputElement.attr('name', name);
      inputElement.attr('type', type);
      if (required) {
        inputElement.attr('required', 'required');
      }
      labelElement.append(name + ': ');
      labelElement.append(inputElement);
      $compile(labelElement)(scope);
      element.replaceWith(labelElement);
    }
  }
});

The fiddles are simplified versions of what I'm trying to make. The problem is that these fields, even though compiled and rendered perfectly(which can be seen by inspecting the HTML), are not getting included as part of the parent form control. This can be seen in the displayed form control object in both the fiddles. Because of this, the form validity cannot be determined and both forms behave differently on submitting invalid input.

I need the form control in the second fiddle to have correct values for its properties and to have the child controls and their properties like in the first fiddle. Is this even possible using a custom directive? What do I need to change to make this work?

Note - The directive would involve complex operations to dynamically create HTML, so it has to be done in the link function of a directive. A directive template with multiple ngIfs would just not work.

1 Answer 1

0

In order not to lose bindings from your parent form, include it in your custom form directive

In your directive

    (function () {
    'use strict';

    angular
        .module('myApp')
        .directive('customInput', customInput)





    customInput.$inject = ['$compile'];
    /* @ngInject */
    function customInput ($compile) {


        var directive = {
            templateUrl: 'app/custom-input.html',
            restrict: 'E',
            transclude: true,
            require: "?^form",
            compile: compile,
            controller:CustomInputController,
            controllerAs:'vm',
            scope:{
                inputType:'=',
                inputValue:'='
            }
        };

        return directive;
        function CustomInputController($scope){
            var vm = this;


        }
        function compile(element, attributes){

            return {
                pre: preLink,
                post: postLink
            }
        }
        function preLink (scope,element,attrs, form, transclude){

        }
        function postLink (scope,element,attrs, form, transclude){
            scope.currentForm = form;

            $compile(element.contents())(scope);
        }
    }

})();

In your directive html template

<input type="inputType" ng-model="inputValue">

When you call your directive

   <br-input type="text"
          input-value="vm.user.email"
          inputname="name"
          input-required ="true">
   </br-input>
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.