Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to bind to ng-model inside a directive that has no scope?

I want to create a directive that wraps a form element (input, textarea, select, etc.) and binds to ng-model.

Here's the usage:

<div ng-controller="formController">
    <field 
           type="text" 
           ng-model="model.CellPhoneNumber" 
           label="Cell phone" 
           mini-help="Sample: 123412341234" 
           required="please give us your number" 
           numeric 
           cellPhone="cell phone number is invalid" />
    <div>{{ model.CellPhoneNumber }}</div>
</div>
<script>
    app.cp.register('formController', ['$scope', function ($scope) {

    }]);
</script>

And here's my directive:

app.directive('field', function () {
        return {
            restrict: 'E',
            replace: 'true',
            scope: false,
            require: 'ngModel',
            template: '<div class="field">' +
                            '<label ng-if="label">{{ label }}</label>' +
                            '<input type="text" ng-if="type == \'text\'" required ng-model="ngModel" />' +
                            '<span class="mini help" ng-if="miniHelp">{{ miniHelp }}</span>' +
                            '<span class="messages">' +
                                '<span class="error message" ng-message="required" ng-if="requried">{{ required }}</span>' +
                            '</span>' +
                      '</div>',
            link: function (scope, element, attributes, ngModel) {
                scope.label = attributes.label;
                scope.miniHelp = attributes.miniHelp;
                scope.type = attributes.type;
                scope.required = attributes.required;
            }
        };
    });

However, it doesn't work. I'm stuck at binding ng-model. I know I can switch to a child scope through scope: {}, and things would work. But I need scope: false.

Here is a good sample of how to do it. But I can't find a sample with scope: false.

Dynamic ng-model binding inside a directive

like image 609
Nasseh Avatar asked Jan 20 '26 21:01

Nasseh


1 Answers

You're very close to your desired solution. The fourth parameter of the link function is a ngModelController which is different than ngModel. Your problem is that you're using it as a plan ngModel. All that you need to do is just a couple of small changes.

First of all, you need to bind the ngModelController to your scope. Then, instead of ng-model="ngModel", you bind the $viewValue, like this: ng-model="ngModel.$viewValue". Finally, you need to create a watch in order to allow your directive, field, to change the ngModel's value, otherwise it will be one directional.

Here's the working code:

angular
  .module('myApp', [])
  .directive('field', function() {
    return {
      restrict: 'E',
      replace: 'true',
      scope: false,
      require: 'ngModel',
      template: '<div class="field">' +
        '<label ng-if="label">{{ label }}</label>' +
        '<input type="text" ng-if="type == \'text\'" required ng-model="ngModel.$viewValue" />' +
        '<span class="mini help" ng-if="miniHelp">{{ miniHelp }}</span>' +
        '<span class="messages">' +
        '<span class="error message" ng-message="required" ng-if="requried">{{ required }}</span>' +
        '</span>' +
        '</div>',
      link: function(scope, element, attributes, ngModel) {
        scope.label = attributes.label;
        scope.miniHelp = attributes.miniHelp;
        scope.type = attributes.type;
        scope.required = attributes.required;

        scope.ngModel = ngModel;
        scope.$watch(function() {
          return ngModel.$viewValue;
        }, function(newValue) {
          ngModel.$setViewValue(newValue);
          ngModel.$render();
        });
      }
    };
  });
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"></script>

<div ng-app="myApp" ng-init="myModel = 'qwe'">
  <field type="text" ng-model="myModel" label="Cell phone" mini-help="Sample: 123412341234" required="please give us your number" numeric cellPhone="cell phone number is invalid"></field>

  <input type="text" ng-model="myModel">
  <p>{{ myModel }}</p>
</div>
like image 145
Cosmin Ababei Avatar answered Jan 24 '26 05:01

Cosmin Ababei



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!