2

first Stack Overflow post!

I'm trying to get my head around Angular, i've used jQuery for years, but im having requests in work to use it.

I'm loading in external JSON through a HTTP reqest..

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

              $scope.myData = response.data 

            }, function errorCallback(response) {

               showError()

            });
          }

This is working fine and the content is displaying in my 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>

The only issue is the news ID (NewsItemVersion) needs to be formatted before it is displayed, it needs to be rounded to an integer.

How do I intercept this value and change it before it is displayed?

4 Answers 4

1

I would suggest to separate part of retrieving data and modifying. You can create 2 services for that and one controller to pass data to view.

e.g

Here is controller, it knows only about newsService and does not care about parsing id or whatever, just load.

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);
        })      
}]);

Your service responsible for processing news and preparing them for controller or any other further usage. It knows what kind response will come and how to process it. In your case you can go through news list and call parseInt for all NewsItemVersion. So you have only one place where you modify it.

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;
        }
    }
}]);

And finally requestService or call whatever you want :) httpService, backendService etc. It is very thin layer which knows how and where to send request in order to get information from backend.

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;
        }
    }
}]);
Sign up to request clarification or add additional context in comments.

Comments

0

You have two main options here. Either you transform the data directly, as in the above answer of A Macdonald, or you use a filter.

If you're sure that you will only need the transformed data in your app, and you'll never need the original floating number, I'd suggest going with that first option. (I just noticed your comment on that answer, saying you can't seem to affect the $scope variable at all. If this is the case, I suggest you create a plunker or show us a bit more of your implementation, as this really should work.)

If you only need the rounded number for display purposes, and will still use the original floating number in you're logic, there are two approaches: You can create an additional property on the $scope called, for example, roundedNewsItemVersion. Or you can create a custom Angular filter. This is a really powerful feature of the language which you can use to transform any data, using a simple pipeline.

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

You can then use this filter in your code like this:

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

With custom filters, you can easily transform any data in your view, without actually changing the data itself. Of course, this filter is completely modular and you can continue to use it on different locations throughout your app. Now I know all this might be a bit of an overkill, but I hope it gives you some more insight into what exactly makes AngularJS a powerful framework.

By the way, I'd also suggest placing any asynchronous code that deals with getting data like your $http request in a service, instead of a controller. Controllers in Angular should only be used to add stuff to the $scope, not perform any meaningful logic.

Comments

0

handle it within the callback for the ajax call:

$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()

        });
      }

4 Comments

0 down vote accept That doesnt seem to work, in fact I cant seem to affect it at all, even if i try... response.data.NewsItemVersion = "hello" it displays the returned number.
if you run console.log response.data before and after setting it can you see why it's not setting? Could be simple typo or vals could be stale if it is setting ok and you might need to wrap the $scope.myData in a $scope.$apply(function () { $scope.myData = response.data; });
The issue is the returned JSON has multple news objects in, so if I console log the returned data it returns a series of objects. In my old jQuery way of thinking I would have a 'each' type function within the response.
of course sorry missed the array - do it inside a forEach then... but the principle remains the same - this is where to update data before it hits the template - or use a filter on the fly if you want data untouched (as suggested below by @onomanatee
0

Thanks everyone for the answers. I found the simplest answer was to use the forEach function as advised by A Macdonald, it essentially created a new data array with the manipulated content in it. I think this is the more jQuery type way of doing it, but it works for me.

$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()

            });
          }

This method is useful as it allows the manipulation of the data before it is rendered out, so you could add variables, counters etc to the data before it is displayed.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.