1

I've created this very simple directive called <form-field>, I'm trying to bind ng-model to that directive. I've broken down the example to the simplest usecase possible,

I've included the controller, and the directive with the HTML for the form it sits on. I've seen a lot of examples where require:ngModel is used and then action takes place inside link: but all these examples are just for either dom manipulation, or increments for instance that don't save a value

angular.module('taskApp', [])
  .controller('taskController', function($scope) {
    $scope.taskData = {};
    $scope.save = function(taskData) {
      $scope.taskData = angular.copy(taskData);
    };
  })
  .directive('formField', function($timeout) {
    var template = '<div class="form-group" ng-switch="element">' +
      '<input ng-switch-when="input" ng-model="ngModel" name="{{field}}">' +
      '<textarea ng-switch-when="textarea" ng-model="ngModel" name="{{field}}"></textarea>' +
      '</div>';
    return {
      restrict: 'EA',
      template: template,
      replace: true,
      scope: {
        ngModel: '=',
        field: '@',
        live: '@',
        element: '@'
      },
      link: function($scope, element, attr) {

      }
    };
  });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

<body ng-app="taskApp" ng-controller="taskController">
  <form name='taskForm' novalidate>

    <form-field element='input' live='false' field="title" ng-model="taskData.title"></form-field>

    <form-field element='textarea' live='false' field="notes" ng-model="taskData.notes"></form-field>

    <button type="submit" ng-click="save(taskData)">save</button>

  </form>

  <br/>
  <pre>{{taskData | json}}</pre>

</body>
kmassada
  • 263
  • 5
  • 16

1 Answers1

3

ngModel inside your directive still refers to the inner isolated scope. You can use $parent.ngModel to access the outer model.

var template = '<div class="form-group" ng-switch="element">' +
  '<input ng-switch-when="input" ng-model="$parent.ngModel" name="{{field}}">' +
  '<textarea ng-switch-when="textarea" ng-model="$parent.ngModel" name="{{field}}"></textarea>' +
  '</div>';
Antony Mativos
  • 863
  • 1
  • 8
  • 5
  • is there a way to 'inject' the parent scope into the directive declaration like `.directive(function($timeout,$parent.scope)`, and could you elaborate on how come it is a $parent, and not a sibling? – kmassada Sep 23 '15 at 15:43
  • http://stackoverflow.com/a/17900556/1095800 I'm reading this answer and it looks like $parent is not recommended. perhaps is there a way while binding in my scope `scope {ngModel: =$parent.ngModel}` – kmassada Sep 23 '15 at 15:48
  • @kmassada You can access parent scope via `$scope` variable that's injected in your link function: `$scope.$parent`. I haven't come accross any explanation of why `$parent` is not recommended... As for the explanation, the version of Angular that I used when I encountered the same problem actually worked without using `$parent`, so it must be an internal change that I don't know about. You can also use `scope: true` on your directive, which will not create an isolate scope and will allow you to *not* use `$parent`. – Antony Mativos Sep 23 '15 at 17:52