AngularFire - $firebaseArray can $add but not read - javascript

I feel like I must be missing something very basic. Here is a portion of my service:
angular.module('fire')
.constant('FIREBASE_URI', 'https://___.firebaseio.com/')
.factory('syncArraySvc', function(FIREBASE_URI, $firebaseArray) {
var buildingsUri = FIREBASE_URI + "buildings";
var buildings = $firebaseArray(new Firebase(buildingsUri));
console.log(buildings);
var getBuildings = function() {
return buildings;
};
var addBuilding = function(item) {
buildings.$add(item);
};
return {
getBuildings: getBuildings,
addBuilding: addBuilding
};
});
The console.log in the middle of that just returns an empty array. If I try to call the syncArraySvc.getBuildings() function from another controller, I also get an empty array. Somehow, $add(item) works, as does syncArraySvc.addBuilding(item). What am I missing?

If you look at $add $firebaseArray, It does create new item & add it into to $firebaseArray as like we have buildings. But as soon as you add item to ``$firebaseArray` it doesn't get added instantly. It get added when the $add promise get resolved.
I think you are doing correct thing, only you need call syncArraySvc.addBuilding(item) method on success of $add promise.
To make this approach you need to return a promise from the service method like
var addBuilding = function(item) {
return buildings.$add(item);
};
And then the caller function will take that promise and on resolve of it, he will call syncArraySvc.addBuilding(item) method that have assurity that items has added in buildings array.
syncArraySvc.addBuilding({foo: "bar"}).then(function(addedItem){
console.log(addedItem);
console.log(syncArraySvc.addBuilding(item)); //this will show you updated list
})

The other answers helped get me pointed in the right direction.
The API documentation has a code sample that doesn't seem to need the data to be wrapped in a promise:
var list = $firebaseArray(new Firebase(URL));
$scope.list = list;
However, it does point out that you can use the $loaded promise to be notified when the data is loaded. This is how I got it to work in my project:
syncArraySvc.getBuildings().$loaded(function(data) {
$scope.buildings = data;
});
I tried replicating this in a fresh project, and it consistently worked without the $loaded wrapper, like they show in the first example. It makes sense to me that the $loaded wrapper would be required. I don't understand how it could be working in the first example without it.

Try using a $timeout service inside the getBuildings function or rather when you call it. It probably takes a little while before data is returned.

Related

AngularJS: How to use ngOption to iterate data from cached Api call

I have an application in which I am making multiple API calls and caching that data for later. Then someone else in the app, I want to retrieve that data and list it in a drop down using ng-option.
To get the cached data for each call, I am doing
var httpCache = $cacheFactory.get('$http');
var cachedImpactedEntities = httpCache.get('my api url');
This returns an object of an array in an array like so:
[200,"[ {
"entity_id": 1,"entity_desc": "test1" },
{"entity_id": 2,"entity_desc": "test2"}]",
{"content-type":"application/json;
charset=utf-8"},"OK"]
What would be a good way to extract just the inside array in quotes and output each "entity_desc" to the drop down using ng-option like:
test1
test2
...
The way the cached information comes back is confusing me.
Thanks.
If I understand you correctly the following shall be sufficient:
$scope.cachedEntities = eval(cachedImpactedEntities[1]);
<select ng-options="item as item.entity_desc for item in cachedEntities track by item.entity_id" ng-model="selected"></select>
But that means you will need to update "manually" the cachedEntities each time you get the data back from api call.
Consider of using promise construct:
$http.get("url+parameters").then(function(data) { $scope.cachedEntities = data}, function(){ // do something on error });

Angularjs click row if the data is available

I'm new to JavaScript so I am not sure what is possible. I am using AngularJS as my frontend application.
I've a clickable table(rows) its pretty much a table inside a table (collapisble table)
I'm trying to click the first row of the table if the data is available so I wrote this function
$scope.clicker = function(){
if (!$scope.first || !$scope.second){
setTimeout($scope.clicker, 500)
}
$(".clickableRow").first().click()
}
This pretty much checks if the values first and second is not null, if not then click the first row. This WOULD work sometimes but almost every time I get this error '
Error: [$rootScope:inprog] $digest already in progress
http://errors.angularjs.org/1.4.3/$rootScope/inprog?p0=%24digest
I am not sure what this means. Any help would be nice.
Using $q.all you can pass in multiple $http requests in an array.
You can use .then on the q.all() method and get a callback when they're all done.
$scope.$watch(
function() {
return $route.current;
},
function(newValue) {
if (newValue) {
$scope.url = newValue.$$route.originalPath;
if($scope.url == '/loadTestForm') return;
$scope.neustaridParam = newValue.params.neustarid;
$q.all([
$http.get('/corecase/browserKPI/'+$scope.neustaridParam).success(function(response){
$scope.browserKPI = response;
}),
$http.get('/corecase/serverKPI/'+$scope.neustaridParam).success(function(response){
$scope.serverKPI = response;
}),
$http.get('/corecase/info/'+$scope.neustaridParam).success(function(response){
$scope.corecaseinfo = response;
})
]).then(function(){
$scope.selectTableRow(0, 1000); //I'd advise not hardcoding the first row's data here. You can do something like this instead: $scope.storeDataModel.storedata[0].id, scope.storeDataModel.storedata[0].storeId
});
}
}
);
If the only purpose behind the click event is to show or hide then you can potentially skip the click event all together. Put a "ng-show" in your tr (or any other element you want to show) and simply set a scoped variable equal to whatever is referencing your data. If you have data then your ng-show will be true and it will show. This is also assuming that your data is undefined or null until it is available, if not just set it to false.
In view:
<tr ng-show="checkData"></tr>
In controller:
$scope.checkData = data;

Filter json data in controller, the right way

(there are other questions but neither helped me out)
Hi, I would like to know if this is the right way to filter the results I get from service where I'm displaying only one result (like a detail).
I know I could use ng-repeat and filter it in the view and that is the cleanest, but I want to have more control over because I will re-use some of the data in the controller for other operations.
Right now I'm doing this:
$scope.savedEvents = Event.getPayedEvents(); //gets a list from service
//Goes through entire list and checks for a match
angular.forEach($scope.savedEvents, function(event) {
if (event.IdEvent == $stateParams.eventId) {
$scope.showEvent = event;
}
});
//now if there is a match I can use $scope.showEvent.eventName etc
Not sure if this would be easier using $filter to return just one event that has correct IdEvent. Or if someone has better solution, please let me know.
thanks
I don't see any problems with what you have, but you could inject the $filter service and do this one liner:
$scope.showEvent = $filter('filter')($scope.savedEvents, { IdEvent: $stateParams.eventId });
EDIT: Here is an easy way to resolve the result to a single value from the returned array:
var showEvents = $filter('filter')($scope.savedEvents, { IdEvent: $stateParams.eventId });
$scope.showEvent = showEvents && showEvents.length ? showEvents[0] : null;
In CoffeeScript it is a little more concise:
$scope.showEvent = $filter('filter')($scope.savedEvents, { IdEvent: $stateParams.eventId })?[0]

node.js/javascript/couchdb view to associative array does not seem to work

I am trying to create a webapp on a node/couchdb/windows stack but get terribly stung by what seems to be a lack of experience.
In the database, there is a view that returns all users with passwords. Based on the tutorial for a blog I have tried to access the view through my node code.
Whenever I investigate the structure of the users or users variable, I get an undefined object.
The call to getDatabase() has been tested elsewhere and works at least for creating new documents.
function GetUser(login)
{
var users = GetUsers();
return users[login];
}
function GetUsers() {
var db = getDatabase();
var usersByEmail = [];
db.view("accounts", "password_by_email")
.then(function (resp) {
resp.rows.forEach(function (x) { usersByEmail[x.key] = x.value});
});
//usersByEmail['test'] = 'test';
return usersByEmail;
}
I am aware that both the use of non-hashed passwords as well as reading all users from the database is prohibitive in the final product - just in case anyone wanted to comment on that.
In case something is wrong with the way I access the view: I am using a design document called '_design/accounts' with the view name 'password_by_email'.
Your call to db.view is asynchronous, so when you hit return usersByEmail the object hasn't yet been populated. You simply can't return values from async code; you need to have it make a callback that will execute the code that relies on the result.

How do I call a function stored in a jQuery array?

I have an array of hooks in jQuery that are executed before I load data into a grid. In one case, however, I want to remove the hook, then add it back for later. Whatever I'm doing is not working just right... it's probably a syntax error because I'm still somewhat new to jQuery. Any help would be appreciated, thanks!
Current code:
var preLoad = this.opts.hooks.preLoad.pop();
//stuff happens
//now I want to add the preLoad hook back
this.opts.hooks.preLoad.push(function(report) { preLoad(report); });
EDIT
It turns out the issue lies elsewhere in the code. However, I'd still like to know how best to accomplish this.
You access it the same way as any other variable stored in any other array.
this.opts.hooks.preLoad[0](myReport)
Can you not just add the function you removed like this?
var preLoad = this.opts.hooks.preLoad.pop();
//stuff happens
//now I want to add the preLoad hook back
this.opts.hooks.preLoad.push(preLoad);
And are you sure it's always the last one in the array that you want to remove?
It probably has to do with the fact that you are "canning" the argument "report" when you push the function back on the stack.
Try doing it like that:
var preLoad = this.opts.hooks.preLoad.pop();
//stuff happens
//now I want to add the preLoad hook back
this.opts.hooks.preLoad.push(preLoad);
I've tested it here http://jsfiddle.net/fWRez/
The example you gave has nothing to do with jQuery and is pure Javascript. Also, beware that what you are doing in your example is... not right. Consider this :
var ReportManager {
...
replace: function(report) {
var preLoad = this.opts.hooks.preLoad.pop();
//stuff happens
//now I want to add the preLoad hook back
this.opts.hooks.preLoad.push(function(report) { preLoad(report); });
}
}
If you execute this :
replace(null);
replace({foo:'bar'});
replace(null);
Your this.opts.hooks.preLoad array will look like this :
Array(
0: function(report) { return function(report) { return function(report) { ... } } }
)
Because you are pushing the function wrapped into itself every time you execute your code. I'm not sure why you need to pop and push it back in again, but this just look odd.
Also, Javascript is a very flexible language; which mean that you can do many weird stuff, like
"hello".concat(" world"); // -> 'hello world'
0.toString(); // -> '0'
(function(a) { return a; })("foo"); // -> 'foo'
(function() { return false; })() || (function() { return true; })(); // -> true (executes both functions)
(function(i) { return [i*2,i*3,i*4]; })(2)[1]; // -> 6
$('selector')[0]; // ...
// etc.

Categories