3

上周开始使用 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>

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

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

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

4

2 回答 2

2

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

查看您的代码后,您的问题有两个方面:

  • 你有一个链接到href="#"

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

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

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

    这个有点复杂,但基本上要使角度数据绑定起作用,角度需要知道何时scope更改。大多数情况下,它是由角度函数自动处理的(例如内部控制器、内部ng-*指令等),但在某些情况下,当从浏览器触发事件​​时(例如 XHR、点击、触摸等),您必须告诉角度有些东西已经改变了。您可以使用$scope.$apply(). 有几篇关于这个主题的好文章,所以我建议您阅读一下(尝试从这里开始)。

有两种解决方案 - 一种是使用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>

希望这可以帮助 :)

于 2013-11-13T10:47:24.930 回答
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参数意味着它也只允许严格匹配,所以ed不会匹配edward

请注意,这| filter:{sort: model.value}:true是一个角度表达式,:s 就像 JavaScript 逗号。如果你用 JavaScript 来想象它,它会更像: 一个特殊的“在此处注入过滤器”函数|('filter',{sort:model.value}, true)在哪里......|

编辑

我发现如果没有工作代码就很难调试您的示例。如果你能把它变成一个笨拙的人,我可以提供更多帮助,但与此同时,我认为你应该尝试通过使用不同的方法来降低你的代码复杂性。

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

我还建议将您的提要项制作成directive. 这些指令可以有自己的控制器,这样就可以防止你不得不对ng-controller.

于 2013-11-12T15:02:57.343 回答