2

我有一个简单的 google-chrome 扩展应用程序。我正在使用书签,它存在于清单文件中。首先,我在控制器中使用 chrome 书签 api,它运行良好。但我决定使用工厂来获得清晰的代码和最佳实践。

我的 index.html 文件

<!DOCTYPE html>
<html lang="en" ng-app="BookmarksSharer" ng-csp>
<head>
    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
    <title>bokmarks sharer</title>
    <link rel="stylesheet" href="/css/main.css"/>
    <script src="/javascript/jquery-2.1.1.min.js"></script>
    <script src="/javascript/angular.min.js"></script>
    <script src="/javascript/bookmark_sharer.js"></script>
    <script src="/javascript/MainController.js"></script>
    <script src="/javascript/BookmarkService.js"></script>
</head>
<body>
    <div id="main_popup" ng-controller="MainController">
        <p>Bookmarks</p>
        <ul>
            <li ng-repeat="bookmark_folder in bookmarks_folders" id="{{bookmark_folder.title}}">
                {{bookmark_folder.title}}
                <ul ng-repeat="bookmarks in bookmark_folder">
                    <li ng-repeat="bookmark in bookmarks | filter">{{bookmark.title}}</li>
                </ul>
            </li>
        </ul>
    </div>
</body>
</html>

bookmark_sharer.js 很简单

var app = angular.module("BookmarksSharer", []);

MainController.js 也很简单。

app.controller('MainController',['$scope', 'bookmarkFactory', function($scope, bookmarkFactory){
    $scope.boormarks_folders = bookmarkFactory.folders;
}]);

还有我的工厂

app.factory('bookmarkFactory', function () {
    var bookmarks_folders;
    function allBookmarksFolders(){
        chrome.bookmarks.getTree(function(bookmarks_tree){
            bookmarks_folders = bookmarks_tree[0].children;
        });

        return bookmarks_folders;
    }

    return {
        folders: allBookmarksFolders()
    };
});

为什么 $scope.bookmarks_folders 未定义?

ExpertSystem 您的代码也无法正常工作。简单的解决方案是

app.controller('MainController',['$scope', function($scope){
    chrome.bookmarks.getTree(function(nodes){
        $scope.bookmarks_folders = nodes[0].children;
        $scope.$apply();
    })
}]);

但我想使用工厂或服务来组织我的代码。

4

1 回答 1

4

chrome.bookmarks.getTree()是异步的,所以到getAllBookmarks()函数返回时,bookmarks_folders它是未定义的。

您的服务公开了一个属性 ( folders),它绑定到 的结果allBookmarksFolders(),唉undefined

由于此操作是异步的,因此您的服务应该返回一个 promise,因此控制器可以使用该 promise 并在返回时获取实际数据:

// The service
app.factory('bookmarkFactory', function ($q) {
    function retrieveAllBookmarksFolders() {
        var deferred = $q.defer();
        chrome.bookmarks.getTree(function (bookmarks_tree) {
            deferred.resolve(bookmarks_tree[0].children);
        });
        return deferred.promise;
    }

    return {
        foldersPromise: retrieveAllBookmarksFolders()
    };
});

// The controller
app.controller('MainController', function($scope, bookmarkFactory){
    bookmarkFactory.foldersPromise.then(function (bookmarks_folders) {
        $scope.boormarks_folders = bookmarks_folders;
    });
});

主要问题源于(在您的实现中)您返回绑定到bookmarks_folders该点的值,然后重新分配bookmarks_folders以保存对不同对象(bookmarks_tree[0].children)的引用。

服务内部的事件流有点像这样:

  1. bookmarks_folders被声明(并初始化为未定义)。
  2. allBookmarksFolders()被执行并返回(仍然未定义)bookmarks_folders
  3. folders被分配了对当前所引用的对象的引用bookmarks_folders(即未定义)。
  4. getTree()回调执行并分配给bookmarks_folders不同对象的引用 ( ) bookmarks_tree[0].children。那时对此folders一无所知,并继续引用先前的值(未定义)。

另一种方法($resourcebtw 使用的方法)是不为 分配新的引用bookmarks_folders,而是修改已经引用的对象。

// The service
app.factory('bookmarkFactory', function () {
    var bookmarks_folders = [];   // initialize to an empty array
    function allBookmarksFolders(){
        chrome.bookmarks.getTree(function(bookmarks_tree){
            // Here we need to modify the object (array)
            // already referenced by `bookmarks_folders`

            // Let's empty it first (just in case)
            bookmarks_folders.splice(0, bookmarks_folders.length);

            // Let's push the new data
            bookmarks_tree[0].children.forEach(function (child) {
                bookmarks_folders.push(child);
            });
        });

        return bookmarks_folders;
    }

    return {
        folders: allBookmarksFolders()
    };
});
于 2014-05-31T14:56:00.190 回答