問題
在使用 typeahead 的時候,有這樣一個需求,當使用者選中其中一項的之後,將項目對應的 id 儲存到另外一個變數中,以後在提交表單的時候,將這個 id 發送到伺服器中。
但是,在 typeahead 中對於元素的操作,angularjs 沒有感知到,導致不能擷取最新的資料。
typeahead 中選擇資料之後的事件 itemSelected
在 typeahead 中,我們可以定義一個 itemSelected 的事件處理函數,在選中一個項目之後, typeahead 會觸發這個事件,我們在這個事件中可以擷取當前選中的元素,對應的值,已經顯示的提示文本。
這個函數的使用方式如下:
itemSelected: function (item, val, text) { console.info(val); }
整合到頁面中,我們可以如下配置 typeahead 的配置參數。
var option = { ajax: { url: '@Url.Action("AjaxService")', timeout: 300, method: "post", triggerLength: 3, preDispatch: function (query) { return { type: type, query: query }; }, preProcess: function (data) { return data; } }, display: "name", val: "id", itemSelected: function (item, val, text) { console.info(item); } }; $("#tbxName").typeahead(option);
但是,在使用 angularjs 的時候,會帶來一個問題,如果我們直接將這個 id 賦予某個元素,比如說輸入框的話,angularjs 是不能檢測到這個元素值的變化的,angularjs 通過監測元素的擷取焦點,失去焦點,change 等事件來感知輸入元素的變化,在通過代碼直接賦值的時候,會沒有這些事件的觸發。
原理
我們可以通過 angularjs 的自訂指令將 typeahead 封裝一下,在 itemSelected 事件觸發的時候,調用 angularjs 的 $apply 發出通知,這樣 angularjs 自然就可以感知到資料的變化了。
實現
本欄目更多精彩內容:http://www.bianceng.cnhttp://www.bianceng.cn/webkf/tools/
為了便於已經熟悉 typeahead 的朋友,繼續使用原來的方式進行配置,我們不修改配置方式。
指令的定義如下:
// 自訂指令 app.directive("typeahead", function () { var option = { restrict: "A", require: "?ngModel", scope: { option: "=typeahead" }, link: function (scope, element, attrs, ngModel) { // typeahead 的配置參數 var option = scope.option; // 將原來的 itemSelected 替換為 angularjs 的 itemSelected 函數 // 在使用者選擇了選項之後,通過 angularjs 執行 var itemSelected = option.itemSelected; option.itemSelected = function (item, val, text) { scope.$apply(function () { itemSelected(item, val, text); }) }; element.typeahead(option); } }; return option; });
scope 是自訂一個範圍,=typeahead 是將 typeahead 屬性的值取過來,剩下的處理就比較簡單了,我們將原來的 itemSelected 事件截獲過來,通過 scope.$apply 進行處理,這樣 angularjs 自然就可以擷取資料的變化了。
元素的定義如下,增加一個名為 typeahead 的 Attribute, 值就是配置參數對象,定義在 angularjs 的模型對象上。
<input typeahead ="typeaheadOption" ng-model="petName" type="text" />
下面是對應的指令碼。
// 控制器 app.controller("myController", function ($scope) { // 額外附加的參數 $scope.type = "java"; // 標準的使用方式 $scope.petName = "Cat"; $scope.petId = ""; // 使用標準的 typeahead 配置參數, 在元素上使用 typeahead Attribute 串連 $scope.typeaheadOption = { ajax: { url: '@Url.Action("AjaxService")', timeout: 300, method: "post", triggerLength: 3, preDispatch: function (query) { return { type: $scope.type, query: query }; }, preProcess: function (data) { return data; } }, display: "name", val: "id", itemSelected: function (item, val, text) { $scope.petId = val; } }; });
總結
使用 angularjs 的自訂指令,我們可以很容易地將 angularjs 之外的事件處理封裝到 angularjs 之中。