Ben Weiser
Ben Weiser

Reputation: 11

Using Angular $http in a service to fire on ng-click

I am currently using Angular 1.3.14 and I would like to make an request using $http whenever a link is clicked. I am trying to place the $http request in a service so it's not bound to any one controller and can be accessed by multiple controllers. I've created two functions sayHello() and getData(). I want each one to console.log when clicked. Only the sayHello() function does, but not the getData() function.. Here's what I don't understand.

  1. Why does the $http request fire on load, and not on click whereas the sayHello function works perfectly?

  2. How can I modify my code so it works as intended?

    <p><a href="#" ng-click="getData()">Console Log Our Data</a></p>
    <p>
      <a href="#" ng-click="sayHello()">Console Log The Word "Hello"</a></p>
    

    var app = angular.module('myApp', [])
    
    .controller('mainCtrl', function($scope, dataService){
    
    $scope.sayHello = dataService.sayHello;
    
    $scope.getData = dataService.getData(function(response){
            $scope.myData = response.data;
        console.log($scope.myData);
        });
    })
    .service('dataService', function($http){
    
    this.getData = function(callback){
          $http.get('http://jsonplaceholder.typicode.com/posts')
            .then(callback);
        }
    
      this.sayHello = function(){
        console.log("Hello!");
      }
    
    
    });
    

Codepen for reference http://codepen.io/benweiser/pen/remvvo/

Upvotes: 1

Views: 180

Answers (4)

Mauricio Poppe
Mauricio Poppe

Reputation: 4876

That's because $scope.getData is equal to undefined when it should be a function

$scope.getData = function () {
  dataService.getData(function(response) {
     $scope.myData = response.data
     console.log($scope.myData)
  })
}

Update: You can send parameters either from the call to the method or from the method itself, suppose you have the following input

<input ng-model="name">

Then you can use the send the value and use it in your service as follows

<a ng-click="getData(name)">get data</a>

$scope.getData = function (name) {
  dataService.getData(name)
     .then(function (response) { ... })
}

Or using it directly in the controller

<a ng-click="getData()">get data</a>

$scope.getData = function () {
  dataService.getData($scope.name)
     .then(function (response) { ... })
}

Note that both assume that dataService.getData() returns a promise instead of passing the callback so you'd also need to do the following on your service if you want to code it like above

this.getData = function (name) {
  // do something with name
  return $http.get('http://jsonplaceholder.typicode.com/posts/' + name)
}

You should read more on Promises vs callbacks and how you can take advantage of them :)

Upvotes: 2

Richard Threepwood
Richard Threepwood

Reputation: 31

The Ajax query was being made when controller was first loading. Your bind with "getData" wasn't with a function, but with an ajax call, and that was why it was not triggered.

This refactor works on codepen:

'use strict';

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

.controller('mainCtrl', function($scope, dataService){

    $scope.sayHello = dataService.sayHello;

    $scope.getData = function(){
    dataService.getData().then(
        function(response){
            $scope.myData = response.data;
                console.log($scope.myData);
            }
        );
    }
})

.service('dataService', function($http){

    this.getData = function(callback){
        return $http.get('http://jsonplaceholder.typicode.com/posts');
    }

    this.sayHello = function(){
        console.log("Hello!");
    }

});

Main updates:

  1. $scope.getData is binded to a function, not an Ajax call/promise
  2. Promise is outside the service (better solutions are welcome :-) ).
  3. dataService.getData is called as a function. (Did't work in other way).

Upvotes: 0

George Chen
George Chen

Reputation: 6939

When you do this

$scope.getData = dataService.getData(function(response){
    $scope.myData = response.data;
    console.log($scope.myData);
 });

})

dataService.getData get executed immediately. As a result, $scope.getData is set to a promise instead of a function you intent to bind to ng-click

change this line $scope.getData = dataService.getData to the following which will actually set a function with callback to $scope.getData

$scope.getData = dataService.getData.bind(this, function(response) {
    $scope.myData = response.data;
    console.log($scope.myData);
});

Upvotes: 1

user2263572
user2263572

Reputation: 5606

I would try doing something like this. Should be easy to apply to your code above

//in your factory
app.factory('dataFactory',function($http){

    factory = {};

    //get data
    factory.getData = function(obj){
        return $http({
            method: 'GET',
            url: 'http://jsonplaceholder.typicode.com/postsn'
        })
    };

    return factory
}); 

//in your controller
app.controller(someCtrl,function($scope,dataFactory){

  dataFactory.getData().then(function(data){
      console.log('This will be your data: ', data)
  })

})

Upvotes: 0

Related Questions