Knockout Mapping toJSON - cannot ignore nested child - javascript

Assume I have a viewModel like below.
var data = {
a: { a1: "a1", a2: "a2" },
b: "b"
};
I would like to ignore a.a1 and b. So my expected JSON is
{"a":{a2:"a2"}}
However, on doing this
var result = ko.mapping.toJSON(data, { ignore: ["a.a1", "b"] })
I am getting result=
{"a":{"a1":"a1","a2":"a2"}}
Knockout mapping is not ignoring a.a1. Is this a bug in the plugin? It correctly ignored 'b' but why not 'a.a1'?

The names found in the ignore array should be the name of the property, regardless of what level it is in the object. You have to use:
{ ignore: [ "a1", "b" ] }

I had similar ignore list where some "ids" have to be suppressed and others left as is. I wanted to expand on the answer so that people using fromJS can see specific ignores do work
var data1 = {
invoice: { id: 'a1', name: 'a2', type: 'a3'},
shipping: "b1",
id:"c1"
};
var resultvm = ko.mapping.fromJS(data1, {'ignore':["invoice.id",
"ship"]}); ko.applyBindings(resultvm);
Will give you an output as below. Notice that only the id for invoice has been ignored.
{"invoice":{"name":"a2","type":"a3"},"id":"c1"}
But toJSON gives
Code:
var result = ko.mapping.toJSON(data1, { ignore: ["invoice.id",
"shipping"] });
Result:
{"invoice":{"id":"a1","name":"a2","type":"a3"},"id":"c1"}
Here is my jsFiddle: https://jsfiddle.net/3b17r0ys/8/

Related

Adding another property with Key Value in an object

I am sorry if this question already asked but i guess it confusing so i want to know how to add a property in an object which is not defined in the object.
I want to add a property name: 'something' in a nested objects.
let cars = {
passengers: null,
engine: {
yearBuilt: 2002,
model: "25481 AL"
}
now it has two properties passengers and engine. What i want is to add another property "name" in passengers and log it in an array with ['Alex', 'Mark']
What i tried:
cars.passengers = [{name: 'Alex'}]; //Output is like this [ { name: 'Alex' } ],
and when i add a square bracket notation in Alex only the output will be
name: [Object] }
cars.passengers = [{name: 'Alex'}]; //Output is like this [ { name: ['Alex'] } ] //Output is like { passengers: [ { name: [Object] } ]
code:
let newData = cars.passengers = [{name: ['Alex']}];
why its not showing in an array.? and how to do that .?
Can u try
cars.passengers = {name: ['Alex'] }

Keys to Mongoose Object are different from property names

In order to troubleshoot an error I have been getting, I wrote the following snippet:
var myFunction = function(obj) {
var keys = Object.getOwnPropertyNames(obj);
console.log(obj);
console.log(keys);
}
When running my function within a mongoose query callback, the console logs this:
{_id: 5a8g123vjsdj83nf8afvn48,
username: 'Player1',
adv1: { name: 'a', type: '!' },
adv2: { name: 'a', type: '!' },
adv3: { name: 'a', type: '!' },
__v: 0,
invitations: [ 'PlayTest1', 'PlayTest2' ] }
[ '$__', 'isNew', 'errors', '_doc', '$init' ]
Now as far as I understand it, the last line in the console (separated for reading convenience) should read:
[ '_id', 'username', 'adv1', 'adv2', 'adv3', '__v', 'invitations ]
My question is why does the keys obj I create in myFunction not contain the properties names shown when I log the actual object?
Mongoose document fields are stored in obj._doc
console.log displays the document fields due to an .inspect function attached to the document object.
Use node --inspect if you want to debug something.

JS – How to build a dynamic nested object of arrays with objects etc. from string

This is a nice evening project, but actually i'm stuck with some headache.
All I need is a function like this example:
result = set("itemCategories[0].items[0].name", "Test")
which should return:
{ itemCategories: [
{
items: [ {name: "Test"} ]
}
}]
...and in case of the given attribute "itemCategories[1].items[2].name" this result:
{ itemCategories: [
null,
{
items: [
null,
null,
{name: "Test"}
]
}
}]
Use lodash#set:
result = lodash.set({}, "itemCategories[0].items[0].name", "Test")
If you are asking about the vanilla JavaScript Set method then you could do this.
/* this is what you are trying to get.
{ itemCategories: [
{
items: [ {name: "Test"} ]
}
}]
*/
var mySet = new Set(); // your set object.
Create your data (number, text, string, object, array, null).
ver data1 = 365;
ver data2 = 'Dragonfly';
ver data3 = {name: 'Bobby', age: 20000, job: 'dj'};
Then you just add to that set using its add method.
mySet.add(data1);
mySet.add(data2);
mySet.add(data3);
So to get what you are looking for you would write this.
var itms = {items: [{name: 'test'}]};
mySet.add(itms);
The good thing about set is that is like an array. So you can use forEach.
mySet.forEach( function(val){
console.log(val); // gets all your data.
});
You can even check if a value is in your data using the has method.
mySet.has(365); // true
mySet.has(36500000); as false
JavaScript Set

Get elements with biggest attribute using find only

EDIT: Ok, got it. It cannot be done with a find. I workarounded this in another way, but its pretty unrelated with this question: i added a boolean field "last_inserted" and used meteor hooks to make sure that only the last inserted have that field. Thank you all anyway.
I'm in a Meteor project and have a collection like this:
group_id, date, attribute1, attributeN
1, 2015-11-26 09:40:23.000Z, "foo", "bar"
1, 2015-11-23 14:23:53.000Z, "foo", "bar"
2, 2015-11-23 14:24:01.000Z, "foo", "bar"
2, 2015-11-23 14:25:44.000Z, "foo", "bar"
i have to filter this and get, for each group_id, the element with the biggest date, having a result like this:
group_id, date, attribute1, attributeN
1, 2015-11-26 09:40:23.000Z, "foo", "bar"
2, 2015-11-23 14:25:44.000Z, "foo", "bar"
I read in some related question that it can be done with the aggregate operator:
MongoDB - get documents with max attribute per group in a collection
but Meteor still doesn't implement it, and i have to do it with a find.
I'm no MongoDB expert and i'm reading the documentation from a lot, but i'm starting to fear that i can't do this without getting all the elements and manually filtering those in javascript (i really don't like this kind of solution)
I read there are some meteor packages that adds the aggregate command (like this), but i don't know how much they are reliable since this is a project that needs to be rock-solid
How can i do that?
This is a proposal in plain Javascript with a temporary object for the references to the result array.
var data = [{ group_id: 1, date: '2015-11-26 09:40:23.000Z', attribute1: 'foo', attributeN: 'bar' }, { group_id: 1, date: '2015-11-23 14:23:53.000Z', attribute1: 'foo', attributeN: 'bar' }, { group_id: 2, date: '2015-11-23 14:24:01.000Z', attribute1: 'foo', attributeN: 'bar' }, { group_id: 2, date: '2015-11-23 14:25:44.000Z', attribute1: 'foo', attributeN: 'bar' }],
result = function (data) {
var r = [], o = {};
data.forEach(function (a) {
if (!(a.group_id in o)) {
o[a.group_id] = r.push(a) - 1;
return;
}
if (a.date > r[o[a.group_id]].date) {
r[o[a.group_id]] = a;
}
});
return r;
}(data);
document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');

How to filter objects with another object in Angular?

Working on a font library, I store fonts like this:
var fonts = [
{
name: "Foo",
style: "Bar",
families: [
{ name: "A", parent: "B" },
{ name: "C", parent: "D" }
]
} // and so on...
];
And I want to filter out fonts whose families list contains { name: "A", parent: "B" }.
The filter looks like var selection = [{ name: "A", parent: "B" }]
Actually, the code look like this:
// Triggers when a new family is added to the filter
$scope.$on('filter:changed', function(e, selection) {
_.each($scope.fonts, function(font) {
_.each(font.families, function(family) {
_.each(selection, function(item) {
if(_.isMatch(family, item)) {
console.log('font', font);
console.log('has a match for family', family);
} else {
console.log('no match for family', family);
}
});
});
});
});
What is the best way to do it without performance impact, as there will be thousands font objects in the future?
underscore#where
$scope.$on('filter:changed', function(e, selection) {
var multiselection,
singleSelection;
_.each($scope.fonts, function(font) {
multiselection = _.where(font.families, { name: "A", parent: "B" }); //all matching objects
singleSelection = _.findWhere(font.families, { name: "A", parent: "B" }); // single matching object
});
});
JSFIDDLE
Since you're using underscore use filter
From underscore docs:
_.filter(list, predicate, [context]) Alias: select Looks through each value in the list, returning an array of all the values that pass a
truth test (predicate).
So your filter would be (use this only if you want to manipulate data for each object, otherwise use where):
var myFamilyMatch = { name: "A", parent: "B" };
var selection = _.filter(fonts, function(font){
return _find(font.families, function(family){
return family == myFamilyMatch;
};
});
Or simply (and better) use where as #dcodesmith suggested:
_.where(list, properties) Looks through each value in the list, returning an array of all the values that contain all of the key-value
pairs listed in properties.
Underscore will take care of performance for you, so don't worry about it.

Categories

Resources