【问题标题】:Non-functioning view when sharing controller共享控制器时视图不起作用
【发布时间】:2013-07-13 08:37:32
【问题描述】:

我有一个简单的应用程序,它从 Flickr 获取图像并呈现它们。该应用程序分为两个视图,SearchViewPhotoListView。以前,当将这些视为一个视图时,一切正常,并且渲染了照片。现在,当共享控制器时,两者都会被渲染,但不会填充照片列表。在调试的时候,我可以看到照片确实被抓取了。

我是 Angular 的新手,所以我真的没有很好的猜测问题可能是什么,但可能这两个视图没有正确共享范围?

这是路由(使用ui-router):

// app.js

'use strict';

angular.module('pruApp', ['ui.state'])
    .config(function ($httpProvider, $stateProvider, $urlRouterProvider) {
        $urlRouterProvider.otherwise('/photos');
        $stateProvider
            .state('/', {
                url: '/photos',
                views: {
                    'SearchView': {
                        templateUrl: '/views/search.html',
                        controller: 'PhotoCtrl'
                    },
                    'PhotoListView': {
                        templateUrl: '/views/photo-list.html',
                        controller: 'PhotoCtrl'
                    }
                }
            });

        // Remove X-Requested-With header to enable CORS
        delete $httpProvider.defaults.headers.common['X-Requested-With'];
    });

与 Flickr 服务对话的控制器和工厂:

// photo.js

'use strict';

angular.module('pruApp')
    .controller('PhotoCtrl', function ($scope, PhotoFactory) {
        $scope.search = function() {
            PhotoFactory.getPhotos($scope.searchQuery).then(function (data) {
                $scope.photos = [];

                var parsedData = angular.fromJson(data);
                var items = parsedData.photos.photo;

                for (var i = 0; i < items.length; ++i) {
                    var photo = items[i];
                    $scope.photos.push({
                        title: photo.title,
                        image: 'http://farm' + photo.farm + '.staticflickr.com/' + photo.server + '/' + photo.id + '_' + photo.secret + '_m.jpg',
                        link: 'http://www.flickr.com/photos/' + photo.owner + '/' + photo.id
                    });
                }
            });
        };
    });

angular.module('pruApp')
    .factory('PhotoFactory', function ($http, $q) {
        return {
            _get: function(url) {
                var deferred = $q.defer();

                $http.get(url)
                    .success(function (data) {
                        deferred.resolve(data);
                    })
                    .error(function (data, status) {
                        deferred.reject('An error occured: ' + status);
                    });

                return deferred.promise;
            },
            getPhotos: function (searchQuery) {
                return this._get('http://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=<MY_KEY>&tags=' + searchQuery + '&format=json&nojsoncallback=1');
            }
        };
    });

这是视图被注入的地方:

<!-- index.html -->

<div class="main" role="main">
    <div class="search" ui-view="SearchView"></div>
    <div class="results" ui-view="PhotoListView"></div>
</div>

搜索模板:

<!-- search.html -->

<h2 class="struct">Search</h2>
<form>
    <fieldset>
        <div class="cell">
            <input type="search" name="search-query" class="search-query" placeholder="Search photos by tags (e.g. lolcat, rageface, bronie)" ng-model="searchQuery" required>
        </div>
        <div class="cell">
            <button type="submit" name="search-button" class="search-button" ng-click="search()">Search</button>
        </div>
    </fieldset>
</form>

照片列表模板:

<!-- photo-list.html -->

<h2 class="struct">Search results</h2>
<ul>
    <li ng-repeat="photo in photos">
        <h3>{{ photo.title }}</h3>
        <a href="{{ photo.link }}"><img ng-src="{{ photo.image }}" alt="{{ photo.title }}"></a>
        <p class="author">Author: <span>{{ photo.author }}</span></p>
    </li>
</ul>

【问题讨论】:

    标签: javascript angularjs


    【解决方案1】:

    所以您的问题似乎是您正在调用该方法来获取控制器的一个实例上的照片,但它不与您的另一个控制器共享数据。在第一次阅读时,我错过了您的工厂定义,但问题仍然是控制器范围内的变量位于不同的实例中。

    处理这个问题的方法是始终从工厂/服务返回一个承诺给控制器,在控制器中使用承诺分配范围。这样,如果服务已有数据可用,它将自动填充到您的控制器范围内,如果没有可用数据,则可以立即填充。

    确实,看起来您正在执行我在上一段中所说的操作,但我看不到在控制器中调用搜索功能的位置。本质上,您应该在控制器中有一些东西直接从服务中填充 $scope.photos 数组。然后,您应该分别拥有搜索功能,该功能会触发对传递参数的服务的调用。

    另一种选择是 $watch 您在工厂/服务中的属性,并在更改时更新控制器 $scope 中的变量。

    angular.module('pruApp')
        .factory('PhotoFactory', function ($http, $q) {
            return {
                photos: [],
                _get: function(url) {
                    var deferred = $q.defer();
    
                    $http.get(url)
                        .success(function (data) {
                            this.photos = [];
    
                            var parsedData = angular.fromJson(data);
                            var items = parsedData.photos.photo;
    
                            for (var i = 0; i < items.length; ++i) {
                                var photo = items[i];
                                this.photos.push({
                                    title: photo.title,
                                    image: 'http://farm' + photo.farm + '.staticflickr.com/' + photo.server + '/' + photo.id + '_' + photo.secret + '_m.jpg',
                                    link: 'http://www.flickr.com/photos/' + photo.owner + '/' + photo.id
                                });
                            }
                            deferred.resolve(data);
                        })
                        .error(function (data, status) {
                            deferred.reject('An error occured: ' + status);
                        });
    
                    return deferred.promise;
                },
                getPhotos: function (searchQuery) {
                    return this._get('http://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=<MY_KEY>&tags=' + searchQuery + '&format=json&nojsoncallback=1');
                }
            };
        });
    

    在控制器中

    angular.module('pruApp')
        .controller('PhotoCtrl', function ($scope, PhotoFactory) {
                $scope.$watch(function () { return PhotoFactory.photos; }, function(data) {
                     $scope.photos = data;
                }); // initialize the watch
    
                $scope.search = function() {
                    PhotoFactory.getPhotos($scope.searchQuery);
                };
            }
        });
    

    【讨论】:

    • 为了澄清,search() 在搜索视图中单击按钮时被调用。 $scope.search 被声明为控制器中的第一个也是唯一一个函数。
    • @Jorum,我的意思是它没有在控制器中调用并且控制器有多个实例,我会看看我是否可以修改你的代码以显示我认为它应该如何被处理。如果在用于 view1 的控制器上调用 search(),则不会为 view2 上的控制器调用它,因此视图不会填充其范围的照片数组。
    • 一个例子会很棒。另外,感谢您的努力。就像我说的那样,我是 Angular 的新手,仍在尝试掌握这些概念。
    • @Jorum 查看我在上面所做的编辑可能存在语法错误,因为我只是在编辑所以如果遇到无法调试的错误,请告诉我。基本上我将您的一些数据处理代码移到服务中并将数据存储在服务中,然后在控制器中我只是观察服务属性的变化。
    • 还有另外几种方法可以做到这一点,但我发布了我在实践中实际使用的方法。
    猜你喜欢
    • 2017-02-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-06
    相关资源
    最近更新 更多