在 NG-Repeated 之前,如何编辑从 Angular API 请求调用的数据?

How do I edit data called from Angular API request, before is NG-Repeated?

第一个 Stack Overflow post!

我正在努力了解 Angular,我已经使用 jQuery 多年,但我在工作中收到了使用它的请求。

我正在通过 HTTP 请求加载外部 JSON..

$http({
            method: 'GET',
            url: "/Api/News/GetNews?pageNumber=" + pageNumber
            }).then(function successCallback(response) {

              $scope.myData = response.data 

            }, function errorCallback(response) {

               showError()

            });
          }

这工作正常,内容显示在我的 NG-Repeat 中..

<div class="newsRow" ng-repeat="x in myData track by $index">

   <div class="col-md-3">
      <a href="{{x.Url}}">Read more</a>
    </div>

    <div class="col-md-9">
      <h3><a href="{{x.api.Url}}">{{x.Title}}</a></h3>
      <p>{{x.Excerpt}}/p>
      {{x.NewsItemVersion}}
    </div>

</div>

唯一的问题是新闻ID(NewsItemVersion)在显示之前需要格式化,需要四舍五入为整数。

如何拦截这个值并在显示之前更改它?

在 ajax 调用的回调中处理它:

$http({
        method: 'GET',
        url: "/Api/News/GetNews?pageNumber=" + pageNumber
        }).then(function successCallback(response) {
          response.data.forEach(function (item) {
             item.NewsItemVersion = Math.abs(item.NewsItemVersion);
          });

          $scope.myData = response.data 

        }, function errorCallback(response) {

           showError()

        });
      }

我建议将检索数据和修改部分分开。您可以为此创建 2 个服务和一个控制器以将数据传递给视图。

例如

这里是controller,它只知道newsService,不关心解析id什么的,只管加载。

app.controller('myController', ['$scope', 'newsService', function($scope, newsService) {
    $scope.pageNumber = 1;

    newsService.loadNews(pageNumber)
        .then(function(news) {
            $scope.news = news;
        }, function(err) {
            console.log(err);
        })      
}]);

您的服务负责处理新闻并为控制器或任何其他进一步使用做准备。它知道会出现什么样的响应以及如何处理它。在您的情况下,您可以浏览 news 列表并为所有 NewsItemVersion 调用 parseInt。所以你只有一个地方可以修改它。

app.factory('newsService', ['$q', 'requestService', function($q, requestService) {
    return {
        loadNews: function(pageNumber) {
            var defer = $q.defer();
            requestService.getNews(pageNumber)
                .then(function(data) {
                    data.forEach(function(item) {
                        item.NewsItemVersion = parseInt(item.NewsItemVersion, 10);                      
                    });
                    defer.resolve(data);
                }, function(err) {
                    defer.reject(err);
                });
            return defer.promise;
        }
    }
}]);

最后 requestService 或调用任何你想要的 :) httpService, backendService 等。这是一个非常薄的层,它知道如何以及向何处发送请求以获取信息来自后端。

app.factory('requestService', ['$http', '$q', function($http, $q, requestService) {

    var urls = {
        'getNews': '/Api/News/GetNews?pageNumber=%pageNumber%'
    };

    return {        
        getNews: function(pageNumber) {
            var requestUrl = urls['getNews'].replace('%pageNumber%', $pageNumber);
            var defer = $q.defer()
            $http({ 
                method: 'GET', 
                url: requestUrl
            }).then(function(response) {
                defer.resolve(response.data);
            }, function() {
                defer.reject('Some meaningful message');
            });
            return defer.promise;
        }
    }
}]);

这里有两个主要选项。要么像 A Macdonald 的上述回答那样直接转换数据,要么使用过滤器。

如果您确定在应用中只需要转换后的数据,而永远不需要原始浮点数,我建议您选择第一个选项。 (我刚刚注意到您对该答案的评论,说您似乎根本无法影响 $scope 变量。如果是这种情况,我建议您创建一个 plunker 或向我们展示更多您的实现,因为这确实应该可以。)

如果您只需要四舍五入的数字用于显示目的,并且仍将在您的逻辑中使用原始浮点数,则有两种方法:您可以在 $scope 上创建一个额外的 属性 调用,例如,roundedNewsItemVersion。或者您可以创建自定义 Angular 过滤器。这是该语言的一项非常强大的功能,您可以使用它使用简单的管道来转换任何数据。

angular.module('yourApp', []).filter('absNumber', function() {
  return function(input) {
    // Optionally check wether input is a number, etc...
    return Math.abs(input);
  };
});

然后您可以像这样在您的代码中使用此过滤器:

<div class="col-md-9">
  <h3><a href="{{x.api.Url}}">{{x.Title}}</a></h3>
  <p>{{x.Excerpt}}/p>
    {{x.NewsItemVersion | absNumber}}
</div>

使用自定义过滤器,您可以轻松转换视图中的任何数据,而无需实际更改数据本身。当然,此过滤器是完全模块化的,您可以在整个应用程序的不同位置继续使用它。现在我知道这一切可能有点矫枉过正,但我​​希望它能让你更深入地了解是什么让 AngularJS 成为一个强大的框架。

顺便说一句,我还建议放置任何处理获取数据的异步代码,例如服务中的 $http 请求,而不是控制器。 Angular 中的控制器应该只用于向 $scope 添加东西,而不是执行任何有意义的逻辑。

谢谢大家的回答。我发现最简单的答案是按照 A Macdonald 的建议使用 forEach 函数,它实际上创建了一个新的数据数组,其中包含操作内容。我认为这是更 jQuery 类型的方式,但它对我有用。

$http({
            method: 'GET',
            url: "/Api/News/GetNews?pageNumber=" + pageNumber
            }).then(function successCallback(response) {

            var newsItems=[]

            angular.forEach(response.data, function(value, key) {

                  newsItems.push({
                    Title : response.data[key].Title, 
                    Excerpt : response.data[key].Excerpt,
                    Image : response.data[key].Image,
                    Url : response.data[key].Url,
                    NewsItemVersion :  Math.abs(response.data[key].NewsItemVersion)
                  })

            });

            $scope.myData = newsItems;


            }, function errorCallback(response) {

               showError()

            });
          }

此方法很有用,因为它允许在数据呈现之前对其进行操作,因此您可以在数据显示之前将变量、计数器等添加到数据中。