点击范围的更改未在我的应用中更新

时间:2013-11-12 14:30:18

标签: angularjs

上周开始使用Angular,阅读/观看了许多教程,我正在尝试构建新闻源类型的应用程序。

这是瘦的:我有一个从服务器获取数据的服务。在新闻源本身,我有两个控制器:一个在其范围内拥有整个新闻源,另一个在每个新闻源文章中都有一个实例。如果用户单击单个帖子上的图标,则应调用已注入两个控制器的服务,然后广播主控制器选择的消息。然后,主控制器更新过滤器中的变量,根据用户的选择过滤新闻源内容。

问题在于:除了主控制器不更新HTML中的绑定变量外,一切正常。我已经阅读了关于ng-repeat和相关斗争中的双向绑定的每篇SO文章,但在我的情况下,绑定变量超出了ng-repeat,因此我发布了。

代码:

services.factory('filterService', function() {
var filterService = {};

filterService.filterKey = '';

filterService.getFilter = function() {
    return filterService.filterKey;
};

filterService.setFilter = function(name) {
    filterService.filterKey = name;
    $rootScope.$broadcast('changeFilter');
};

return filterService;

});

app.controller('CommentCtrl', function($scope, $timeout, $http, filterService) {

$scope.setSearchParam = function(param) {
    alert('clicked: ' + param)
    filterService.setFilter(param);
}



app.controller('FeedCtrl', function($scope, articles, filterService, $timeout) {
$scope.articles = articles;
$scope.model = {
    value: ''
};
$scope.$on('changeFilter', function() {
    console.log(filterService.filterKey);
    $scope.model.value = filterService.filterKey
    }  
}); 

});

<div class="articles">
    <div class="articleStub" ng-repeat="article in articles|filter:model.value">

        <div ng-controller="CommentCtrl">
            <div class="{{article.sort}}">
                <div class="leftBlock">
                    <a href="#" ng-click="setSearchParam(article.sort)">
                        <div class="typeIcon">
                            <i ng-class="{'icon-comments':article.question, 'icon-star':article.create, 'icon-ok-sign':article.notype}"></i>
                        </div>
                    </a>

注意:在app.config $ routeprovider函数中调用FeedCtrl控制器,无论它叫什么

编辑添加:警报和控制台检查两者都有效,所以我假设问题不在filterService或CommentCtrl中。

这是Plnkr:http://plnkr.co/edit/bTit7m9b04ADwkzWHv88?p=preview

2 个答案:

答案 0 :(得分:2)

我正在添加另一个答案,因为另一个仍然有效,但不是唯一的问题!

看了你的代码,你的问题有两个:

  • 您有href="#"

    的链接

    这导致路由代码重新运行,并且它在同一页面上创建了一个新的控制器实例,但使用的是不同的范围。我发现这一点的方法是将调试行console.log("running controller init code for $scope.$id:" + $scope.$id);添加到script.js的{​​{1}}空白行下面。model.value。您会注意到它在每次点击时都会运行,并且范围的$id每次都不同。我不完全理解之后发生的事情,但是让两个相同的控制器照看页面的相同位置不是一件好事!

因此,考虑到这一点,我设置了href=""。这有点破坏了按钮的渲染,但它确实解决了实例化多个控制器的问题。但是,这不能解决问题......另一个问题是什么?

  • angular.element.bind('click',....)正在“在角度世界之外”运行

    这个有点复杂,但基本上对于角度数据绑定起作用,当scope发生变化时,角度需要知道。大多数情况下,它通过角度函数(例如内部控制器,内部ng-*指令等)自动处理,但在某些情况下,当从浏览器触发事件​​时(例如XHR,点击,触摸等) ,你必须告诉角度有些变化。您可以使用$scope.$apply()执行此操作。有一些关于这个主题的好文章,所以我建议稍微阅读一下(先试试here)。

有两个解决方案 - 一个是使用ng-click指令,它将click事件包装在$scope.$apply中(并且还有一个额外的优点,即你的标记更具语义性)或者另一种是自己做。为了尽量减少对代码的更改,我将click代码包裹在scope.$apply中:

element.bind('click', function() {
  // tell angular that it needs to 'digest' the changes you're about to make.
  scope.$apply(function(){
    var param = scope.article.sort;
    filterService.setFilter(param);
  })                
});

以下是您的代码的有效版本:http://plnkr.co/edit/X1AK0Bc4NZyChrJEknkN?p=preview

注意我还在列表中设置了一个过滤器。当没有设置过滤器时,您可以轻松地通过按钮清除隐藏的按钮:

<button ng-click="model.value=''" ng-show="model.value">Clear filter</button>

希望这会有所帮助:)

答案 1 :(得分:0)

我实际上认为问题不是你的model.value没有得到更新 - 所有代码看起来都很好。

我认为问题在于你的filter

<div class="articleStub" ng-repeat="article in articles|filter:model.value">

此过滤器会将任何对象与包含model.value的任何字段进行匹配。你真正想做的是以下几点:

<div class="articleStub" 
  ng-repeat="article in articles|filter:{sort: model.value}:true">

指定您只想匹配每篇文章的sort属性。最终的true参数意味着它也只允许严格匹配,因此ededward不匹配。

请注意,| filter:{sort: model.value}:true是一个角度表达式,:就像JavaScript逗号。如果你想象它在JavaScript中更像是:|('filter',{sort:model.value}, true)其中|是一个特殊的'在这里注入过滤器'功能..

修改

我发现很难调试你的例子而没有在我面前的工作代码。如果你可以把它变成一个plunker我可以帮助更多,但与此同时,我认为你应该尝试通过使用不同的方法使你的代码更简单。

我创建了a plunker,它显示了按您点击的项目过滤列表的简便方法。我使用的代码非常少,所以希望它很容易理解?

我还建议您将Feed项目改为directive。这些指令可以有自己的控制器,这样就可以防止你不得不重复ng-controller