AngularJS 工厂不工作?

AngularJS Factory Not Working?

所以我正在跟进 thinkster.io MEAN stack tutorial,我已经完成了 "Beginning Node" 之前的所有工作,但我的应用程序没有按预期工作。

查看 post 的评论时,工厂似乎没有正确共享其变量。标题(和 link,如果出现在 post 记录中)不显示,评论也不显示(如果 post 记录有相关评论)。

我仔细检查了我的代码并确保它遵循了教程,但我无法让它工作!我做错了什么?

indexV2.html

<html>
  <head>
    <title>My Angular App!</title>
    <link href="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet">
    <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.10/angular.min.js">         </script>
    <script src="http://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.10/angular-ui-router.js"></script>
    <script src="appV3.js"></script>
    <style> .glyphicon-thumbs-up { cursor:pointer } </style>
  </head>
<body ng-app="flapperNews">
  <div class="container">
    <div class="row">
      <div class="col-md-6 col-md-offset-3">

        <!-- where ui-router places templates, depending on the state -->
        <ui-view></ui-view>

       </div>
     </div>
   </div>
  </div>

  <script type="text/ng-template" id="/home.html">
    <!-- begin home.html inline template -->
    <div class="page-header">
      <h1>Flapper News</h1>
    </div>

    <form ng-submit="addPostV2()">
      <div class="form-group">
        <input class="form-control" type="text" placeholder="Title" ng-model="title"></input>
      </div>
      <div class="form-group">
        <input class="form-control" type="text" placeholder="Link" ng-model="link"></input>
      </div>
      <button type="submit" class="btn btn-primary">Add Post</button>
    </form>

    <div ng-repeat="post in posts | orderBy: '-upvotes'">
      <span class="glyphicon glyphicon-thumbs-up" ng-click="incrementUpvotes(post)"></span>
      <a href="{{post.link}}" ng-show="post.link">{{post.title}}</a>
      <span ng-hide="post.link">{{post.title}}</span>
      - upvotes: {{post.upvotes}}
      - <span>
        <a href="#/posts/{{$index}}">Comments</a>
      </span>
    </div>
  </script>

    <script type="text/ng-template" id="/posts.html">
      <!-- begin posts.html inline template -->
      <div class="page-header">
        <h3>
          <a ng-show="post.link" href="{{post.link}}">
            {{post.title}}
          </a>
          <span ng-hide="post.link">
            {{post.title}}
          </span>
        </h3>
      </div>

      <div ng-repeat="comment in post.comments | orderBy:'-upvotes'">
        <span class="glyphicon glyphicon-thumbs-up" ng-click="incrementUpvotes(comment)"></span>
          {{comment.upvotes}} - by {{comment.author}}
        <span style="font-size:20px; margin-left:10px;">
          {{comment.body}}
        </span>
      </div>

      <form ng-submit="addComment()" style="margin-top:30px;">
        <h3>Add a new comment</h3>
        <div class="form-group">
          <input type="text" class="form-control" placeholder="Comment" ng-model="body"></input>
        </div>
        <button type="submit" class="btn btn-primary">Post</button>
      </form>
    </script>

  </body>
</html>

appV3.js

// instantiate app, call it flapperNews, and declare the ui.router dependency
var app = angular.module('flapperNews', ['ui.router']);

// Set up states using the config function
app.config([
    '$stateProvider',
    '$urlRouterProvider',
    function($stateProvider, $urlRouterProvider) {
        $stateProvider
            .state('home', { // homepage state
                url: '/home',
                templateUrl: '/home.html',  // specify template (will be inline, in index.html, for this example)
                controller: 'MainCtrl'  // assign a controller
            })
            .state('posts', { // state that will display comments associated with a post
                url: '/posts/{id}', // id is a route parameter, made available to our controller
                templateUrl: '/posts.html',
                controller: 'PostsCtrl'
            });
        $urlRouterProvider.otherwise('home'); // redirect unspecified routes
    }
]);

// factory that will share the posts array with controllers
app.factory('posts', [function () {
    var o = {   // create object that will hold our posts array
        posts: []
    };
    return o;
}]);

// controller for "home" state
app.controller('MainCtrl', [
    '$scope',
    'posts',    // inject service into controller (by adding it as a parameter)
    function($scope, posts) {

        // bind (not just assign) the service variable to our scope
            // any changes in either will be reflected in the other
        $scope.posts = posts.posts;

        $scope.posts = [    // array of objects
            {title: 'post 1', upvotes: 3, url: ''}, // object (collection of properties) with 2 properties
            {title: 'post 2', upvotes: 4, url: ''},
            {title: 'post 3', upvotes: 1, url: ''},
            {title: 'post 4', upvotes: 2, url: ''},
            {title: 'post 5', upvotes: 6, url: ''}
        ];

        $scope.addPostV2 = function() {
            if(!$scope.title || $scope.title === '') {  // if empty or not set
                return;                                 // exit function
            }
            $scope.posts.push({ // push new object into array
                title: $scope.title,
                link: $scope.link,
                upvotes: 0,
                comments: [ // fake array
                    {author: 'Joe', body: 'Cool post!', upvotes: 0},
                    {author: 'Bob', body: 'Great idea but everything is wrong!', upvotes: 0}
                ]
            });
            $scope.title = '';  // empty the property (the model in the form)
            $scope.link = '';
        }

        $scope.incrementUpvotes = function(post) {  // pass the instance of post (passed in calling function, by reference - located in HTML)
            post.upvotes  += 1;
        }

    }
]);

// new controller for "posts" state
app.controller('PostsCtrl', [
    '$scope',
    '$stateParams',
    'posts',
    function($scope, $stateParams, posts) {

        $scope.post = posts.posts[$stateParams.id]; // Grab a post from posts, using the id parameter from $stateParams (in URL)

        $scope.addComment = function() {
            if($scope.body === '') {
                return;
            }
            $scope.post.comments.push({
                body: $scope.body,
                author: 'user',
                upvotes: 0
            });
            $scope.body = '';
        }

        $scope.incrementUpvotes = function(comment) {
            comment.upvotes += 1;
        }
    }
]);

感谢您提前的帮助

让我们检查一下您的代码:

$scope.posts = posts.posts;

在这行代码之后,你得到的是:

posts.posts -------> []
                     ^
$scope.posts --------|

所以 $scope.posts 和 posts.posts 都引用同一个空数组。

现在是下面一行:

$scope.posts = [    // array of objects
    {title: 'post 1', upvotes: 3, url: ''},
    ...
];

此行不填充服务和范围引用的数组。它将一个新数组分配给 $scope.posts。所以你最终得到

posts.posts -------> []

$scope.posts ------> [{title: 'post 1', upvotes: 3, url: ''}, ...]

因此,当您转到下一个屏幕并从 posts.posts 取回一个元素时:

$scope.post = posts.posts[$stateParams.id];

你什么也得不到,因为 posts.posts 仍然是原来的空数组。

而不是

$scope.posts = [    // array of objects
    {title: 'post 1', upvotes: 3, url: ''},
    ...
];

你需要

$scope.posts.push({title: 'post 1', upvotes: 3, url: ''});
...

然后您将填充控制器和服务引用的数组。

请注意,让详细信息页面依赖于列表页面无论如何都是一个坏主意:如果用户刷新详细信息页面,应用程序将从头开始,详细信息页面将找不到任何东西在数组中。您应该通过向服务器发送 GET 请求来获取 post,以获取 post.