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

28,722

Solution 1

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.

Solution 2

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.)

Share:
28,722

Related videos on Youtube

poshest
Author by

poshest

Updated on July 09, 2022

Comments

  • poshest
    poshest almost 2 years

    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!

    • smurtagh
      smurtagh almost 7 years
      I think @Lois's answer is more common for the angular problem in the title.
  • poshest
    poshest over 10 years
    Damn, and I had already tried the scope.$apply based on this excellent article too! link (slider example). Must have had something else wrong at the time. Your answer fixes the fiddle, so accepted! I was still getting the error in my app. It was indeed because the fiddle didn't match my code! :P There were a two textareas defined in my code and one was missing the caret-position attribute. A case of many concurrent errors, and not knowing which one the error msg is describing!
  • poshest
    poshest over 10 years
    Submitted request to update the Angular docs