setting "x" number of parameter to function property - javascript

I am trying to create a generic function where you are able to pass an object that has a property of a random function. With this you should be able to set a property stating the key and value for each parameter of the function.
the generic function should then call this "random" function with all the parameters.
However im not quite sure how to do it?
// Keep in mind its created for demonstration purposes
var functionOne = function(id)
{
return id;
}
var functionTwo = function(id,name)
{
return id + ' 'name;
}
var functionThree = funciton(id,name,age)
{
return id + ' '+name+' '+age;
}
var obj = [
{
callback: functionOne,
callbackParameters: [{key: 'id', value: 1}]
},
{
callback: functionTwo,
callbackParameters: [{key: 'id', value: 1}, {key: 'name', value:'Marc'}]
},
{
callback: functionThree,
callbackParameters: [{key: 'id', value: 1}, {key: 'name', value: 'Marc'}, {key: 'age', value: 45}]
}
]
obj.forEach(function(x){
//How do i call it with the correct keys? :(
})
Fiddle

You can call apply() on a function in JS and pass an array of parameters into it. So you could use the following assuming your callbackParameters are always in the correct order.
obj.forEach(function(x){
var parameters = x.callbackParameters.map(function(p) { return p.value; });
console.log(x.callback.apply(this, parameters));
})
Updated fiddle https://jsfiddle.net/y6oh1078/1/
Edit: Further reading
If you are interested in more ways to manipulate functions in JS, the following article on currying is a good read - https://www.sitepoint.com/currying-in-functional-javascript/

You cannot do this. This would require something like reflection, i.e. forEach anonymous function should know the definition of every callback function and get names (and what is much more important - order) of its arguments.
However, you can do the following:
var functionOne = function (o) {
return o.id;
};
var functionTwo = function (o) {
return o.id + ' ' + o.name;
};
var functionThree = function (o) {
return o.id + ' ' + o.name + ' ' + o.age;
};
var obj = [{
callback : functionOne,
callbackParameters : [{
key : 'id',
value : 1
}
]
}, {
callback : functionTwo,
callbackParameters : [{
key : 'id',
value : 1
}, {
key : 'name',
value : 'Marc'
}
]
}, {
callback : functionThree,
callbackParameters : [{
key : 'id',
value : 1
}, {
key : 'name',
value : 'Marc'
}, {
key : 'age',
value : 45
}
]
}
];
// Now, are you able to generate `o` objects dynamically using something like:
obj.forEach(function (x) {
var o = {};
x.callbackParameters.forEach(function (p) {
o[p.key] = p.value;
});
console.log(x.callback(o));
});
P.S. Actually, you can dynamically get the names and order of function arguments, but you do not want to do this.
If you are still interested in this, read this question.

Related

Javascript Object manipulation to create an Object list with a variable id

I am not comfortable with certain subtleties, and here are 2 days that I go around in circles, to carry out "manipulations" of Objects in javascript (NodeJS), I therefore appeal to your knowledge!
I send elements from a json as a parameter in a .js script.
in this script, I would like to process the elements sent as a parameter (by a loop), to add them to a list, then to be able to add others "manually", to finally get a "list" of the set with different additional information.
my "test" script where I simulate the parameters received and "try" to get this "list":
let params = JSON.parse('{ "100": 3, "101": 1 }') // simulate parameters
let lstObj = {} // content all the list obj
// only for the test
function foo(type) {
return "type is " + type;
}
function addToList(id, type) {
let obj = {
id: id,
type: type,
test: foo(type)
}
console.log('from addToList() -> ', obj);
return obj;
}
// process the Obj from parameters
let index = 0;
for (let [key, value] of Object.entries(params)) {
console.log("from Param: ", `${key} -> ${value}`, " or ", key, "->", value);
obj = addToList(key, value); // seem work
//lstObj.key = obj; // use 'key' not the key value
//lstObj.[key] = obj; // error
//lstObj.`${key}` = obj; // error
//lstObj.["999"] = obj; // error
//index++; lstObj.index = obj; // bad :)
lstObj.a999 = obj; // Work ! but how can a make it ?
}
console.log('\nResult -> ', lstObj);
// Now want to manualy add other Obj in the List, like this ?
// lstObj.999 = addToList("999", 3)
I would like to get a result like this:
{
"100": {id: 100, type: 1, test: 'Type is 1', ....}
"102": {id: 102, type: 3, test: 'Type is 3', ....}
"110": {id: 110, type: 1, test: 'Type is 1', ....}
"305": {id: 305, type: 2, test: 'Type is 2', ....}
}
The purpose of being able to subsequently retrieve the object of an element by a call like: "lstobj.101"
Thank's a lot !
What you need is to assign the key to the object.
Change this line
lstObj.a999 = obj; // Work ! but how can a make it ?
to
lstObj[key] = obj;
What this does is assign whatever value is contained by variable key to be a key in variable lstObj, then assign the value of obj as it's value.
For example
let key = 'exampleKey';
let value = 'exampleValue';
let obj = {};
obj[key]=value; //now object is { 'exampleKey': 'exampleValue' }

Would like this function to return when a string matches a value in an object partially or completely

I'm trying to filter using javascript and lodash. The search is performed using an input field and I want this function to return when this.props.search matches a value in the file object partially or completely. Without using the object's key names.
let files = [{
'id': '00001',
'fileName' : 'Test01.test',
'size': 105,
'uploadDate' : '2016-02-12',
'permissions' : 'Private'
}, {
'id': '00002',
'fileName' : 'Test02.test',
'size': 111,
'uploadDate' : '2016-02-10',
'permissions' : 'Private'
}, {
'id': '00003',
'fileName' : 'Test03.test',
'size': 55,
'uploadDate' : '2016-02-06',
'permissions' : 'Shared'
}];
let filteredFiles = files.filter((file) => {
return _.includes(file, this.props.search);
});
But using the function it will only work when it matches the string completetly. What am I doing wrong? I am open to not using lodash also if there's a suggestion.
UPDATE:
I end up using the following:
let filteredFiles = this.props.files.filter((file) => {
for (let prop in file) {
let string = String(file[prop]).toLowerCase();
if (string.indexOf(this.props.search.toLowerCase()) >= 0) {
return true;
}
}
return false;
});
Basically you want to apply the includes() function to each property value (or more accurately, till a match is found), not the object itself.
Try this:
let filteredFiles = files.filter((file) => {
return _.some(file, _.partial(_.includes, _, this.props.search, 0));
});
Loop through all the properties and check if your search value is in any of the properties.
let filteredFiles = files.filter((file) => {
for (var prop in file) {
var val = file[prop];
if (val === this.props.search || String(val).includes(this.prop.search)) {
return true;
}
}
return false;
});
Or here's a version that is a little more lodash like, but still VanillaJS, inspired by Amit's answer.
"use strict";
function filter(files, value) {
return files.filter(file => {
return Object.keys(file).some(key => {
return file[key] === value || String(file[key]).includes(value);
});
});
}
let files = [{
'id': '00001',
'fileName': 'Test01.test',
'size': 105,
'uploadDate': '2016-02-12',
'permissions': 'Private'
}, {
'id': '00002',
'fileName': 'Test02.test',
'size': 111,
'uploadDate': '2016-02-10',
'permissions': 'Private'
}, {
'id': '00003',
'fileName': 'Test03.test',
'size': 55,
'uploadDate': '2016-02-06',
'permissions': 'Shared'
}];
document.write('Filtering by Pri: ' + filter(files, 'Pri').length + ' matches<br/>');
document.write('Filtering by 105: ' + filter(files, '105').length + ' matches<br/>');
Because you are passing an object as the first parameter to _.includes, it is checking if any of the values stored in file have the exact value of this.props.search. If you want to see if a particular field matches at all, you should pass that field name, then it will search for a string part rather than a complete match. For instance:
let filteredFiles = files.filter((file) => {
return _.includes(file.fileName, this.props.search);
});

Why Object.create doesn't create a new list for me? [duplicate]

This question already has answers here:
Javascript object members that are prototyped as arrays become shared by all class instances
(3 answers)
Closed 7 years ago.
I'm trying to create a builder pattern in JavaScript. But I'm wondering why if I call Object.create twice I got the same list as before.
Here's my code.
var filterBuilder = {
filters: [],
addFilter: function(options) {
var filter = {
'type': 'selector',
'dimension': options.dimension,
'value': options.value
}
this.filters.push(filter);
return this;
},
build: function() {
return this.filters;
}
};
If I run Object.create(filterBuilder).build() I get [] which is good. But when I start adding filter
Object.create(filterBuilder).addFilter({dimension: '1', value: 'v'}).build();
I get one filter which is good
But then if I do
Object.create(filterBuilder).addFilter({dimension: '1', value: 'v'}).addFilter({dimension: '1', value: 'v'}).build();
I will get three filters, the first one is from the previous call. Isn't Object.create supposed to create a new object for me?
Prototype properties are shared, so the filters array is the same for both objects you created. If you want each object to have its own filters you have to add it as an own property (a property that is owned by the object, not the prototype), ie:
var filterBuilder = {
addFilter: function(options) {
var filter = {
'type': 'selector',
'dimension': options.dimension,
'value': options.value
}
this.filters.push(filter);
return this;
},
build: function() {
return this.filters;
}
};
var a = Object.create(filterBuilder)
a.filters = [];
a.addFilter({dimension: '1', value: 'v'}).build();
var b = Object.create(filterBuilder)
b.filters = []
b.addFilter({dimension: '1', value: 'v'}).addFilter({dimension: '1', value: 'v'}).build();
console.log(a.filters.length, b.filters.length); // 1 2
You can do this with new as well:
function FilterContainer() {
this.filters = [];
}
FilterContainer.prototype.addFilter = function() {
...
};
FilterContainer.prototype.build = function() {
...
};
// Has its own `filters` array
new FilterContainer().addFilter(...).build();
When you call Object.create(filterBuilder) several times, you get two objects which hold references to the same filters array.
var b1 = Object.create(filterBuilder);
var b2 = Object.create(filterBuilder);
// now b1.filters is the _same_ object as b2.filters,
// so calling
b1.filters.push(...);
// will inevitably modify b2.filters as well.
Your best choice here is using classical functions and prototypes
function FilterBuilder() {
this.filters = [];
}
FilterBuilder.prototype.addFilter = function() { };
var builder = new FilterBuilder();
builder.addFilter();
Object.create() takes an optional second argument which can define properties that are not inherited from the prototype, so you can (re-)define the filters property of newly created object like this:
Object.create(filterBuilder, {
filters : { writable : true, enumerable: true, value : [] }
})
https://jsfiddle.net/1m7xx4ge/2/
// full code
var filterBuilder = {
filters: [],
addFilter: function(options) {
var filter = {
'type': 'selector',
'dimension': options.dimension,
'value': options.value
}
this.filters.push(filter);
return this;
},
build: function() {
return this.filters;
}
};
Object.create(filterBuilder, {
filters : { writable : true, enumerable : true, value : [] }
})
.addFilter({dimension: '1', value: 'v'}).build();
Object.create(filterBuilder, {
filters : { writable : true, enumerable : true, value : [] }
})
.addFilter({dimension: '1', value: 'v'})
.addFilter({dimension: '1', value: 'v'}).build();

checking if javascript array contains value using underscorejs

I have an array of cars like this:
[{ name:"Toyota Minivan", id:"506" }, { name:"Honda Civic", id:"619" }]
I am trying to check whether the array contains a certain id.
I have tried
var x =!!_.where(cars, {id:'506'}).length;
expecting it to return true if the array contains the id, but it always returns false.
What am I doing here ?
Btw, I don't have to use underscore.js if there is a better way of doing this.
thanks
Thomas
Your code does work (once you fix the syntax errors in the object array):
http://jsfiddle.net/ArPCa/
var cars = [{ name:"Toyota Minivan", id:"506"}, { name:"Honda Civic", id:"619"}];
var x =!!_.where(cars, {id:'506'}).length;
console.log('value: ' + x);
returns "value: true". So there must be a problem somewhere else.
But, a better way to do this might be some:
var y = _.some(cars, function(c) {
return c.id == '506';
});
I know this is late, but even easier:
var cars = [{ name:"Toyota Minivan", id:"506"}, { name:"Honda Civic", id:"619"}];
function findById(id) {
return _.contains(_.pluck(cars, 'id'), id);
}
Say you have the array arr, and your id, id.
arr.filter(function(elem) { return elem.id == id; });
will return an array with the matching element(s);
You could wrap it in a function like:
function findById(arr, id) {
var filtered = arr.filter(function(elem) { return elem.id == id; });
return filtered && filtered.length ? filtered[0] : null;
}
, potentially doing some other stuff if you weren't happy with the default filtered array.
var obj = [{
name: "Toyota Minivan",
id: "506"
}, {
name: "Honda Civic",
id: "619"
}];
function findCar(id) {
return obj.filter(function (car) {
if (car.id == id) {
return car;
}
});
}

how to change value with Ember.js Array forEach?

self.resultList.forEach(function(item, index, enumerable){
console.log(self.resultList);
item.id=11;
item.get('id');
});
the item like this:
if item.id = 11;
the exception like this:
Assertion failed: You must use Ember.set() to access this property (of
[object Object])
so item.get('id') or item.set('id',11)
the exception like this
Uncaught TypeError: Object # has no method 'get'
is this item not the Ember's Object?so what the item is?
could someone tell me how to change the 'itme.id's value..
Thanks a million
You can use the Ember.set(yourObject, propertyName, value); and Ember.get(yourObject, propertyName); to safely set and get properties.
In your case:
self.resultList.forEach(function(item, index, enumerable) {
Ember.set(item, "id", 11);
Ember.get(item, "id");
});
In my case I did it in this way
//In my controller I've defined the array
displayInfoCheckboxes: [
{
turnover: {
label: "Turnover",
value: 1,
propertyName: "turnover"
}
}, {
pl: {
label: "P&L",
value: 1
}
}
]
//and in my handler I passed the full string path to the property in the set method
let displayInfoCheckboxes = this.get('displayInfoCheckboxes');
let controller = this;
displayInfoCheckboxes.forEach(function(items,index) {
for (var key in items) {
controller.set('displayInfoCheckboxes.' + index + '.' + key + '.value', false);
}
})

Categories