Error: "fourSquareService.getVenues is not a function"

61 Views Asked by At

AngularJs - how to use factory with form input as part of URL to fetch?

First question here. I am studying angular and was trying to use separated files for my services and also using a user input on a form as part of the request URL. I got it working by injecting $http on my controller and calling the service inside the on click function, but to keep things clean, I really wish to keep services in separed files and call them inside my controller. I've tried to return a one attribute function on my service so I could parse the input (ng-model="cityInput") when calling it. But when I call it on my controller (after adding the service as dependency) it's giving me "fourSquareService.getVenues is not a function" error. What am I doing wrong? Thanks in advance. Code below:

foursquare service

 // Foursquare API Info
    const clientId = 'PU3IY1PZEOOANTPSHKNMS5HFSMEGEQ1IAVJYGYM4YVZP3NGD';
    const clientSecret = '0V21IXU0EETE3SZJGGCP4T4R13NUTBJ0LMI5WQY45IMDPEKY';
    const url = 'https://api.foursquare.com/v2/venues/explore?near=';
    const imgPrefix = 'https://igx.4sqi.net/img/general/150x200';
    
    // Current day
    function getCurrentDate() {
        let today = new Date();
        let yyyy = today.getFullYear();
        let mm = today.getMonth() + 1;
        let dd = today.getDate();
        if (dd < 10) {
            dd = '0' + dd
        }
        if (mm < 10) {
            mm = '0' + mm
        }
        return yyyy + mm + dd;
    };
    let currentDay = getCurrentDate();
    
    //Foursquare Angular request
    app.factory('fourSquareService', ['$http', function ($http) {
        return {
            getVenues: function(place) {
            const fourSquareURL = `${url}${place}&venuePhotos=1&limit=5&client_id=${clientId}&client_secret=${clientSecret}&v=${currentDay}`;
            return $http.get(fourSquareURL);
        }
    }
    }]);

APIXU service

// APIXU Info
const apiKey = '44972f525fb14478ac0224821182604';
const forecastUrl = 'https://api.apixu.com/v1/forecast.json?key=';

//Angular request
app.factory('apixuService', ['$http', function ($http) {
    return {
        getForecast: function (place) {
            const apixuURL = `${forecastUrl}${apiKey}&q=${place}&days=4&hour=10`;
            return $http.get(apixuURL);
        },
        getCurrentWeather: function (place) {
            const currentWeatherUrl = `${forecastUrl}${apiKey}&q=${place}`;
            return $http.get(currentWeatherUrl);
        }
    };
}]);

Controller

app.controller('MainController', ['$scope', 'apixuService', 'fourSquareService', function ($scope, fourSquareService, apixuService) {
    //Search on Click Function
    $scope.executeSearch = function () {

        //Venues
        fourSquareService.getVenues($scope.cityInput).then(function (response) {
            $scope.fouSquareData = response.data.response
            $scope.destination = $scope.fouSquareData.geocode.displayString;
            $scope.venues = $scope.fouSquareData.groups[0].items.map(spot => spot.venue);
            let photos = [];
            $scope.venues.forEach((venue, index) => venue.photos.groups[0] && venue.url ? photos.push(`<a href="${venue.url}" target="_blank"><img class="venueimg" src="${imgPrefix}${venue.photos.groups[0].items[0].suffix}"/></a>`) : venue.photos.groups[0] ? photos.push(`<img class="venueimg" src="${imgPrefix}${venue.photos.groups[0].items[0].suffix}"/>`) : photos.push('<img class="venueimg" src="./img/320px-No_image_available.png"/>'));
            $scope.photos = photos;
        }, function (error) {
            $scope.showdestination = true;
            $scope.showData = false;
            $scope.destination = 'Place not found, please try again.';
        });

        //Current Weather
        getWeather.getCurrentWeather($scope.cityInput).then(function (response) {
            $scope.currentWeather = response.data.current;
            $scope.place = response.data.location.name;
        });

        //Forecast
        getWeather.getForecast($scope.cityInput).then(function (response) {
            $scope.showdestination = true;
            $scope.showData = true;
            $scope.forecast = response.data.forecast.forecastday;
            const weekDays = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];
            $scope.weekDays = [];
            $scope.forecast.forEach(function (day, index) {
                $scope.weekDays[index] = weekDays[(new Date(day.date)).getDay()]
            });
            $scope.weekDays[0] = 'Today';
            $scope.weekDays[1] = 'Tomorrow';
        });

    };

}]);
2

There are 2 best solutions below

6
John Velasquez On

You have a mismatch on referencing your dependencies

It should be this

app.controller('MainController', ['$scope', 'apixuService', 'fourSquareService', 
function ($scope, apixuService, fourSquareService) {
        //Search on Click Function
        $scope.executeSearch = function () {

        //Venues
        fourSquareService.getVenues($scope.cityInput).then(function (response) {
            $scope.fouSquareData = response.data.response
            $scope.destination = $scope.fouSquareData.geocode.displayString;
            $scope.venues = $scope.fouSquareData.groups[0].items.map(spot => spot.venue);
            let photos = [];
            $scope.venues.forEach((venue, index) => venue.photos.groups[0] && venue.url ? photos.push(`<a href="${venue.url}" target="_blank"><img class="venueimg" src="${imgPrefix}${venue.photos.groups[0].items[0].suffix}"/></a>`) : venue.photos.groups[0] ? photos.push(`<img class="venueimg" src="${imgPrefix}${venue.photos.groups[0].items[0].suffix}"/>`) : photos.push('<img class="venueimg" src="./img/320px-No_image_available.png"/>'));
            $scope.photos = photos;
        }, function (error) {
            $scope.showdestination = true;
            $scope.showData = false;
            $scope.destination = 'Place not found, please try again.';
        });

        //Current Weather
        apixuService.getCurrentWeather($scope.cityInput).then(function (response) {
            $scope.currentWeather = response.data.current;
            $scope.place = response.data.location.name;
        });

        //Forecast
        apixuService.getForecast($scope.cityInput).then(function (response) {
            $scope.showdestination = true;
            $scope.showData = true;
            $scope.forecast = response.data.forecast.forecastday;
            const weekDays = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];
            $scope.weekDays = [];
            $scope.forecast.forEach(function (day, index) {
                $scope.weekDays[index] = weekDays[(new Date(day.date)).getDay()]
            });
            $scope.weekDays[0] = 'Today';
            $scope.weekDays[1] = 'Tomorrow';
        });

    };

}]);
1
Pedro Santos On

I've changed the order of the parameters inside the controller function to match the same order of the depedencies and it worked! Didn't know the order was important.

working controller:

 app.controller('MainController', ['$scope', 'fourSquareService', 'apixuService', 
function ($scope, fourSquareService, apixuService) {
        //Search on Click Function
        $scope.executeSearch = function () {

            //Venues
            fourSquareService.getVenues($scope.cityInput).then(function (response) {
                $scope.fouSquareData = response.data.response
                $scope.destination = $scope.fouSquareData.geocode.displayString;
                $scope.venues = $scope.fouSquareData.groups[0].items.map(spot => spot.venue);
                let photos = [];
                $scope.venues.forEach((venue, index) => venue.photos.groups[0] && venue.url ? photos.push(`<a href="${venue.url}" target="_blank"><img class="venueimg" src="${imgPrefix}${venue.photos.groups[0].items[0].suffix}"/></a>`) : venue.photos.groups[0] ? photos.push(`<img class="venueimg" src="${imgPrefix}${venue.photos.groups[0].items[0].suffix}"/>`) : photos.push('<img class="venueimg" src="./img/320px-No_image_available.png"/>'));
                $scope.photos = photos;
            }, function (error) {
                $scope.showdestination = true;
                $scope.showData = false;
                $scope.destination = 'Place not found, please try again.';
            });

            //Current Weather
            apixuService.getCurrentWeather($scope.cityInput).then(function (response) {
                $scope.currentWeather = response.data.current;
                $scope.place = response.data.location.name;
            });

            //Forecast
            apixuService.getForecast($scope.cityInput).then(function (response) {
                $scope.showdestination = true;
                $scope.showData = true;
                $scope.forecast = response.data.forecast.forecastday;
                const weekDays = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];
                $scope.weekDays = [];
                $scope.forecast.forEach(function (day, index) {
                    $scope.weekDays[index] = weekDays[(new Date(day.date)).getDay()]
                });
                $scope.weekDays[0] = 'Today';
                $scope.weekDays[1] = 'Tomorrow';
            });

        };

    }]);