Search code examples
angularjsangularjs-directiveangular-ngmodel

AngularJS - Directive ngModel doesn't get updated


I have a good understanding of AngularJS Directives, but I'm thinking I'm missing something here with my directives.

What's wrong : On the initial page load, the ngModel gets triggered correctly and I successfully receive the data and it's modeled in the input.

Everything I do after... doesn't work. If I modify the text in the input, the model is not updated.

Please note that if I don't use a directive (straight HTML), it works fine.


I have a directive like so :

.directive('defaultFormGroup', function () {
    return {
        restrict: 'A',
        templateUrl: 'form-group.html',
        replace: true,
        scope: {
            uniqueId: '@',
            labelTitle: '@',
            placeholderText: '@',
            ngModel: '=',
            bsLabelClasses: '@',
            bsFormControlClasses: '@'
        }
    };
})


The directive's template :

<div class="form-group">

    <label class="{{bsLabelClasses}} control-label text-left" for="{{uniqueId}}">{{labelTitle}}</label>

    <div class="{{bsFormControlClasses}}">
        <input type="text" class="form-control" id="{{uniqueId}}" placeholder="{{placeholderText}}" data-ng-model="ngModel">
    </div>

</div>


And here's how I call the directive in the template:

<div data-default-form-group 
     data-label-title="Name" 
     data-placeholder-text="Name" 
     data-unique-id="name" 
     data-bs-label-classes="col-sm-2 col-md-2" 
     data-bs-form-control-classes="col-sm-3 col-md-3" 
     data-ng-model="site.name">
</div>


I also have the same issue with radio buttons :

.directive('radioSwitch', function () {
    return {
        restrict: 'A',
        templateUrl: 'radio-switch.html',
        replace: true,
        scope: {
            ngModel: '=',
            radioName: '@',
            firstId: '@',
            firstValue: '@',
            firstLabel: '@',
            secondId: '@',
            secondValue: '@',
            secondLabel: '@',
        }
    };
})


Template:

<input type="radio" name="{{radioName}}" value="{{firstValue}}" id="{{firstId}}" data-ng-model="ngModel">
<label for="{{firstID}}">{{firstLabel}}</label>

<input type="radio" name="{{radioName}}" value="{{secondValue}}" id="{{secondId}}" data-ng-model="ngModel">
<label for="{{secondID}}">{{secondLabel}}</label>


HTML:

<div data-radio-switch 
     data-ng-model="site.existingCustomer" 
     data-first-label="Yes" 
     data-second-label="No" 
     data-radio-name="existingCustomer" 
     data-first-value="True" 
     data-first-id="true" 
     data-second-value="False" 
     data-second-id="false">
</div>


What am I missing?

UPDATE I was missing something in my directive... I want to choose the inputType (text, email, password, etc...)

If it's a textarea, the HTML is different... but it seems this line doesn't work data-ng-if=" inputType !== textarea "> ... if I remove it, it works

Anyone know why?

Here's a plunker : http://plnkr.co/edit/ITElF2epihSALeTutQAz


Solution

  • There doesn't seem to be something wrong with the directive itself: look at the example below with your directive, you can see that model which is the ng-model attribute of the directive gets updated. So, please try to reproduce your problem so we can help you (either embedded snippet, or jsfiddle, or just more code)

    angular.module('test', [])
    
    .controller('ctrl', function($scope) {
      $scope.model = 'foo';
    })
    
    .directive('defaultFormGroup', function () {
        return {
            restrict: 'A',
            template: '<div class="form-group"> <label class="{{bsLabelClasses}} control-label text-left" for="{{uniqueId}}">{{labelTitle}}</label> <div class="{{bsFormControlClasses}}"> <input type="text" class="form-control" id="{{uniqueId}}" placeholder="{{placeholderText}}" data-ng-model="ngModel"> </div> </div>',
            replace: true,
            scope: {
                uniqueId: '@',
                labelTitle: '@',
                placeholderText: '@',
                ngModel: '=',
                bsLabelClasses: '@',
                bsFormControlClasses: '@'
            }
        };
    })
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
    
    <div ng-app="test" ng-controller="ctrl">
      <div>model: {{model}}</div>
      <div default-form-group ng-model="model"></div>
    </div>

    Update: it seems that the issue comes from the ng-if, as reproduced in the following snippet. It is fixed by using nh-show instead, as the ng-if may loose the binding from your directive. I am not clear about the exact cause though.

    angular.module('test', [])
    
    .controller('ctrl', function($scope) {
      $scope.model = 'foo';
    })
    
    .directive('defaultFormGroup', function () {
        return {
            restrict: 'A',
            template: '<div ng-if="true"><input type="text" data-ng-model="ngModel" /></div>',
            replace: true,
            scope: {
                ngModel: '='
            }
        };
    })
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
    
    <div ng-app="test" ng-controller="ctrl">
      <div>model: {{model}}</div>
      <div default-form-group ng-model="model"></div>
    </div>