I'm working in Angular (angularfire) trying to combine two firebaseArrays into a single object, but the asynchronous nature of the return calls is making it difficult. I would like to do something simple like:
$scope.itemStats = $firebaseStorage.getArray('item-stats');
$scope.stats = $firebaseStorage.getArray('stats');
$scope.newArray = $scope.itemStats.concat($scope.stats);
The code for the getArray function is:
getArray: function(key) {
var dbRef = ref.child(key);
return $firebaseArray(dbRef);
}
It's possible I'm querying the data wrong in the first place, and could grab both at the same time which would also solve my problem (aka, I'm asking the wrong question).
Which approach should I use, and how do I solve this?
You can use the $loaded which will return a promise resolved when loading the array is done.
An example from the documentation
var list = $firebaseArray(ref);
list.$loaded()
.then(function(x) {
// now "list" is loaded
})
Related
I am having some trouble currently with a project I am working on. Essentially I am trying to run multiple tests from different files together in separate describe blocks.
In the first test I would like to to set up all of the parameters and then in the second test I would like to use those parameters to fill out a form. With the way promises and describes work I am wondering if this is even possible. Does anyone have any suggestions?
I haven't tried much other than trying to make my objects global which I would prefer to stay away from and passing my objects into the second describe which doesn't work since it gets passed in before the first describe finishes and actually assigns value to them.
describe('0', function () {
let objectToPassAround = {}
describe('1', function () {
const test1 = require('#file1');
test1.runTest();
});
describe('2', function () {
const test2 = require('#file2');
test2.runTest();
});
});
For example, in the above, I would want to set the value of objectToPassAround in test1 and use that object, with it's newly set values, in test2.
Thanks!
You can wrap all of it in a bigger describe.
describe('0', () => {
let objectToPassAround = {};
describe('1', () => {
// you should have access to objectToPassAround
});
describe('2', () => {
// you should have access to objectToPassAround
});
});
Something to be careful is that if you're using Jasmine, the tests may run in random order and so if you set the object in test 3 and then expect for it to be set in test 4, it may not be the case. Test 4 can run before test 3. This is a feature to ensure the order of the tests do not matter since each one should be independent of each other.
I am having troubles with some parts of my code randomly.
This object is declared in a angular controller.
this.tData = {
'questions':[],
'typeQuestion':[],
'category':[],
'dName':this.dName,
'tCodigo':this.tCodigo}
Then I got some data from others functions and push it into respective fields,
this.tData.questions.push(this.idQuestion) // this come from frontend ng-model
this.tData.typeQuestion.push(this.typeQuest) // this come from frontend ng-model
this.tData.category.push(this.idCategory)// this come from frontend ng-model
This construct my object fine. Doing console.log(this.tData) show me the object completely fine. But then when I pass it to the backend in this function of the angular service.
this.updateStuff = function(codStuff,tData){
return $http.put('/updateStuff' + codStuff,tData)}
The object that backend get doing console.log(params) is
{
questions:['exampleId'],
typeQuestion:['exampleData'],
category:[], // HERE IS THE PROBLEM
dName:'exampleName',
tCodigo:'exampleCod'}
Like you see category:[] is empty but doing console.log(tData) in the service of angular before I send it I see the correct data there.
I miss data when I send it to the backend. This problem happend to me in 3 others cases like this.
Why some arrays are ok in backend and why others are not?
I tried a lot of things but ever 1 item of the object I send to the backend go empty.
If you need more specific code tell me in comments.
Updates
Code here I push category in the controller:
this.getCategoryByName = function(){
this.bName = document.getElementById('seCategory').value;
Category.getCategoryByName(this.bName).then((result)=>{
this.idCategory = result.data.data._id; // this give me id of category
this.tData.category.push(this.idCategory);
})
}
2
This is where I call in frontend my functions:
<button class="btn btn-primary" ng-click="ctController.getCategoryByName(); ctController.updateTest();" > up </button>
This is the code of updateTest() function:
this.updateTest = function(){
Test.updateTest(this.codTest,this.tData).then(result=>{})
}
Above method call the angular service updateStuff
SOLVED
Solved adding a chain promise in the method getCategoryByName and adding the updateTest() method nested in getCategoryByName() method more or less like #T.J. Crowder sugest so I give it the response.
Code here I push category in the controller:
this.getCategoryByName = function(){
this.bName = document.getElementById('seCategory').value;
Category.getCategoryByName(this.bName).then((result)=>{
this.idCategory = result.data.data._id; // this give me id of category
this.tData.category.push(this.idCategory);
})
}
That tells us that you're calling updateStuff before Category.getCategoryByName has finished its work, and so before this.tData.category.push is called. The reason console.log seems to show you things in this.tData.category is (as I mentioned in a comment) because of deferred evaluation in the console.
This also explains why it happens sometimes: You have a race between that Category.getCategoryByName operation and the operation calling updateStuff. Sometimes, Category.getCategoryByName wins and so updateStuff includes the pushed information, other times the code calling updateStuff wins and so updateStuff doesn't have the information in this.tDate.category (yet).
this.getCategoryByName should return the promise chain:
this.getCategoryByName = function(){
this.bName = document.getElementById('seCategory').value;
return Category.getCategoryByName(this.bName).then((result)=>{
// ^^^^^^
this.idCategory = result.data.data._id; // this give me id of category
this.tData.category.push(this.idCategory);
});
};
...and then you should make whatever is calling updateStuff dependent on the resolution of that promise.
(You'll also want to ensure that something handles the chain's rejection path. Your current getCategoryByName ignores errors, which will lead to "Unhandled rejection" errors in the console if Category.getCategoryByName fails.)
So, I have a lot of places with code, when I push some elements to array:
arr.push(...)
But the problem is, that I would like to run custom code after each push. Basically the question is not only about this example. What I want to do is something like this:
func1.func2(...);
After this I want to run another function which will get all things, which func2 did and for example log it. But these functions in code are a lot and it is not desirable to write something like this every time:
if (func1.func2(...)) {
log_results();
}
Instead, for every func1.func2() I want automatically run another separate function, which will get results and log it.
The only way to really accomplish this is to wrap it in a function that does the extra work you want.
function pushAndLog(item) {
arr.push(item);
// Additional Code here
logResults();
}
This is an interesting question. There are plenty of libraries like Lodash that do similar things to functions. Like methods that return copies of functions with arguments partially applied: _.curry. I tested it and it works on Array.prototype.push.
Doing some research I found this post with this answer: JavaScript: clone a function and decided to try to do what you wanted without making the clone method.
Here is what I came up with. Replace the console.log with a call to any function you like or any other code you wish.
Array.prototype.push = (function() {
var old = Array.prototype.push;
var push = function () {
console.log('my new push where I can do what I want, like log some stuff');
return old.apply(this, arguments)
};
return push;
})();
var foo = [];
foo.push(1,2,3);
console.log(foo);
You could add another prototype to Array that uses push inside and then whatever else you want to execute.
let testArr = [];
Array.prototype.pushPlusStuff = function(val) {
this.push(val);
console.log("executing other stuff here");
};
testArr.pushPlusStuff("test");
console.log(testArr);
This will make the .pushPlusStuff method available to all Arrays
Actually gforce301 code helped me. I was dealing with Google dataLayer and the task was to log all push data (except some). This code snippet helped me:
var dataLayer_copy = dataLayer.push;
dataLayer.push = function() {
dataLayer_copy.apply(this, arguments);
console.log(JSON.stringify(arguments));
$.post('/log', {data: arguments}, function() {
}, 'json');
};
I'm trying to learn javascript to work with node.js and obviously don't quite get closures.
I'm try to read a file, line by line, parse the line and put the result into an array and return the array. Here's what I have (doesn't quite work):
var fs = require('fs'), Lazy = require('lazy');
function parseMyFile (filename) {
var myArray= [];
var lazy = new Lazy (fs.createReadStream(filename));
lazy
.lines
.map(function(line){
var parts = line.toString().split('|');
var item = {
bucket: parts[1],
uri: parts[2].substring(2),
token: parts[0],
fileDate: parts[3]
};
myArray.push (item);
});
console.log(myArray); // empty
return myArray;
};
var myItems = parseMyFile ('Tokens.csv');
I'm sure this has something to do with closures, just not quite getting it. Any help would be appreciated.
Thanks!
It's a lazy list. It's a wrapper around asynchronous behavior. You're trying to examine the list before it's been filled in, so of course it doesn't work.
The problem has nothing to do with closures. It's all about asynchronous behavior.
I don't see anything in that lazy list code that allows a generic "when finished" callback.
I am trying to write a javascript class that loads script files as they are needed. I have most of this working. It is possible to use the library with the following Syntax:
var scriptResource = new ScriptResource('location/of/my/script.js');
scriptResource.call('methodName', arg1, arg2);
I would like to add some additional syntactic sugar so you could write
var scriptResource = new ScriptResource('location/of/my/script.js');
scriptResource.methodName(arg1, arg2);
I'm almost certain that this isnt possible but there may be an inventive solution. I guess what there need to be is some sort of methodCall event. SO the following could work
ScriptResource = function(scriptLocation)
{
this.onMethodCall = function(methodName)
{
this.call(arguments);
}
}
This code is obviously very incomplete but I hope it gives an idea of what I am trying to do
Is something like this even remotely possible?
There is a non standard method, __noSuchMethod__ in Firefox that does what you're looking for
have a look at
https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/Object/noSuchMethod
so you could define
obj.__noSuchMethod__ = function( id, args ) {
this[id].apply( this, args );
}
If the set of method names is limited, then you could generate those methods:
var methods = ["foo", "bar", "baz"];
for (var i=0; i<methods.length; i++) {
var method_name = methods[i];
WildCardMethodHandler[method_name] = function () {
this.handleAllMethods(method_name);
};
}
edit: Posted this answer before the question changed dramatically.
An intermediary solution might be to have syntax such as:
var extObj = ScriptResource('location/of/my/script.js');
extObj('methodname')(arg1,arg2);
the code might look like this:
function ScriptResource(file) {
return function(method) {
loadExternalScript(file);
return window[method];
}
}
All kinds of assumptions in the code above, which I'd let you figure out yourself. The most interesting, IMHO, is - in your original implementation - how do you get the proxyied method to run synchronously and return a value? AFAIK you can only load external scripts asynchronously and handle them with an "onload" callback.