2

I've implemented the foo component whose template has an input (binded to fooValue property) with a directive attribute that calls that component controller function onEnter when "enter" key is pressed when the input has focus.

The issue that I'm getting is, after inserting a value in the input (i.e. "foo3") and pressing "enter" key, fooValue is not update with the input value.

Here is the snippet:

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

app.component('foo', {
  template: '<input ng-model="$ctrl.fooValue" enter-key="$ctrl.onEnter()" />',
  controller: function() {
    this.onEnter = function() {
      // this.fooValue is not updated with input value
    };
  },
  bindings: {
    fooValue: '@'
  }
});

app.directive('enterKey', function() {
  return {
    restrict: 'A',
    link: function(scope, element, attrs) {
      element.bind("keydown keypress", function(event) {
        var keyCode = event.which || event.keyCode;

        // If enter key is pressed
        if (keyCode === 13) {
          scope.$apply(function() {
            // Evaluate the expression
            scope.$eval(attrs.enterKey);
          });
        }
      });
    }
  };
});

describe('test', function() {
  describe('foo', function() {
    beforeEach(module('app'));

    var element,
      inputElem;

    beforeEach(inject(function($compile, $rootScope) {
      var fooScope = $rootScope.$new();

      element = angular.element('<foo foo-value="foo1"></foo>');
      element = $compile(element)(fooScope);

      fooScope.$digest();
    }));

    it('should set fooValue with foo3', function() {
      var controller = element.controller('foo');
      inputElem = element.find('input');
      inputElem.val('foo3');
      inputElem.triggerHandler({
        type: 'keydown',
        which: 13
      });

      expect(controller.fooValue).toBe('foo3');
    });
  });
});
<!DOCTYPE html>
<html ng-app="app">

<head>
  <link rel="stylesheet" href="//cdn.jsdelivr.net/jasmine/2.0.0/jasmine.css" />
  <script src="//cdn.jsdelivr.net/jasmine/2.0.0/jasmine.js"></script>
  <script src="//cdn.jsdelivr.net/jasmine/2.0.0/jasmine-html.js"></script>
  <script src="//cdn.jsdelivr.net/jasmine/2.0.0/boot.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.js"></script>
  <script src="https://code.angularjs.org/1.6.1/angular-mocks.js"></script>
</head>

<body>
</body>

</html>

What's missing to make fooValue updated?

4
  • The directive executes functions on portal-enter-key and the component puts the function on enter-key Commented May 27, 2018 at 10:22
  • @georgeawg, thank you answering, just updated the snipped, "attrs.enterKey" is what I want. However, this isn't the problem, has the issue still persists. Commented May 27, 2018 at 13:52
  • 1
    The AngularJS <input> directive uses the input event to update the model. Commented May 27, 2018 at 14:03
  • Thank you @georgeawg, that was it. Meanwhile, because I also want to support IE11 I'll have to use change instead, otherwise input would do. Commented May 27, 2018 at 18:15

1 Answer 1

0

To update fooValue the input event is required to be fired. In case IE11 support is needed, use the change event.

The following snipped shows it working:

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

app.component('foo', {
  template: '<input ng-model="$ctrl.fooValue" enter-key="$ctrl.onEnter()" />',
  controller: function() {
    this.onEnter = function() {
      // this.fooValue is now updated with input value
    };
  },
  bindings: {
    fooValue: '@'
  }
});

app.directive('enterKey', function() {
  return {
    restrict: 'A',
    link: function(scope, element, attrs) {
      element.bind("keydown keypress", function(event) {
        var keyCode = event.which || event.keyCode;

        // If enter key is pressed
        if (keyCode === 13) {
          scope.$apply(function() {
            // Evaluate the expression
            scope.$eval(attrs.enterKey);
          });
        }
      });
    }
  };
});

describe('test', function() {
  describe('foo', function() {
    beforeEach(module('app'));

    var element,
      inputElem;

    beforeEach(inject(function($compile, $rootScope) {
      var fooScope = $rootScope.$new();

      element = angular.element('<foo foo-value="foo1"></foo>');
      element = $compile(element)(fooScope);

      fooScope.$digest();
    }));

    it('should set fooValue with foo3', function() {
      var controller = element.controller('foo');
      inputElem = element.find('input');
      inputElem.val('foo3');
      inputElem.triggerHandler('input');  // fire the input event to update fooValue with 'foo3'
      // inputElem.triggerHandler('change'); for IE11 
      inputElem.triggerHandler({
        type: 'keydown',
        which: 13
      });

      expect(controller.fooValue).toBe('foo3');
    });
  });
});
<!DOCTYPE html>
<html ng-app="app">

<head>
  <link rel="stylesheet" href="//cdn.jsdelivr.net/jasmine/2.0.0/jasmine.css" />
  <script src="//cdn.jsdelivr.net/jasmine/2.0.0/jasmine.js"></script>
  <script src="//cdn.jsdelivr.net/jasmine/2.0.0/jasmine-html.js"></script>
  <script src="//cdn.jsdelivr.net/jasmine/2.0.0/boot.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.js"></script>
  <script src="https://code.angularjs.org/1.6.1/angular-mocks.js"></script>
</head>

<body>
</body>

</html>

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.