Search code examples
javascriptangularjsangular-ngmodel

ngModel.$setViewValue is not a function when trying to set model value


The ngModel I get from my directive's link function is a collection rather than an instance of ngModel. Of course, when I try to call ngModel.$setViewValue('bill'), my program throws an Error, ngModel.$setViewValue is not a function.

If I change my changeName function to address the first element of the array, it works fine. Why is ngModel coming through as a collection in this case? What does the order of the elements refer to? How can I fix it?

$scope.changeName = function(){
    ngModel[0].$setViewValue('bill');
    console.log(ngModel);
}

CodePen example

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

angular.module('app')
  .controller('MainController', function($scope) {
    $scope.name = "Greg"
  });

angular.module('app').directive('multiselectDropdown', multiSelectDropDown);

function multiSelectDropDown($window, $rootScope) {
  return {
    scope: {
      ngModel: '=',
    },
    require: ['?ngModel'],
    restrict: 'E',
    template: '<div>hi, {{ngModel}}<br><br><button ng-click="changeName()">Change name to bill.</button><br><br></div>',
    replace: true,
    link: linkFn
  };

  function linkFn($scope, iElement, iAttrs, ngModel) {
    $scope.changeName = function() {
      ngModel.$setViewValue('bill');
      console.log(ngModel);
    }
  }
}


Solution

  • Because you specified your require attribute as an array, angular will give your link function an array as a result. The array will contain the controllers requested.

    If you only need the ngModel controller, you can pass it as a string to require instead. Otherwise you need to reference it within the array given to your link function.

    require

    Require another directive and inject its controller as the fourth argument to the linking function. The require property can be a string, an array or an object:

    • a string containing the name of the directive to pass to the linking function
    • an array containing the names of directives to pass to the linking function. The argument passed to the linking function will be an array of controllers in the same order as the names in the require property
    • an object whose property values are the names of the directives to pass to the linking function. The argument passed to the linking function will also be an object with matching keys, whose values will hold the corresponding controllers.

    (emphasis added)