2013-03-11 59 views
11

我创建了一个ajax搜索页面,该页面将包含一个搜索输入框,一系列过滤器下拉菜单,然后是显示结果的UL。由于过滤器的搜索部分将位于页面上的一个独立位置,因此我认为创建一个处理协调输入和ajax请求到搜索服务器端的服务是一个不错的主意。然后可以由几个单独的控制器(一个用于搜索框和结果,另一个用于过滤器)调用。AngularJS - 使用服务作为模型,ng-repeat不更新

我正在努力挣扎的主要事情是调用ajax时刷新结果。如果我将ajax直接放在SearchCtrl控制器中,它可以正常工作,但是当我将ajax移出到某个服务时,它停止在调用服务上的find方法时更新结果。

我敢肯定,这是简单的我错过了,但我似乎无法看到它。

标记:

<div ng-app="jobs"> 
    <div data-ng-controller="SearchCtrl"> 
     <div class="search"> 
      <h2>Search</h2> 
      <div class="box"><input type="text" id="search" maxlength="75" data-ng-model="search_term" data-ng-change="doSearch()" placeholder="Type to start your search..." /></div> 
     </div> 
     <div class="search-summary"> 
      <p><span class="field">You searched for:</span> {{ search_term }}</p> 
     </div> 
     <div class="results"> 
      <ul> 
       <li data-ng-repeat="item in searchService.results"> 
        <h3>{{ item.title }}</h3> 
       </li> 
      </ul> 
     </div> 
    </div> 
</div> 

AngularJS:

var app = angular.module('jobs', []); 

app.factory('searchService', function($http) { 
    var results = []; 

    function find(term) { 
     $http.get('/json/search').success(function(data) { 
      results = data.results; 
     }); 
    } 

    //public API 
    return { 
      results: results, 
      find: find 
    }; 
}); 

app.controller("SearchCtrl", ['$scope', '$http', 'searchService', function($scope, $http, searchService) { 
    $scope.search_term = ''; 
    $scope.searchService = searchService; 

    $scope.doSearch = function(){ 
     $scope.searchService.find($scope.search_term); 
    }; 

    $scope.searchService.find(); 
}]); 

这是一个粗略的jsfiddle,我已经注释掉Ajax和我只是手动更新的结果变量作为一个例子。为了简洁起见,我没有包括滤波器下拉菜单。

http://jsfiddle.net/XTQSu/1/

我很新的AngularJS,所以如果我在完全错误的方式去了解它,请告诉我这样:)

回答

29

在您的HTML中,您需要引用在您的控制器的$ scope中定义的属性。要做到这一点的方法之一是在您的控制器绑定$scope.searchService.resultssearchService.results一次:

$scope.searchService.results = searchService.results; 

现在,这条线将工作:

<li data-ng-repeat="item in searchService.results"> 

在你的服务,使用angular.copy()而不是分配一个新的数组引用results,否则你的控制器的$范围将失去其数据绑定:

var new_results = [{ 'title': 'title 3' }, 
        { 'title': 'title 4' }]; 
angular.copy(new_results, results); 

Fiddle。在小提琴中,我将find()的最初调用注释掉了,所以当您在搜索框中输入内容时,您会看到更新发生。

+2

谢谢马克。这是'angular.copy'部分,这是难题的一部分。 – 2013-03-12 09:40:38

+1

这对我来说是完全意义上的。我曾在3个其他服务/控制器上工作,但他们只是我推动的阵列,所以绑定从未打破。如果您完全替换阵列/对象,则需要使用副本!谢谢! – LukeP 2014-10-13 22:19:11

1

的问题是,你永远更新您的范围内的结果。有许多方法来做到这一点,但根据您当前的代码,你可以先修改找到函数返回的结果:你的“公共的API”在

function find(term) { 
    $http.get('/json/search').success(function(data) { 
      var results = data.results; 

    }); 
    //also notice that you're not using the variable 'term' 
    //to perform a query in your webservice 
    return results; 
} 

你使用一个模块模式,使您searchService返回找到功能和结果一个数组,但你想使功能找到负责实际返回的结果。

设置,放在一边,只要您拨打doSearch()在你的范围,你要更新那些您searchService返回当前结果

$scope.doSearch = function(){ 
    $scope.searchService.results = searchService.find($scope.search_term); 
}; 

我更新了的jsfiddle我的想法,不起作用,但我添加了一些委员和日志来帮助您调试此问题。 http://jsfiddle.net/XTQSu/3/

+0

感谢您的努力。在这种情况下,我不希望'find'返回结果,因为结果在一个控制器中是需要的,而find()可能是从另一个控制器调用的。这是将结果保存在本地服务中而不是在控制器中的原因。缺少的是将服务中的结果绑定到使用它们的控制器上。正如Mark指出的那样,我没有任何限制,所以这就是为什么它没有更新。当我更新结果时,使用'angular.copy()'保持绑定完好无损。再次感谢您花时间回答。 – 2013-03-12 09:47:46