Issue: "fourSquareService.retrieveLocations does not exist as a function"

Struggling with AngularJs - How to Utilize Factory Alongside Form Input in URL for Data Fetching?

This is my first time asking a question here. I've been diving into Angular and wanted to organize my services by separating them into different files. Additionally, I aimed to incorporate user input from a form as part of the request URL. Although I managed to get it working by injecting $http into my controller and invoking the service within the click function, I prefer maintaining clean code by keeping services in separate files and calling them within the controller. I attempted to create a single attribute function in my service that could handle parsing the input (ng-model="cityInput") when invoked. However, upon calling it in my controller (after adding the service as a dependency), I encountered an error stating "fourSquareService.getVenues is not a function". What am I missing here? Appreciate any help. See code below:

Foursquare Service

// Foursquare API Details
    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';
    
    // Get Current Date
    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
        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';
        });

    };

}]);

Answer №1

You seem to have an issue with referencing your dependencies

Here is the correct format

app.controller('MainController', ['$scope', 'apixuService', 'fourSquareService', 
function ($scope, apixuService, fourSquareService) {
        //Function for search execution
        $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';
        });

    };

}]);

Answer №2

I recently made a small adjustment in the controller function by rearranging the parameters to match the order of dependencies, and surprisingly it worked! I had no idea that the order would play such a crucial role.

Updated Controller:

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

            //Fetching 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.';
            });

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

            //Forecast details
            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';
            });

        };

    }]);

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Retrieving an HTML page from one location and automatically populating textboxes with preexisting values on the receiving end

I'm currently facing a dilemma. Here's the issue: I need to load an HTML page (let's call it test.html) when a button is clicked on another page (referred to as home page). The test.html page has input boxes that I want to populate with p ...

Incorporate classes into multiple titles by utilizing the text within the title

Here is some HTML code: <tr class="more-options"> <td width="190px" valign="top" class="ms-formlabel"> <H3 class="ms-standardheader"> <nobr>Required Hidden 1&l ...

Discovering more about this topic

Looking for a way to create an expandable box that enlarges when "read more" is clicked, revealing text below it. And also looking to add a button that closes the expanded text back up. Experimented with the toggletext JavaScript command, as found on this ...

broadcast a video file from a Node.js server to multiple HTML5 clients at the same time

After researching online, I have been looking for a way to simultaneously stream a video.mp4 to multiple html5 clients. Despite reading various tutorials, I haven't found the ideal solution using nodejs. Do you have any suggestions or alternative met ...

Creating Interactive Labels with React-Three-Renderer (Example code provided)

Currently, I am utilizing react-three-renderer (npm, github) to construct a scene using three.js. In my project, my objective is to create a label that consistently faces the camera by using <sprite> and <spriteMaterial>, inspired by stemkoski ...

"Enhance readability by adjusting the font size on mobile devices and iPhones for an

I'm currently working on a website that needs to maintain a consistent look across all types of devices, including laptops, PCs, iPads, iPhones, and other smartphones. To achieve this, I've implemented fittext.js, a pure JavaScript solution that ...

What is the best way to use JavaScript to show a text value alongside radio buttons?

Currently, I am in the process of creating an e-commerce platform that allows customers to choose custom components for their purchases. Although I am relatively new to JavaScript, I have successfully developed a radio button list where the prices are tota ...

Unable to invoke a custom hook within another custom hook in a React application

I've developed a React application using create-react-app. Currently, I'm working on creating a custom hook that integrates with the Microsoft Authentication Library (MSAL). MSAL provides a custom React hook that I want to utilize within my own ...

Repeated failures in the CodeIgniter JavaScript function

Currently I am developing a donation store using CodeIgniter. I have been focusing on implementing the cart functionality, and have created a small card to display the store items. The card allows users to add items to their cart using an AJAX request to p ...

Is there a discrepancy in speed between Node.js http.get and Google Chrome's $.get function?

Recently, while experimenting with node.js, I decided to test out the following code snippet: var http = require("http"); function get() { var headers = { 'Accept-Encoding': 'gzip' }; var startedAt = new Date().get ...

Safari 7.0 Experiencing Unpredictable Ajax Errors

Encountered an issue with Ajax requests through jQuery on a web app while using Safari 7.0 for Mac OS X 10.9 Mavericks (specifically 9537.71). This problem was occurring intermittently and could not be reproduced consistently on Safari 7.0. Environment: ...

I'm curious about the correct method for updating a parent component using a shared service within the ngOnInit function in Angular version 13

There have been instances where I encountered a scenario multiple times, where I utilize a shared service within the ngOnInit of a component to update a value in another component, specifically its parent. This often leads to the well-known Error: NG0100: ...

Updating the footer of a React application using Material UI Grid

Having some trouble customizing the footer in a React Material-UI grid. Refer to the image below for details. Any ideas on how to change the: 1 row selected? Thank you! ...

Internet Explorer 9 does not display content until the ajax/json function has finished executing

I have encountered an issue with my code regarding updating a div element. The first innerHTML call seems to be ineffective and does not render in the browser. However, the second innerHTML call works as expected by appending "Complete" once the ajax call ...

Tips on expanding the background beyond the boundaries of a parent container with a specific width limit

Could you please take a look at the code snippet below? I am dealing with a situation where I have a container with a fixed width, and inside that container, there are rows whose width exceeds that of the parent container. Some of these rows have a backgro ...

Internet Explorer 11 and the process of URL encoding

Hello there! I am currently working on an MVC project with Angular where I am utilizing a JsonResult to return JSON data from a list containing emails with a specific date. Below is the AJAX call I'm making from Angular: myApp.service('mailServ ...

Utilizing an SSL certification (pem file) within JavaScript

Currently in the process of developing a program to extract data from the FAA's AIDAP database. I received a security certificate in the form of a .p12 file, which I have successfully converted into a .pem file. However, I am encountering difficulties ...

Tips for automatically displaying the first option as selected in an HTML Select dropdown

I have an HTML select element where I want the option chosen by the user to not be displayed in the box. Instead, I would like the box to always show the first option, regardless of what the user selects from the dropdown menu. Below is my CSS code for sty ...

Generating a table with two columns utilizing ng-repeat

I am currently dealing with an array of objects that I need to showcase in a two-column layout. The challenge arises because some columns have more data than others, requiring equi-height rows. Despite utilizing Bootstrap and clearfix in my attempts to di ...

Using AngularJS with ngRepeat allows for the insertion of an extra element every specified number of repeats

I am attempting to establish a layout where every 7 repeated elements, an extra element is inserted. This additional element must be part of the parent container rather than being a child of one of the repeated elements. Simply changing the class is not s ...