poshest
poshest

Reputation: 4237

AngularJS directive: Expression 'undefined' used with directive ... is non-assignable

I'm a 2 week old Angular noob, and I've been attempting my first ever directive for over a day now. :P I've read this and this, which seem good directives introductions and a bunch of Stackoverflow answers, but I can't get this working.

<div ng-app="App" ng-controller="Main">
  <textarea caret caret-position="uiState.caretPosition"></textarea>
  {{uiState.caretPosition}}
</div>

and

angular.module('App', [])
  .controller('Main', ['$scope', function ($scope) {
    $scope.uiState = {};
    $scope.uiState.caretPosition = 0;
  }])


  .directive('caret', function() {
    return {
      restrict: 'A',
      scope: {caretPosition: '='},
      link: function(scope, element, attrs) {
        var $el = angular.element(element);
        $el.on('keyup', function() {
          scope.caretPosition = $el.caret();
        });
      }
    };
  }); 

Fiddle is here. I'm basically trying to get the caret position within a textbox. I'm using this jQuery plugin in the fiddle (source of the .caret() method, which should just return a number).

My questions are

  1. Do I even need a directive here? Ben Nadel says the best directives are the ones you don't have to write (amen to that!)
  2. If yes, is this the right way to go about the directive? Ie isolated scope with two-way bound variable?
  3. If yes, when I run this code locally, I keep getting the error Expression 'undefined' used with directive 'caret' is non-assignable!. I've read the doc and as far as I can tell I've followed instructions for how to fix to no avail.
  4. BONUS: Why in jsfiddle do I get no such error. The fiddle just fails silently. What's with that?

Thanks!

Upvotes: 21

Views: 29391

Answers (2)

Louis
Louis

Reputation: 1035

My solution was harder to find out here, but easier to implement. I had to change it to the equivalent of;

  scope: {caretPosition: '=?'},

(Note that the question mark makes the attribute optional. Prior to 1.5 this apparently wasn't required.)

Upvotes: 23

Austin Greco
Austin Greco

Reputation: 33544

You were close.. The main problem is changing a scope variable inside an event that angular doesn't know about. When that event occurs, you have to tell angular that something changed by using scope.$apply.

  $el.on('keyup', function() {
      scope.$apply( function() {
        scope.caretPosition = $el.caret();
      });
  });

Working fiddle here

For the questions:

  1. yes, I don't think there's a way around having to write a directive for this.
  2. in this case, it seems fine.
  3. not sure, there are no problems in the jsfiddle. It sounds like you're setting carat="something" somewhere? check to make sure the html is the same as what's in the fiddle.
  4. same as 3

Also note that if you click and move the caret, it won't update because it's only listening for keyup.

Upvotes: 14

Related Questions