javascriptangularjs

How to use ngChange on a div (or something similar)


I had an input that had ng-change on it, then I changed it to a contenteditable div, so I can have a little more control over what I can do with the input. But the thing is that when I changed from an input to a div, I am no longer able to use ng-change. What can I do obtain the same effect/result?

Here is how I am using it in my template:

<div class="form-control" ng-model="search" ng-change="searchChanged()" contenteditable="true">{{seach}}</div>

Solution

  • Inorder to support ng-model with ng-change for anything other than form element, you would need to create a custom directive. For example a simple implementation as below directive named contenteditable (much similar to angular having internal directives for input, form etc), have it require ng-model and on keyup event set the viewvalue and render the ng-model. When you setViewValue for the ng-model and values are different than prev value angular will evaluate the ng-change expression.

    .directive('contenteditable', function() {
          return {
            require: 'ngModel',
            restrict: 'A',
            link: function(scope, elm, attr, ngModel) {
    
              function updateViewValue() {
                ngModel.$setViewValue(this.innerHTML);
              }
              //Binding it to keyup, lly bind it to any other events of interest 
              //like change etc..
              elm.on('keyup', updateViewValue);
    
              scope.$on('$destroy', function() {
                elm.off('keyup', updateViewValue);
              });
    
              ngModel.$render = function(){
                 elm.html(ngModel.$viewValue);
              }
    
            }
        }
    });
    

    and do:

    <div class="form-control" type="search" 
          ng-model="seach" ng-change="searchChanged()" 
          contenteditable="true"></div>
    

    angular.module('app', []).controller('ctrl', function($scope) {
      $scope.seach = "Initial";
      $scope.searchChanged = function() {
        console.log('changed', $scope.seach);
      }
    }).directive('contenteditable', function() {
      return {
        require: 'ngModel',
        restrict: 'A',
        link: function(scope, elm, attr, ngModel) {
    
          function updateViewValue() {
            ngModel.$setViewValue(this.innerHTML);
          }
    
          //Or bind it to any other events
          elm.on('keyup', updateViewValue);
    
          scope.$on('$destroy', function() {
            elm.off('keyup', updateViewValue);
          });
    
          ngModel.$render = function() {
            elm.html(ngModel.$viewValue);
          }
    
        }
      }
    });
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
    <div ng-app="app" ng-controller="ctrl">
      Edit
      <div class="form-control" type="search" ng-model="seach" ng-change="searchChanged()" contenteditable="true"></div>
      {{seach}}
    </div>