5

I have the following on a page - full code in this Plunker

There is a custom onEnter directive that calls a function when enter is pressed on a chat form input. Code snippet below

//**HTML View**
<div ng-controller="mainCtrl">
    <ul>
      <li ng-repeat="chat in chatMessages">
        {{chat.username}}<br/>
           {{chat.message}}
        </li>
    </ul>
</div>
<form id="chatForm" name="chatForm" ng-controller="formCtrl">
    <label for="chat-username">User: </label>
    <input type="text" id="chat-username" class="chat__username" ng-model="chat.username" required>
    <label for="chat-input">Chat: </label> 
    <input type="text" id="chat-input" class="chat__input" on-enter="sendChat()" ng-model="chat.message" required>
    <a href="#" class="chat__submit icon-comments" id="chat-submit"  ng-click="sendChat()" ng-disabled="isChatValid()">Chatme</a>
</form>


//**Javascript**
app.controller('formCtrl',function($scope,Chats){
  $scope.sendChat = function() {
    if($scope.isChatValid()) {
      return;
    }
    console.log(JSON.stringify($scope.chat));
    var msg = {};
    angular.copy($scope.chat,msg);
    Chats.data.push(msg);       
  };

  $scope.isChatValid = function() {
    return $scope.chatForm.$invalid;
  };
});

Problem is the value of the input (message) is not saved into the scope model (chat). If I remove the onenter directive it works. What am I missing here? Any help will be great

4 Answers 4

11

Ok figured it out. Turns out when you define a scope object in your directive you create a new child scope. Details found here:

Directive with scope breaking ngmodel of an input

To fix this I removed the scope declaration and used the value of the function from attrs object.

Directive looks like this now:

app.directive('onEnter',function() {

  var linkFn = function(scope,element,attrs) {
    element.bind("keypress", function(event) {
      if(event.which === 13) {
        scope.$apply(function() {
      scope.$eval(attrs.onEnter);
        });
        event.preventDefault();
      }
    });
  };

  return {
    link:linkFn
  };
});

Full code in plunker

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

3 Comments

ah didn't see you also got it
personally I don't like this solution because it uses $eval
At the beginning I had the same opinion as @lamisti . However, I realized that this solution has big advantage - it does not create isolate scope, so there'll be no conflicts with other potential directives with isolate scope, that might be applied to the same DOM element.
2

For angular 1.2 i wrote like:

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

app.directive('onEnter', function() {
    return {
        scope: {onEnter: '&'},
        link: function(scope, element) {
            console.log(scope);
            element.bind("keydown keypress", function(event) {
                if(event.which === 13) {
                    scope.onEnter();
                    scope.$apply();
                }
            });
        }
    }
});

1 Comment

improved solution would be: scope.$apply(function(){ scope.onEnter(); });
1

You should use $parent to refer to the chat object like this

$parent.chat.message

Because you use the directive which declares a child scope. Here is the full html:

<input type="text" id="chat-input" class="chat__input" on-enter="sendChat()" ng-model="$parent.chat.message" required>

1 Comment

thanks for the answer @sza,I figured out it was a scope thing and solved it
0

In reply to @zool:

I had to modify your answer as follows to avoid my onEnter function being called twice:

[...]
if(event.which === 13) {
    event.preventDefault();
    scope.onEnter();
    scope.$apply();
}
[...]

Also see AngularJS form not submitting when pressing enter

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.