2

I need to develop a simple application with angular.js and I'm having a lot of trouble since I'm not used to use javascript.. My application consists of an input text where i write a series/movie title and then i have to say based on the JSON I get how many series, movies and games there are in that JSON. Here's the JSON(you can see the Type attribute I'm talking about):

{
    "Search": [
        {
            "Title": "The Wire",
            "Year": "2002–2008",
            "imdbID": "tt0306414",
            "Type": "series",
            "Poster": "http://ia.media-imdb.com/images/M/MV5BNjc1NzYwODEyMV5BMl5BanBnXkFtZTcwNTcxMzU1MQ@@._V1_SX300.jpg"
        },
        {
            "Title": "Wire in the Blood",
            "Year": "2002–",
            "imdbID": "tt0337792",
            "Type": "series",
            "Poster": "http://ia.media-imdb.com/images/M/MV5BMTg2NDc3ODI4MF5BMl5BanBnXkFtZTcwOTM3OTIzMQ@@._V1_SX300.jpg"
        },
        {
            "Title": "Thru the Wire",
            "Year": "1987",
            "imdbID": "tt0094143",
            "Type": "movie",
            "Poster": "N/A"
        },
        {
            "Title": "The Wire",
            "Year": "1997–1998",
            "imdbID": "tt0960700",
            "Type": "series",
            "Poster": "N/A"
        },
        {
            "Title": "Over the Wire",
            "Year": "1996",
            "imdbID": "tt0114071",
            "Type": "movie",
            "Poster": "http://ia.media-imdb.com/images/M/MV5BMTY5MjE1NDQ0MF5BMl5BanBnXkFtZTcwODMyNjUxMQ@@._V1_SX300.jpg"
        },
        {
            "Title": "The Wire: The Musical",
            "Year": "2012",
            "imdbID": "tt2191222",
            "Type": "movie",
            "Poster": "N/A"
        },
        {
            "Title": "The Wire: The Chronicles",
            "Year": "2007–",
            "imdbID": "tt1168599",
            "Type": "series",
            "Poster": "N/A"
        },
        {
            "Title": "Hold the Wire",
            "Year": "1936",
            "imdbID": "tt0027756",
            "Type": "movie",
            "Poster": "N/A"
        },
        {
            "Title": "Tapping the Wire",
            "Year": "2007",
            "imdbID": "tt1075404",
            "Type": "movie",
            "Poster": "N/A"
        },
        {
            "Title": "Wind in the Wire",
            "Year": "1993",
            "imdbID": "tt0324568",
            "Type": "movie",
            "Poster": "N/A"
        }
    ]
}

For example when I type "The wire" I should get 4 series, 0 games and 6 movies. I do that by calling IMDB API and then I access the type element and read whether it is a movie, game or series. I've written this code so far but it has some weird behaviour:

<html>
    <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>

    <body>
        <div ng-app="myApp" ng-controller="customersCtrl">TV Series:
            <input type="text" ng-model="seriesName">
            <br>
            <br>Series Name: {{seriesName}}
            <input type="submit" ng-click="search(seriesName)" value="Search" />
            <ul>
                <li ng-repeat="x in names | filter:isActive"></li>
            </ul>
            <br>Series:{{series}}
            <br>
            <br>Game:{{games}}
            <br>
            <br>Movie:{{movies}}
            <br>
        </div>

       <script>

       var app = angular.module('myApp', []);
       app.controller('customersCtrl', function ($scope, $http) {
           $scope.series = 0;
           $scope.movies = 0;
           $scope.games = 0;
           $scope.search = function (value) {

               $http.get("http://www.omdbapi.com/?s=" + value).success(function (response) {
                   $scope.names = response.Search;
               });

               $scope.isActive = function (x) {
                   if (x.Type === "movie") {
                       $scope.movies = $scope.movies + 1;
                   } else if (x.Type === "game") {
                       $scope.games = $scope.games + 1;
                   } else if (x.Type === "series") {
                       $scope.series = $scope.series + 1;
                   }
                   return false;
               };
           };
       });

       </script>

First problem I have is that when i click search i get 44 series instead of 4 and 66 movies instead of 6 Second problem is that after clicking for the first time, as soon as i type again, my series,games and movies attributes change their number without me clicking the search button.

2 Answers 2

2

You are getting 44 and 66 because you are string appending instead of adding those numbers. In Javascript the + operator also concatenates strings so 'foo'+1 = 'foo1'. One of the two sides of the sum is a string and not an integer.

Also, if you want to search just once when the search button is clicked, I would not put the $scope.isActive function nested inside the $scope.search function. Just make the search function to set the $scope.names variable and also if you want set the movies games and series counters also, right after the success by iterating the response (I recommend lodash for things like this).

Once all the data is properly loaded by the search function on the scope you can manipulate or render it. About the isActive function, I'm not entirely sure what are you trying to achieve there. But I think you don't need it.

Edit:

app.controller('customersCtrl', function ($scope, $http) {
$scope.series = 0;
$scope.movies = 0;
$scope.games = 0;
$scope.search = function (value) {
$http.get("http://www.omdbapi.com/?s=" + value).success(function (response) {
    $scope.names = response.Search;
    $scope.movies = _.filter($scope.names,function(entry){
        return entry.Type === 'movie'
    }).length;
    $scope.games = _.filter($scope.names,function(entry){
        return entry.Type === 'game'
    }).length;
    $scope.series = _.filter($scope.names,function(entry){
        return entry.Type === 'series'
    }).length;
});
}

There you have the jsFiddle with how would I do it.

Sign up to request clarification or add additional context in comments.

2 Comments

I just tried parseInt() on the 2 numbers and it's still displaying the same result. And I'm not actually string appending because the result is correct. It's just that at some point maybe it srting appends but dont know where.
I would not append/add a number to the counter, you may want just to overwrite the value. I've posted a jsFiddle in my previous answer with my approach.
1

It seems that there is still a lot you have to learn about angular and how it interacts with the DOM and what the purpose of each angular component is. I suggest reading up on the proper use of filters and other parts of angular such as Services and Factories.

Also it wouldn't hurt learning a few asynchronous programming skills when working with JS. Using promises can make your application perform a lot better and will make your code much cleaner.

The following html and js snippets should clear up a lot of detail for you :

<div ng-app="myApp" ng-controller="customersCtrl">Query :
<input type="text" ng-model="seriesName">
<input type="submit" ng-click="search(seriesName)" value="Search" />
<br /><br />
<div ng-repeat="entry in data">{{entry}}</div>
<br />
<br/>Series:{{series}}
<br/>
<br/>Game:{{games}}
<br/>
<br/>Movie:{{movies}}
<br/>

var app = angular.module('myApp', []);

app.controller('customersCtrl', function ($scope, $http, $q) {
    $scope.series = 0;
    $scope.movies = 0;
    $scope.games = 0;

    //Use this as a service/factory instead it is not recommended to have this in a controller
    var get = function (search) {
        var deferred = $q.defer();

        $http.get("http://www.omdbapi.com/?s=" + search).success(function (response) {
            deferred.resolve(response)
        });

        return deferred.promise;
    };

    $scope.search = function (value) {
        var promise = get(value);
        promise.then(function (data) {
            $scope.data = data.Search;
            $scope.series = 0;
            $scope.movies = 0;
            $scope.games = 0;

            angular.forEach($scope.data, function(datum){
                switch(datum.Type) {
                    case 'movie' : $scope.movies += 1; break;
                    case 'series' : $scope.series += 1; break;
                    case 'games'  : $scope.games += 1; break;
                    default:break;
                }
            });
        });
    };
});

There are a lot of improvements that can be made to this piece of code but this should set you on the right track and help you see your mistakes.

I have not written the code keeping in mind all the angular best practices or other standards. Please only use this to see where you went wrong and what you can improve on, this code is not suitable for use in any production/development environment.

There are several good angular sources out there that can teach you all that you need to know about how to correctly use all of angular's wonderful and powerful features. I hope my quick and dirty answer helps you out.

2 Comments

Thank you very much. You are very right, this was my first script using angular so i have a lot to learn. I'll take your advice and look through some tutorials. I mark this answer as the correct one. Your code was very useful to clear up some concepts.
Just need to add something here for you, go have a look at Scotch and Egghead , these two sites are two of the most reliable sources on angular and everything that comes with it even if the implementation isn't as it should be in a production environment it provides a lot of educational value. Enjoy angular and your ventures in to the world of javascript.

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.