3

I have created simple Angular app that uses Yahoo Finance to pull some currency data. However, at present, it pulls the data, but it is not until i reload the page that the currency changes, which is fine. I can create a simple $timeout around the $http.get, however, i would prefer to use SocketIO.

Here is the standard working $http.get: http://plnkr.co/edit/oiZ7JOASUbtLDPAQkZj2?p=preview

Here's is the start of the SocketIO app: http://plnkr.co/edit/dUEekn6kIJwLYxikWT9H?p=preview

However i am stuck as to where to go from here so that the currency data constantly updates.

Controller:

app.controller('MainCtrl', function($scope, yahooService) {
  $scope.name = 'World';

      yahooService.getData()
        .success(function(data, status, headers, config) {
          $scope.currencies = data;
        })
        .error(function (data, status, headers, config) {
          $scope.currencies = 'There has been an error';
        });
});

Service:

app.factory('yahooService', function($http) {
    return {
        getData: function() {
            var url = "https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20yahoo.finance.xchange%20where%20pair%20in%20(%22USDMXN%22%2C%20%22USDCHF%22)&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys&callback=";
            return $http.get(url);
        }
    };
});

SocketService:

app.factory('socket', function ($rootScope) {
  var socket = io.connect('https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20yahoo.finance.xchange%20where%20pair%20in%20(%22USDMXN%22%2C%20%22USDCHF%22)&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys&callback=');
  //var socket = io.connect();
  return {
    on: function (eventName, callback) {
      socket.on(eventName, function () {  
        var args = arguments;
        $rootScope.$apply(function () {
          callback.apply(socket, args);
        });
      });
    },
    emit: function (eventName, data, callback) {
      socket.emit(eventName, data, function () {
        var args = arguments;
        $rootScope.$apply(function () {
          if (callback) {
            callback.apply(socket, args);
          }
        });
      })
    }
  };
});

Any help would be appreciated.

6
  • I tried the socket io part, but it shows 404 for that URL. Are you sure that the endpoint supports WebSocket? Can I have a link to the documentation of the Yahoo API please? Commented Sep 7, 2015 at 13:53
  • no ws for this link, and plunker send origin problem ;) Commented Sep 7, 2015 at 13:58
  • Ok, if there is no web socket for Yahoo Finance, then some form of SocketIO Finance/Currency real-time app. Commented Sep 7, 2015 at 15:13
  • @FelisCatus - Yahoo API docs: code.google.com/p/yahoo-finance-managed/wiki/YahooFinanceAPIs Commented Sep 7, 2015 at 15:15
  • @OamPsy I checked the docs but I didn't see anything WebSocket there. Your code looks perfectly fine for me, but we really need a WebSocket endpoint in order to test it out. Commented Sep 8, 2015 at 3:58

4 Answers 4

3
+25

As suggested by Omkara, you can use Angular's $interval functionality to execute a function continuously after a delay. I've forked your Plunker (http://plnkr.co/edit/edyFvnAU1LCRS4uZqJdR?p=preview) , changing your MainCtrl to the following

app.controller('MainCtrl', function($scope, $interval, yahooService) {
  $scope.name = 'World';
    $interval(function () {
      yahooService.getData()
        .success(function(data, status, headers, config) {
          $scope.currencies = data;
        })
        .error(function (data, status, headers, config) {
          $scope.currencies = 'There has been an error';
        });
    }, 1000);
});

This makes the controller execute your getData() function every 1000 milliseconds.

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

Comments

2

It seems that the query.yahooapis.com does not have support for WebSockets or at least I could not find it with some research in their documentation. WebSockets are cool solution to this problem but if they are not provided by Yahoo you will need to fallback to polling and as suggested you can do it with $interval angular service.

Here is your refactored code, I hope you will like it.

Example usage:

app.controller('MainCtrl', function($scope, yahooService) {
  yahooService.setRealTime(true);
  $scope.currencies = yahooService.getData();
});

Yahoo service implementation:

app.factory('yahooService', function($http, $interval) {
  var url = "https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20yahoo.finance.xchange%20where%20pair%20in%20(%22USDMXN%22%2C%20%22USDCHF%22)&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys&callback=";
  var realTime = false;
  var cancelIntervalCallback;
  var data = {};

  var getData = function () {
    $http.get(url).success(function(response, status, headers, config) {
      angular.merge(data, response);
    });
  };

  return {
      getData: function() {
        if (!realTime) {
          getData(); 
        }
        return data;
      }, 
      setRealTime: function (isRealTime) {
        realTime = isRealTime;
        if (!isRealTime && angular.isFunction(cancelIntervalCallback)) {
          cancelIntervalCallback();
          cancelIntervalCallback = null;
        } else {
          cancelIntervalCallback = $interval(getData, 1000);
        }
      }
  };
});

Note: I've upgraded to Angular 1.4 for angular.merge function, if this is problem for you can use merge from lodash.

1 Comment

If you can find an API that has support for WebSockets I would be happy to change my answer. Regards.
0

I want to suggest few changes in Controller 'MainCtrl' as below:

app.controller("MainCtrl", function($scope, $interval){

    $interval(callAtInterval, 5000);
});

function callAtInterval() {
    console.log("Invoke Get data");
}

Comments

0

You have to add options like reconnect and delay in Socket service like

app.factory('socket', function ($rootScope) {
      var socket = io.connect('your url',{
     'reconnect': true,
      'reconnection delay': 500
});
      //var socket = io.connect();
      return {
        on: function (eventName, callback) {
          socket.on(eventName, function () {  
            var args = arguments;
            $rootScope.$apply(function () {
              callback.apply(socket, args);
            });
          });
        },
        emit: function (eventName, data, callback) {
          socket.emit(eventName, data, function () {
            var args = arguments;
            $rootScope.$apply(function () {
              if (callback) {
                callback.apply(socket, args);
              }
            });
          })
        }
      };
    });

And in controller,if you want to show latest 10 currencies data

var CURRENCIES_DISPLAYED = 10;
app.controller('MainCtrl', function($scope, yahooService) {
  $scope.name = 'World';

      yahooService.getData()
        .success(function(data, status, headers, config) {
          $scope.currencies = data;

         $scope.currencies.unshift(tx);
        if (parseInt($scope.currencies.length, 10) >= parseInt(CURRENCIES_DISPLAYED, 10)) {
          $scope.currencies = $scope.currencies.splice(0, CURRENCIES_DISPLAYED);
          }
  })
        .error(function (data, status, headers, config) {
          $scope.currencies = 'There has been an error';
        });
});

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.