js fiddle http://jsfiddle.net/suras/JzaV9/4/
这是我的指示
'use strict';
barterApp.directive('autosuggest', function($timeout, $http) {
return {
restrict: "E",
scope: {
modelupdate:"=",
suggestions:"=",
urlsend:"@"
},
template: '<ul><li ng-repeat="suggest in suggestions" ng-click="updateModel(suggest)">{{suggest}}</li></ul>',
link: function (scope, element) {
scope.$watch('modelupdate', function() {
$timeout(function(){
$http.post(scope.urlsend, {q:scope.modelupdate}).then(function(data){
scope.suggestions = data.data;
console.log(data.data);
});
}, 3000);
});
scope.updateModel = function(value){
scope.modelupdate = value;
scope.$parent.getBookInfo();
}
}
};
});
控制器
barterApp.controller('openLibraryCtrl', ['$scope','$http',function ($scope,$http) {
$scope.title = "";
$scope.getBookInfo = function(value){
if($scope.title == "" || $scope.title == " ") //here title is 'r'(previous value)
{
return;
}
$http.get('/book_info.json?q='+$scope.title).then(function(res){
if(Object.keys(res).length !== 0)
{
data = res.data
console.log(data);
}
});
}
//here title is 'rails' (updated value from directive).
//( used a watch function here on model update
// and checked it but inside getBookInfo it is still 'r' )
}]);
在更新模型函数中,我设置模型值并在父作用域上调用getBookInfo函数。但这里的事情是当(这是一个自动完成)我输入包含ng-model的输入字段中的值,例如'r'然后触发手表,我从帖子网址获取建议(让我们说“rails”, “摇滚”)并在指令中通过模板显示它。当我点击其中一个建议(比如'rails')时,它会触发指令中的updatemodel函数并设置模型值。这很好但是当我在父作用域中调用getBookInfo函数时,$ scope.title在函数内部是'r'(我在函数外部使用控制台日志检查模型值被正确更新为'rails')。再次当我点击'摇滚'时,getBookInfo中的模型值是'rails'。 我不知道最近发生了什么。 (我也在控制器中使用watch函数进行测试,模型正确更新,但函数调用getBookInfo保持回到之前的值)
view
<form ng-controller="openLibraryController">
<input type="text" ng-model="title" id="title" name="book[title]" />
<autosuggest modelupdate = "title" suggestions = "book_suggestions" urlsend="/book_suggestions.json"> </autosuggest>
</form>
答案 0 :(得分:1)
我没有深入研究它,但我怀疑(高度自信)在调用getBookInfo()
时父级范围尚未更新(因为我们仍处于中间位置) $ digest周期)。
不太好解决方案1:
您也可以立即更新父作用域(例如scope.$parent.title = ...
),但这显然是一个坏主意(出于与nr 2相同的原因,但更是如此)。
不太好解决方案2:
您可以将新标题作为参数传递给getBookInfo()
。
这两种解决方案都会导致控制器代码与指令代码混合,并在组件之间创建紧密耦合,从而减少可重用性并降低可测试性。
不太糟糕的解决方案:
您可以查看标题,并在其发生变化时致电getBookInfo()
:
$scope.$watch('title', function (newValue, oldValue) {
getBookInfo();
});
这样可以,但事实上完全没必要。
更好的解决方案:
Angular应该为我们处理所有保持同步的东西,它实际上是这样。你没有给出调用getBookInfo()
的目的的上下文,但我猜你打算用所选书上的一些信息来更新视图。
在这种情况下,你可以将它绑定到一个元素(使用ng-bind
),Angular将确保它正确和及时地执行。
E.g:
<div>Book info: <span ng-bind="getBookInfo()"></span></div>
此外,autosuggest
指令不必了解它。它应该只关心显示建议,操纵DOM(如果需要)并在每次点击建议时更新指定的模型属性(例如title
)。您使用更新后的值应该不做任何事情。
(顺便说一句,理想情况下,建议应由服务提供。)
以下是解决问题的修改示例(基于您的代码)。如上所述,有几种方法可以解决这个问题,我觉得这个方法更清洁,更符合“Angular方式”:
Book title: <input type="text" ng-model="book.title" />
<autosuggest modelupdate="book.title"
suggestions="book.suggest()"></autosuggest>
Book info: <span ng-bind="book.getInfo()"></span>
只需查看HTML(不知道JS中的内容),就可以很容易地知道发生了什么:
book.title
。autosuggest
内容提供book.suggest()
提供的建议并更新book.title
。span
显示有关该图书的信息。相应的指令如下所示:
app.directive('autosuggest', function() {
return {
restrict: 'E',
scope: {
modelupdate: '=',
suggestions: '&'
},
template:
'<ul><li ng-repeat="suggest in suggestions()" ' +
'ng-click="modelupdated = suggest">' +
'{{suggest}}</li></ul>'
};
});
如您所见,所有指令都知道如何检索建议和更新内容。
请注意,同一指令可用于任何类型的“建议”(即使是没有getBookInfo()
的指令);只需传入正确的属性(modelupdated
,suggestions
)。
另请注意,我们可以删除autosuggest
元素,并且应用程序将继续按预期工作(没有cource的建议),无需在HTML或JS中进行任何进一步修改(在您的版本中,书籍信息将停止更新)
您可以找到此 short demo here 的完整版。