Basically i have two sources of data, one is real time data from socket.io and other is json object. And i'm using both in front-end but the problem is that i need to pass a variable from socket.io to json parser:
This controller for my view:
.controller('mainCtrl', ['$scope','socket','currentData', function($scope, socket, currentData){
// It's updated every 2 seconds
socket.on('chnl', function(data){
// Passed to view OK
$scope.realtimeData = data;
// And i need to pass this to currentData.
$scope.foo = data.foo;
});
// Here i'm getting json response from factory which is computed based on socket.io foo variable and then passed to view.
currentData.get().then(function(data){
if($scope.foo)...
...
$scope..
});
}]
The problem is anything i tried i ended up calling json object on every incoming socket.io package, what i need to calc this at it's initalization and pass data to the view.
Any solutions?
Thanks.
If you need for it to run only once for initialization...
Move the call to the JSON service into the .on callback. Place it inside of a conditional which runs only when an initialization variable is set to false. Once the data is set, switch that variable to true so that it doesn't run again:
.controller('mainCtrl', ['$scope','socket','currentData', function($scope, socket, currentData){
$scope.fooInit = false;
socket.on('chnl', function(data){
$scope.realtimeData = data;
$scope.foo = data.foo;
if (!$scope.fooInit) {
currentData.get().then(function(data){
if($scope.foo)...
...
$scope..
});
$scope.fooInit = true;
}
});
}])
Related
I have need to listen to data comming frome a socket.
Chrome fires this function:
chrome.sockets.tcp.onReceive.addListener(function(info) {
console.log(info);
});
I want my angular controll to get that info.
if i do this:
chrome.sockets.tcp.onReceive.addListener(function(info) {
$scope.$broadcast("newData", info.data);
});
$scope.$on("newData", function (event, data){
console.log(data);
$scope.text = data;
});
the text model dosen't get updated.
Is there a way to get the cycle updating and not using the apply function?
I tried using $watch but i dident succeed.
If you alter where you are saving the data the binding will work as expected. Instead of updating a property on the $scope object go one level deeper.
$scope.values.text = data;
Be sure to update your controller to include the values object creation.
// in controller
$scope.values = {
data: ''
};
I discovered that when I call a service method within my controller and pass to it an object as a parameter, any changes that are done to that object (inside service method) are also made to the original object from my controller.
I always thought that controller data should stay unchanged until I changed it inside promise win/error event and only if I need to.
JS sample:
// Code goes here
var app = angular.module('App', []);
app.controller('AppCtrl', function($scope, simpleService){
$scope.data = { d: 1, c: 10};
$scope.clickMe = function(){
simpleService.clickMe($scope.data).then(function(res){
alert($scope.data.d);
})
.catch(function(err){
alert($scope.data.d);
});
}
});
app.factory('simpleService', function($q){
var simpleServiceMethods = {};
simpleServiceMethods.clickMe = function(data){
var deffered = $q.defer();
//data = JSON.parse(JSON.stringify(data)); - solution: clone data without references
data.d = 1111;
deffered.reject();
return deffered.promise;
}
return simpleServiceMethods;
});
Plunker demo: http://plnkr.co/edit/nHz2T7D2mJ0zXWjZZKP3?p=preview
I believe this is the nature of angular's databinding. If you want to pass the details of a $scope variable you could make use of angular's cloning capability with copy or update your services to work slightly differently by creating a copy on the service side. Normal CRUD style applications you'd normally be passing the id of an entity, receiving a new entity or posting changes which may in most cases already be present client side.
I'm fairly new to angular js, and not really sure how to google the terms i need.
I basically have a html page, bind to a controller. This page will load data from mysql.
in my controller, i have code like this when the page load:
thresholdNameSpace.controller("ThresholdController", ['$scope','$http', function ($scope, $http){
$http.get('http://something.appspot.com/met').success(function(data){
$scope.messages = data;
}]);
There is a functionality on the page that add new entry to the database. How do i update the controller so that after a new content is added to the database, it automatically gets displayed?
what keyword should i be looking for in angularjs term
well, just push the data to the server and send a response back... a brute-force approach would be to send back the entire data back, or just to append the current 'message' at the end of the messages object
thresholdNameSpace.controller("ThresholdController", ['$scope','$http', function ($scope, $http){
// get data
$http.get('http://something.appspot.com/met').success(function(data){
// assuming messages is an array
$scope.messages = data;
});
// create a function to push data up to the db, then update the view on success or failure appropriately
$scope.updateDatabase = function(param1, param2, param3...){
var parameters = {
name: param1,
date: param2,
message: param3
}
$http.get('http://something.appspot.com/metUpdate', parameters).then(function(successResponse){
console.log('successResponse', successResponse);
if($scope.messages)
$scope.messages.push({message: param3, person: param1, sent: param2}); // your object added to array
}, function(failureResponse){
console.log('failureResponse', failureResponse);
// you can also push a error object which will be processed on the front end for proper display
$scope.messages.push({error: failureReason.data.errorMessage});
});
}
}]);
Angular automatically updates the html, you just have to update $scope.messages from the database.
For example, you can get the data every 30 seconds, with $interval.
Something like this :
var update = function() {
$http.get('http://something.appspot.com/met').success(function(data){
$scope.messages = data;
}
}
$interval(update, 30000)
Don't forget to inject $interval in your controller.
I have a factory called "Server" which contains my methods for interaction with the server (get/put/post/delete..). I managed to login and get all data successfully when I had all my code in my controller. Now that I want to separate this code and restructure it a little bit I ran into problems. I can still login and I also get data - but data is just printed; I'm not sure how to access the data in controller? I saw some ".then" instead of ".success" used here and there across the web, but I don't know how exactly.
This is my factory: (included in services.js)
app.factory('Server', ['$http', function($http) {
return {
// this works as it should, login works correctly
login: function(email,pass) {
return $http.get('mywebapiurl/server.php?email='+email+'&password='+pass').success(function(data) {
console.log("\nLOGIN RESPONSE: "+JSON.stringify(data));
if(data.Status !== "OK")
// login fail
console.log("Login FAIL...");
else
// success
console.log("Login OK...");
});
},
// intentional blank data parameter below (server configured this way for testing purposes)
getAllData: function() {
return $http.get('mywebapiurl/server.php?data=').success(function(data) {
console.log("\nDATA FROM SERVER: \n"+data); // here correct data in JSON string format are printed
});
},
};
}]);
This is my controller:
app.controller("MainController", ['$scope', 'Server', function($scope, Server){
Server.login(); // this logins correctly
$scope.data = Server.getAllData(); // here I want to get data returned by the server, now I get http object with all the methods etc etc.
…. continues …
How do I get data that was retrieved with $http within a factory to be accessible in controller? I only have one controller.
Thanks for any help, I'm sure there must be an easy way of doing this. Or am I perhaps taking a wrong way working this out?
EDIT: I also need to be able to call factory functions from views with ng-click for instance. Now I can do this like this:
// this is a method in controller
$scope.updateContacts = function(){
$http.get('mywebapiURL/server.php?mycontacts=').success(function(data) {
$scope.contacts = data;
});
};
and make a call in a view with ng-click="updateContacts()". See how $scope.contacts gets new data in the above function. How am I supposed to do this with .then method?(assigning returned data to variable)
My question asked straight-forwardly:
Lets say I need parts of controller code separated from it (so it doesn't get all messy), like some functions that are available throughout all $scope. What is the best way to accomplish this in AngularJS? Maybe it's not services as I thought …
The trick is to use a promise in your service to proxy the results.
The $http service returns a promise that you can resolve using then with a list or success and error to handle those conditions respectively.
This block of code shows handling the result of the call:
var deferred = $q.defer();
$http.get(productsEndpoint).success(function(result) {
deferred.resolve(result);
}).error(function(result) { deferred.reject(result); });
return deferred.promise;
The code uses the Angular $q service to create a promise. When the $http call is resolved then the promise is used to return information to your controller. The controller handles it like this:
app.controller("myController", ["$scope", "myService", function($scope, myService) {
$scope.data = { status: "Not Loaded." };
myService.getData().then(function(data) { $scope.data = data; });
}]);
(Another function can be passed to then if you want to explicitly handle the rejection).
That closes the loop: a service that uses a promise to return the data, and a controller that calls the service and chains the promise for the result. I have a full fiddle online here: http://jsfiddle.net/HhFwL/
You can change the end point, right now it just points to a generic OData end point to fetch some products data.
More on $http: http://docs.angularjs.org/api/ng.%24http
More on $q: http://docs.angularjs.org/api/ng.%24q
$http.get retuns a HttpPromise Object
Server.getAllData().then(function(results){
$scope.data = results;
})
I am writing a small Angular web application and have run into problems when it comes to loading the data. I am using Firebase as datasource and found the AngularFire project which sounded nice. However, I am having trouble controlling the way the data is being displayed.
At first I tried using the regular implicit synchronization by doing:
angularFire(ref, $scope, 'items');
It worked fine and all the data was displayed when I used the model $items in my view. However, when the data is arriving from the Firebase data source it is not formatted in a way that the view supports, so I need to do some additional structural changes to the data before it is displayed. Problem is, I won't know when the data has been fully loaded. I tried assigning a $watch to the $items, but it was called too early.
So, I moved on and tried to use the angularfireCollection instead:
$scope.items = angularFireCollection(new Firebase(url), optionalCallbackOnInitialLoad);
The documentation isn't quite clear what the "optionalCallbackOnInitialLoad" does and when it is called, but trying to access the first item in the $items collection will throw an error ("Uncaught TypeError: Cannot read property '0' of undefined").
I tried adding a button and in the button's click handler I logged the content of the first item in the $items, and it worked:
console.log($scope.items[0]);
There it was! The first object from my Firebase was displayed without any errors ... only problem is that I had to click a button to get there.
So, does anyone know how I can know when all the data has been loaded and then assign it to a $scope variable to be displayed in my view? Or is there another way?
My controller:
app.controller('MyController', ['$scope', 'angularFireCollection',
function MyController($scope, angularFireCollection) {
$scope.start = function()
{
var ref = new Firebase('https://url.firebaseio.com/days');
console.log("start");
console.log("before load?");
$scope.items = angularFireCollection(ref, function()
{
console.log("loaded?");
console.log($scope.items[0]); //undefined
});
console.log("start() out");
};
$scope.start();
//wait for changes
$scope.$watch('items', function() {
console.log("items watch");
console.log($scope.items[0]); //undefined
});
$scope.testData = function()
{
console.log($scope.items[0].properties); //not undefined
};
}
]);
My view:
<button ng-click="testData()">Is the data loaded yet?</button>
Thanks in advance!
So, does anyone know how I can know when all the data has been loaded
and then assign it to a $scope variable to be displayed in my view? Or
is there another way?
Remember that all Firebase calls are asynchronous. Many of your problems are occurring because you're trying to access elements that don't exist yet. The reason the button click worked for you is because you clicked the button (and accessed the elements) after they had been successfully loaded.
In the case of the optionalCallbackOnInitialLoad, this is a function that will be executed once the initial load of the angularFireCollection is finished. As the name implies, it's optional, meaning that you don't have to provide a callback function if you don't want to.
You can either use this and specify a function to be executed after it's loaded, or you can use $q promises or another promise library of your liking. I'm partial to kriskowal's Q myself. I'd suggest reading up a bit on asynchronous JavaScript so you get a deeper understanding of some of these issues.
Be wary that this:
$scope.items = angularFireCollection(ref, function()
{
console.log("loaded?");
console.log($scope.items[0]); //undefined
});
does correctly specify a callback function, but $scope.items doesn't get assigned until after you've ran the callback. So, it still won't exist.
If you just want to see when $scope.items has been loaded, you could try something like this:
$scope.$watch('items', function (items) {
console.log(items)
});
In my project I needed to know too when the data has been loaded. I used the following approach (implicit bindings):
$scope.auctionsDiscoveryPromise = angularFire(firebaseReference.getInstance() + "/auctionlist", $scope, 'auctionlist', []);
$scope.auctionsDiscoveryPromise.then(function() {
console.log("AuctionsDiscoverController auctionsDiscoveryPromise resolved");
$timeout(function() {
$scope.$broadcast("AUCTION_INIT");
}, 500);
}, function() {
console.error("AuctionsDiscoverController auctionsDiscoveryPromise rejected");
});
When the $scope.auctionsDiscoveryPromise promise has been resolved I'm broadcasting an event AUCTION_INIT which is being listened in my directives. I use a short timeout just in case some services or directives haven't been initialized yet.
I'm using this if it would help anyone:
function getAll(items) {
var deferred = $q.defer();
var dataRef = new Firebase(baseUrl + items);
var returnData = angularFireCollection(dataRef, function(data){
deferred.resolve(data.val());
});
return deferred.promise;
}