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: ''
};
Related
I want to display view once the list of content is retrieved from the database display it in the view.
On a high level what I am doing now works more or less but upon first access the previous results appears to be cached or still saved in my storage service.
This is what the service looks like.
function StorageService() {
var opportunities;
var getOpportunities = function() {
return opportunities;
}
var setOpportunities = function(data) {
opportunities = data;
}
return {
getOpportunities: getOpportunities,
setOpportunities: setOpportunities
}
}
So when I click on the tab to getOpportunities I go direct to the view first and the load the data.
$scope.getAllOpportunities = function() {
$state.go("app.opportunities");
communicationService.getOpportunitiesAll().then(function(data) {
StorageService.setOpportunities(data);
if (!data.length) {
$("#noShow").html("There are no opportunities");
}
}, function(error) {})
}
once the view is rendered I retrieve the results and bind it to the view.
controller('OpportunitiesController', function($scope) {
$scope.$on("$ionicView.afterEnter", function(scopes, states) {
$scope.opportunities = StorageService.getOpportunities();
});
What I am doing here also feels a bit wrong.
Is there a better way or a way that I can improve on the existing.
I want to load the view and the replace the loader with the data once the data is ready.
Thanks in advance
You should resolve the promise in the route, using the resolve property. That way, the data will always be available when the controller is instantiated.
https://toddmotto.com/resolve-promises-in-angular-routes/
Unless the resource is huge and you want to show som loading animation while getting the data. Then it would probably be more proper to just get the data in the controller.
controller('OpportunitiesController', function($scope) {
communicationService.getOpportunitiesAll().then(function(response){
$scope.opportunities = response;
})
});
html:
<span ng-if="!opportunities">Getting stuff</span>
<span ng-if="opportunities">Stuff fetched</span>
Also, there is no use to have getter and setters in the service. Javascript objects are passed by reference so you can just expose the property directly.
I'm using angular-timer and I'm just a little confused how to track its events. For example, I want to do something after time is up, but I can't see any events on console log.
vm.add20Seconds = function() {
$scope.$broadcast('timer-add-cd-seconds', 20);
}
$scope.$on('timer-add-cd-seconds', function (event, data) {
console.log(data); // 'Some data'
});
The console is empty.
https://github.com/siddii/angular-timer/blob/master/examples/angularjs-add-countdown-seconds.html
As the code given in link is not seems to be updated, I think you changed it to use controllerAs syntax. So your button html will use vm alias while calling controller method. Assuming you used ng-controller="MyAppController as vm"
Markup
<button type="button" ng-click="vm.add20Seconds()">Add 20 Seconds</button>
Else wanted to use $scope in your controller then simply change method to $scope.add20Seconds instead of vm.add20Seconds
Update
To get call a function after 20 seconds over, you could use $timeout service here, that will call and specified callback when mentioned $timeout completed.
Code
vm.add20Seconds = function() {
$scope.$broadcast('timer-add-cd-seconds', 20);
}
var myCallbackAfterTimeout = function(){
//add your code.
}
$scope.$on('timer-add-cd-seconds', function (event, data) {
console.log(data); // 'Some data'
$timeout(myCallbackAfterTimeout, data); //data is nothing but timeout milliseconds
});
Include $timeout dependency in your controller before using it.
if you are looking for a good article about using the scope tree As A Publish And Subscribe (Pub/Sub) mechanism in angularJS please check this link
I am writing some forms for adding and editing resources. I am using Angucomplete-alt (https://github.com/ghiden/angucomplete-alt) and my own dropdown directive to get choices from the database. Those are in a separate controller from the main form. My regular text fields populate fine on the edit form, but I have issues with the Angucomplete and selects. The scope data is there on page load. I have written a function to grab it using the ID in the URL. But they don't always populate unless you reload the page. How can I get them to populate EVERY time?
Here is my function to populate the form:
$scope.popForm = function(clientId) {
var config = {
params: {clientId: $stateParams.clientId},
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
};
$http.get('assets/php/clients/pop_client.php', config)
.then(function(data) {
var realStatus = data.data.status;
if(realStatus == 'success'){
//Set the $scope from the JSON response
$scope.client = data.data.client;
//Broadcast a bunch of events with data to the dropdowns
$timeout(function() {
$rootScope.$broadcast('setTypeDropdown', data.data.client.type);
$rootScope.$broadcast('setCatDropdown', data.data.client.category);
$rootScope.$broadcast('setTeamDropdown', data.data.client.team);
$rootScope.$broadcast('setA1Dropdown', $scope.client.assigned1);
$rootScope.$broadcast('setA2Dropdown', $scope.client.assigned2);
});
}
});
};
I have another controller that takes care of the selects, so that's why there are broadcasts of the data down to their isolated scopes. Here is one of the $on functions, since they are all basically the same. (There MUST be a less convoluted way of doing this...)
// Options are the select options that I get from the database
// for each instance of the select controller
$scope.$on('setTypeDropdown', function(event, type) {
var i = 0;
$.each($scope.options, function(){
if (this.value == type){
$scope.client.type = $scope.options[i];
}
i++;
});
});
So, IS there a better way of doing this? Because this doesn't quite work...
EDIT: Angucomplete-alts are working well now. Just my convoluted selects to worry about. Wonder if it wouldn't be better to de-Angularize them and not use my directive.
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;
}
});
}])
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;
}