2014-01-09 26 views
2

我正在用jQuery開發一個類似todo的應用程序,但我想切換到Angular。是否可以在按鍵之後但在鍵控之前更新模型?

有一個用於添加新項目的輸入字段,但只要在該輸入中鍵入任何內容,關鍵筆劃及其後的關鍵筆劃就會有效地移至現有項目組中的新項目。這意味着新的項目輸入文本框始終保持爲空。更好地顯示解釋:

http://jsfiddle.net/29Z3U/4/(許多細節已刪除,但我所指的應用程序的方面是演示)。

<h1>Song List</h1> 
<form id="songs"> 
    <ul id="sortable_songs"></ul> 
</form> 

<ul id="new_song"> 
    <script id="song_form_template" type="text/x-handlebars-template"> 
     <li class="song" id="{{song_id}}"> 
      <input type="text" placeholder="enter song" autofocus />       
     </li> 
    </script> 
</ul> 

一些jQuery的:

var template = Handlebars.compile($('#song_form_template').html()), 

    counter = (function(){var i=0; return function(){return ++i};})(), 

    cloneNewSong = function(){ 
     var count = counter(), 
      templateVals = {song_id: 'song_' + count}; 
     $('ul#new_song').append(template(templateVals)); 
    }, 

    addSong = function(event){ 
     //exclude certain keys here 
     cloneNewSong(); 
     container = $(event.target).closest('li.song'); 
     container.appendTo('ul#sortable_songs'); 
     $(event.target) 
      .removeAttr('placeholder') 
      .focus(); //what I just typed disappears without this! why? 
    }; 

$('ul#new_song').on('keypress', 'input', addSong); 
cloneNewSong(); 

注意的是,新的項目輸入文本框始終保持空,重點表現爲它應該這樣你就可以繼續輸入而中斷。

應用程序代碼變得冗長,我甚至還沒有試圖顯示從JSON派生的歌曲的現有列表。當然,在Angular中,ngRepeat使這一切變得簡單。然而,我在一個角版本嘗試不起作用:http://plnkr.co/edit/xsGRiHFzfsVE7qRxgY8d?p=preview

<!DOCTYPE html> 
<html ng-app="songListApp"> 
    <head> 
    <script src="//code.angularjs.org/1.2.7/angular.js"></script> 
    <link href="style.css" rel="stylesheet" /> 
    <script src="script.js"></script> 
    </head> 

    <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" /> 
     </li> 
    </ul> 

    <form> 
     <input 
      ng-keypress="newSong(new_song)" 
      ng-model="new_song.title" 
      placeholder="enter song" autofocus 
     /> 
    </form> 

    </body> 
</html> 

JS:

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

myapp.controller('songListController', function($scope){ 
    songs = [ 
     {"song_name":"song 1","more_info":""}, 
     {"song_name":"song 2","more_info":""}, 
     {"song_name":"song 3","more_info":""} 
    ]; 
    $scope.songs = songs; 

    $scope.newSong = function(new_song){ 
     var song = {"song_name": new_song.title, "more_info":""}; 
     songs.push(song); 
     new_song.title = ''; 
    }; 
}); 

即使解決重點管理的問題之前,我注意到角模型的更新總是落後通過一次擊鍵。我認爲這是因爲按鍵事件發生了before the character is inserted into the DOM

我意識到,從按鍵切換到按鍵會改變一些東西,但最初的設計是基於按鍵的響應。

我想自定義指令綁定到input event但是我所希望的東西不規矩:http://plnkr.co/edit/yjdbG6HcS3ApMo1T290r?p=preview

我注意到,在angularjs.org第一個代碼示例(基本無控制器綁定)沒有按似乎沒有受到我所擁有的問題的影響 - 示例模型會在發佈密鑰之前更新。

回答

1

解決:)順便說一句。整潔的組件!這裏是plunkr:http://plnkr.co/edit/wYsFRUcqTZFv5uIE0MWe?p=preview

的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> 

我已經改變了NG-按鍵功能,讓一首新歌在控制器完全建立。也不是新的指示焦點 - 如果當前歌曲是新創建的歌曲,則輸入字段獲得焦點。

控制器:

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(); 
    } 
    }; 
}); 

肯定一般,讓每個人的表情可以觸發焦點。

+0

I」我在IE11和Chrome 32上試過了;它僅適用於輸入第一首歌 - 可以再看一次嗎? – KnewB

+0

@KnewB這部分沒有工作。鉻被測試。 IE11 - 我沒有IE – michael

+0

@KnewB對不起。這是發佈之前的最新優化。函數名稱必須是'createNewSong'而不是'newSong'。 – michael

6

雖然有一個被接受的答案,但我提出了一個不同的方法,這個方法簡單得多,受污染的控制器較少。

首先,控制器。這很簡單。

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 
/> 

講解,

  1. 當一個鍵被按下時,它創建一首歌曲並集中在歌曲列表,createAndFocusIn(songs)
  2. create-and-focus-in指令規定了scope.createAndFocusIn(),這樣控制器就不必具有這個功能,除非使用這個指令。它接受的選擇,在這裏創造新的元素,在這種情況下,#songs input

最後,但最重要的是,指令部分:

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(); 
     }); 
    }; 
    }; 
}); 
在指令

,它是不是做別的不多,除了是由屬性指定。

就是這樣。

這是工作演示:http://plnkr.co/edit/mF15utNE9Kosw9FHwnB2?p=preview

---- ----編輯 @KnewB表示不會在FF工作。 Chrome/FF的工作版本在這裏。當按下鍵

在FF,

  1. window.event未設置。我們需要通過參數
  2. event.keyCode不存在,我們需要同時檢查keyCode ||則charCode
  3. 值和焦點使光標移動到第一位置,所以需要第一焦點設置然後添加值

http://plnkr.co/edit/u2RtHWyhis9koQfhQEdW?p=preview

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); 
     }); 
    }; 
    }; 
}); 

$event現在通過:

<input ng-keypress="createAndFocusIn($event, songs)" 
    create-and-focus-in="#songs input" 
    placeholder="enter song" 
    autofocus 
/> 
+0

它在Chrome 31中效果很好,但在FF 26中不起作用(Linux) – KnewB

+0

FF26/Chrome31工作版本,只需傳遞$ event作爲參數,http://plnkr.co/edit/u2RtHWyhis9koQfhQEdW?p=preview – allenhwkim

+0

感謝您再次查看。恐怕FF版本仍然不起作用 - 新標題的第一個字符總是丟失 – KnewB

相關問題