Can't add object to another object with map - javascript

I've ran into a problem I've never seen before in javascript. Here's the essence of what I am doing
var doStuff = function(stuff, otherstuff){
return _.map(stuff, function(s){
// Thing needed is a fairly big object
var thingNeeded = _.find(otherstuff, function(os){
return os.whatineed;
});
var new_thing = _.clone(s);
new_thing.new_field = thingNeeded;
return new_thing;
});
};
But this returns a list that is the original stuff list! It even occurs if I do this variation
var doStuff = function(stuff, otherstuff){
return _.map(stuff, function(s){
// Thing needed is a fairly big object
var thingNeeded = _.find(otherstuff, function(os){
return os.whatineed;
});
s.new_field = thingNeeded;
return s;
});
};
or
var doStuff = function(stuff, otherstuff){
return _.map(stuff, function(s){
// Thing needed is a fairly big object
var thingNeeded = _.find(otherstuff, function(os){
return os.whatineed;
});
s['new_field'] = thingNeeded;
return s;
});
};
Or variations using _.extend() and _.create(). It also doesn't work with the map in the array prototype.
I have no idea what I may be doing wrong here. Its completely ignoring me adding the field. Can anyone help?
EDIT: for the record
[{thing: 1}, {thing: 2}].map(function(t){
t.welp = 'welp';
});
will return [{thing: 1, welp: 'welp'}, {thing: 2, welp: 'welp'}] as expected. So its somewhere inside the map.
EDIT AGAIN:
var doStuff = function(stuff, otherstuff){
return _.map(stuff, function(s){
// Thing needed is a fairly big object
var thingNeeded = _.find(otherstuff, function(os){
return os.whatineed;
});
var new_thing = _.clone(s);
new_thing.new_field = thingNeeded;
console.log('stuff:', new_thing.new_field);
return new_thing;
});
};
The console.log will return the value we'd expect (thingNeeded).
Thank you!

I think you are using stuff within your map iterator when you should be using the currently iterated object 's'.
Here is a working fiddle http://jsfiddle.net/rzkvne23/
var doStuff = function(stuff, otherstuff){
return _.map(stuff, function(s){
var thingNeeded = _.find(otherstuff, function(os){
return os.whatineed === 2;
});
var new_thing = _.clone(s);
new_thing.new_field = thingNeeded;
console.log('stuff:', new_thing.new_field);
return new_thing;
});
};
var a = [{},{},{}];
var b = [{whatineed: 1},{whatineed:2},{whatineed:3}];
console.dir(doStuff(a,b));

Related

Adding properties to an object using function and bracket notation

I have an assignment on a basic javascript class that I'm taking and I can't seem to get this to work. I have this unit test that was given to me:
describe('AddSixthProperty', function() {
it('should add a food property with the value of bbq using bracket notation', function() {
expect(objects.addSixthProperty()['food']).to.equal('BBQ');
});
});
I was given an empty function:
// don't touch this line
var mysticalAnimal = objects.mysticalAnimal();
function addSixthElement(){
return
}
So I tried this:
var mysticalAnimal = objects.mysticalAnimal();
objects.addSixthProperty = function(){
mysticalAnimal['food'] = "bbq";
return mysticalAnimal["food"];
};
It doesn't work. Our test page doesn't pass that. Any help is greatly appreciated!
Thanks in advance!
You're returning mysticalAnimal['food'], and then the test tries to access ['food'] again, so it ends up accessing 'bbq'['food'], which is undefined. You need to just return mysticalAnimal, as well as get all your letter cases right. Here's a little proof of concept:
var objects = (function() {
var animal = { mystical: true };
return {
mysticalAnimal: function() { return animal; }
};
})();
var mysticalAnimal = objects.mysticalAnimal();
objects.addSixthProperty = function(){
mysticalAnimal['food'] = "bbq";
return mysticalAnimal;
};
var capturedAnimal = objects.addSixthProperty();
document.getElementById('result').innerText = capturedAnimal['food'];
<p id="result" />
Here is the function:
var mysticalAnimal = objects.mysticalAnimal();
objects.addSixthProperty = function(){
mysticalAnimal['food'] = "BBQ";
return mysticalAnimal;
};
// Test the function
console.log(objects.addSixthProperty()['food'])

Protractor: Return Repeater Count from Prototype

I have this behavior which I can't understand:
Cart.prototype.getCouponsCount = function() {
// Loop through all rows of coupons currently available in the cart
ele.cartCouponsList.count().then(function(count) {
console.log("Amount of items in cart:", count);
return count;
});
};
When called like this:
var Cart = require("../../../../lib/cartlib");
var cart = new Cart();
expect(cart.getCouponsCount()).toBe(2);
Returns undefined, but in console I can see the correct coupon amount being printed. So it's just not returning the count back.
Similarly I have this working for the getText() method, therefore why I can't understand why the count() method would behave differently.
Working method:
Cart.prototype.getEvent = function(row) {
var cartHistory = new Cart();
var parent = cartHistory.getCartCoupon(row);
var child = parent.element(by.binding("selection.event.name"))
.getText().then(function(e) {
console.log(e);
return e;
});
};
Anyone can point me in the right direction?
There is no return from the function, add it:
Cart.prototype.getCouponsCount = function() {
// HERE
return ele.cartCouponsList.count().then(function(count) {
console.log("Amount of items in cart:", count);
return count;
});
};

Losing scope on recursive call

I'm creating a module that accepts a data set and an integer n and recursively fills that dataset with n products at a time, after the first call, the function loses its scope and errors out. Why, And what's the best practice for fixing this?
Code:
function ProductFactory(){
var bigArr = [0,1,2,3,4,5,6,7,8,9];
var smallArr = [1,2,3,4];
return {
getProductList: getProductList,
getAllProducts: getAllProducts
};
function getProductList(start, size){ return start < 5 ? bigArr : smallArr }
function getAllProducts(batchSizeRequested, dataSet) {
var startPage = dataSet.length / batchSizeRequested;
var productBatch = this.getProductList(startPage, batchSizeRequested);
dataSet = dataSet.concat(productBatch);
if (productBatch.length === batchSizeRequested)
getAllProducts(batchSizeRequested, dataSet);
}
}
var productGetter = new ProductFactory();
productGetter.getAllProducts(10, []);
1) First of all you shouldn't call getProductList using this, in this case you can just call it as it is, because getProductList is not a function that was assigned directly to this object. It is just a closure that uses local variables in it's code. If you want to call function using this, you should assign it using this, for example this.getProductList = function() {}
2) I don't think there are other scoping problems except redundant this, but I found another issue, though.
You are not actually return anything from your function, plus recursive call does not have an exit point.
Fixed code looks like this.
function ProductFactory(){
var bigArr = [0,1,2,3,4,5,6,7,8,9];
var smallArr = [1,2,3,4];
return {
getProductList: getProductList,
getAllProducts: getAllProducts
};
function getProductList(start, size){ return start < 5 ? bigArr : smallArr }
function getAllProducts(batchSizeRequested, dataSet) {
var startPage = dataSet.length / batchSizeRequested;
var productBatch = getProductList(startPage, batchSizeRequested);
dataSet = dataSet.concat(productBatch);
if (productBatch.length === batchSizeRequested) {
return getAllProducts(batchSizeRequested, dataSet);
} else {
return dataSet;
}
}
}
var productGetter = ProductFactory();
var products = productGetter.getAllProducts(10, []);
console.log(products)
The typical approach to a function call like this is to assign an external value to this (typically called self):
function ProductFactory(){
...
var self = this;
function getAllProducts(batchSizeRequested, dataSet) {
...
getAllProducts.apply(self, [batchSizeRequested, dataSet]);
}
}
In this case, however, please try to remember that you have defined a closure function getAllProducts that is only privately accessible internal to the constructor. Instead you should probably do:
function ProductFactory(){
...
var self = this;
this.getAllProducts = function(batchSizeRequested, dataSet) {
...
self.getAllProducts(batchSizeRequested, dataSet);
}
}

Closure issue with KnockoutJs

It seems I have a closure problem here: http://jsfiddle.net/vtortola/NMHQ6/
The code adds some bars to the screen and it should reduce the size of all of them, but it only happens in the last one.
var bar = function(start){
me = {};
me.width = ko.observable(start);
var countDown = function(milliseconds, step, callback){
callback(milliseconds);
if(milliseconds>0)
setTimeout(function(){ countDown(milliseconds-step,step,callback);}, step+10);
};
countDown(start, 1, function(m){me.width(m); });
return me;
}
var viewModel = function(){
var me ={};
me.bars = ko.observableArray();
for(var i=0;i<20;i++){
me.bars.push(bar(300));
}
return me;
}
ko.applyBindings(viewModel);
But I cannot find the problem.
Your are missing the var keyword in the bar function and so, your me variable is declared in the global scope. For this reason, and since in javascript objects are passed by reference, your me.bars is filled with the same content.
A simple fix will be :
var bar = function(start){
var me = {};
me.width = ko.observable(start);
var countDown = function(milliseconds, step, callback){
callback(milliseconds);
if(milliseconds>0)
setTimeout(function(){ countDown(milliseconds-step,step,callback);}, step+10);
};
countDown(start, 1, function(m){me.width(m); });
return me;
}
Hope it helps.

Can't create functions in javascript object

I have two objects
function Response(dbResponseId, responseText){
this.response = {
"dbResponseId" : dbResponseId,
"responseText" : responseText,
"isDeleted" : false,
};
this.setResponseText = function(responseText){
this.response.responseText = responseText;
return this.response;
};
this.getId = function(){
return this.response.frontEndId;
};
this.deleted = function(){
this.response.isDeleted = true;
};
return this.response;
}
function OptionGroup(responses, dbOptionGroupId,isDeleted,id){
this.optionGroup = {"dbOptionGroupId" : dbOptionGroupId, "responses" : responses, "isDeleted" : isDeleted,"frontEndId" : id};
this.setResponses = function(responses){
this.optionGroup.responses = responses;
return this.optionGroup;
};
this.addResponse = function(response){
this.optionGroup.responses.push(response);
return this.optionGroup;
};
this.getId = function(){
return this.optionGroup.frontEndId;
};
this.setId = function(id){
this.optionGroup.frontEndId = id;
return this.optionGroup;
};
this.deleted = function(){
this.optionGroup.isDeleted = true;
return this.optionGroup;
};
this.getResponsesById = function(id){
for(var i = 0; i < this.optionGroup.responses.length;i++){
if(id == this.optionGroup.responses[i].getId()){
return this.optionGroup.responses[i];
}
}
return null;
};
return this.optionGroup;
}
However, when I try and call any of the functions that I've created, console tells me that said object does not have such a function. When I print out a Response or OptionGroup object in console, I can see the fields in the objects, but I cannot see any of the functions.
What is going on?
When you return something from an object used as a constructor, as the above code does, that value is the result of the new call. Note that neither returned object (this.response and this.optionGroup) has the functions you're interested in calling.
The simplest solution is to remove the returns.
Dunno if Matt's answer was clear, but:
> return this.optionGroup;
means the function returns the optionGroup object, not the new object referenced by this.
Constructors return this by default, so no return statement at all is equivalent to:
return this;
Same for the Response function.
Assuming of course that you are calling the functions with new.

Categories