Angularjs 是否可以在按键后但在按键前更新模型?

Angularjs 是否可以在按键后但在按键前更新模型?,angularjs,angularjs-ng-repeat,Angularjs,Angularjs Ng Repeat,我正在用jQuery开发一个类似todo的应用程序,但我想切换到Angular 有一个用于添加新项的输入字段,但只要在该输入中键入任何内容,键笔划(以及其后的笔划)就会有效地移动到现有项组中的新项。这意味着新项目输入文本框始终保持为空。与其解释,不如表现: (许多细节都被删除了,但我所指的应用程序的方面已经展示出来了) 请注意,“新项目输入”文本框始终保持为空,并且焦点的行为与它应该的一样,因此您可以继续键入而不中断 应用程序代码越来越长,我甚至还没有尝试显示从JSON派生的现有歌曲列表。当然,

我正在用jQuery开发一个类似todo的应用程序,但我想切换到Angular

有一个用于添加新项的输入字段,但只要在该输入中键入任何内容,键笔划(以及其后的笔划)就会有效地移动到现有项组中的新项。这意味着新项目输入文本框始终保持为空。与其解释,不如表现:

(许多细节都被删除了,但我所指的应用程序的方面已经展示出来了)

请注意,“新项目输入”文本框始终保持为空,并且焦点的行为与它应该的一样,因此您可以继续键入而不中断

应用程序代码越来越长,我甚至还没有尝试显示从JSON派生的现有歌曲列表。当然,在Angular中,ngRepeat使这变得容易。但是,我尝试的角度版本不起作用:

在解决焦点管理问题之前,我注意到Angular模型的更新总是滞后一次按键。我想这是因为按键事件发生了

我意识到从按键切换到按键会改变一切,但最初的设计是基于按键的反应能力

我尝试了一个自定义指令来绑定到,但事情并不像我希望的那样:

我注意到angularjs.org上的第一个代码示例(没有控制器的基本绑定)似乎没有遇到我遇到的问题-示例模型在密钥发布之前更新。

已解决:)顺便说一句。整洁组件!以下是普朗克:

html:

  <body ng-controller="songListController">
    <h1>Song List</h1>

    <ul id="songs">
        <li ng-repeat="song in songs">
            <input type="text" ng-model="song.song_name" focus-me="song === newSong"/>
        </li>
    </ul>

    <form>
        <input 
          ng-keypress="createNewSong()" 
          ng-model="newSongTitle" 
          placeholder="enter song" autofocus 
        />
    </form>

  </body>
正如您所看到的,新歌的创建由$timeout调用包装。这个调用将执行延迟到下一个摘要周期发生,因此没有挂起的事件可以中断我们

最后,该指令:

myapp.directive('focusMe', function(){
  return function($scope, element, attr){
    if($scope.$eval(attr.focusMe)){
        element[0].focus();
    }
  };
});

当然是通用的,这样每个表达式都可以触发焦点。

虽然有一个公认的答案,但我提出了一种不同的方法,它更简单,控制器污染更少

首先是控制器。这很简单

myapp.controller('songListController', function($scope, $timeout){
    $scope.songs = [
        {"song_name":"song 1","more_info":""},
        {"song_name":"song 2","more_info":""},
        {"song_name":"song 3","more_info":""}
    ];
}); 
第二,标签部分

<input ng-keypress="createAndFocusIn(songs)" 
  create-and-focus-in="#songs input"
  placeholder="enter song" 
  autofocus 
/>
在指令中,除了由属性指定之外,它并没有做很多其他事情

就这样

这是一个有效的演示:

----编辑---- @KnewB表示,它在FF中不起作用。这里是Chrome/FF工作版本

在FF中

  • 按下该键时未设置window.event。我们需要作为参数传递
  • event.keyCode不存在,我们需要同时检查keyCode | | charCode
  • 值和焦点使光标位于第一个位置,因此需要先设置焦点,然后添加值
  • $event
    现在已通过:

    <input ng-keypress="createAndFocusIn($event, songs)" 
        create-and-focus-in="#songs input"
        placeholder="enter song" 
        autofocus 
    />
    
    
    
    我在IE11和Chrome 32中尝试过;它只适用于输入第一首歌曲-你能再看一次吗?@KnewB-wich部分不起作用。对铬进行了测试。IE11-我没有IE@KnewB很抱歉在发布这篇文章之前,这是一个后期优化。函数名必须是
    createNewSong
    而不是
    newSong
    @KnewB solved-请参阅我的上一条评论和新的plunkr@KnewB我们必须等到angular完成一个摘要循环。在循环之后,我们可以确保输入值在newSongTitle属性中可用。使用$timout,我们只需要等待一个循环,该值在newSongTitle属性中安全可用。它在Chrome 31中运行良好,但在FF 26中不起作用(Linux)FF26/Chrome31工作版本,只需将$event作为参数传递,感谢再次查看。我担心FF版本仍然不起作用-新标题的第一个字符总是丢失。我不知道FF使用字符码。更新。
    myapp.controller('songListController', function($scope, $timeout){
        $scope.songs = [
            {"song_name":"song 1","more_info":""},
            {"song_name":"song 2","more_info":""},
            {"song_name":"song 3","more_info":""}
        ];
    
        $scope.newSongTitle = '';
        $scope.newSong = null;
    
        $scope.createNewSong = function(){
            $timeout(function(){
              $scope.newSong = {"song_name": $scope.newSongTitle, "more_info":""};
              $scope.songs.push($scope.newSong);
              $scope.newSongTitle = '';
            });
        };
    });
    
    myapp.directive('focusMe', function(){
      return function($scope, element, attr){
        if($scope.$eval(attr.focusMe)){
            element[0].focus();
        }
      };
    });
    
    myapp.controller('songListController', function($scope, $timeout){
        $scope.songs = [
            {"song_name":"song 1","more_info":""},
            {"song_name":"song 2","more_info":""},
            {"song_name":"song 3","more_info":""}
        ];
    }); 
    
    <input ng-keypress="createAndFocusIn(songs)" 
      create-and-focus-in="#songs input"
      placeholder="enter song" 
      autofocus 
    />
    
    myapp.directive('createAndFocusIn', function($timeout){
      return function(scope, element, attrs){
        scope.createAndFocusIn = function(collection) {
          collection.push({song_name: String.fromCharCode(event.keyCode)});
          $timeout(function() {
            element[0].value = '';
            var el = document.querySelectorAll(attrs.createAndFocusIn); 
            el[el.length-1].focus();
          });
        };
      };
    });
    
    myapp.directive('createAndFocusIn', function($timeout){
      return function(scope, element, attrs){
        scope.createAndFocusIn = function(ev, collection) {
          collection.push({});
          $timeout(function() {
            element[0].value = '';
            var el = document.querySelectorAll(attrs.createAndFocusIn);
            el[el.length-1].focus();
            el[el.length-1].value = String.fromCharCode(ev.keyCode||ev.charCode);
          });
        };
      };
    });
    
    <input ng-keypress="createAndFocusIn($event, songs)" 
        create-and-focus-in="#songs input"
        placeholder="enter song" 
        autofocus 
    />