AngularJS disable 2 way binding - javascript

This actually might be a JavaScript question, but it is happening when I am using AngularJs.
Say I have an array like this:
var players = [
{
id: 1,
name: 'Player 1'
},
{
id: 2,
name: 'Player 2'
}
];
and then I have another array like this:
var teams = [
{
id: 1,
name: 'Team 1',
members: players
},
{
id: 2,
name: 'Team 2',
members: players
}
];
If I decide to add a new property called position to one of the teams:
teams[0].members[0].position = 1;
I don't want it to then update the second team members position.
I hope that makes sense.
Here is a codepen to illustrate my issue:
http://codepen.io/r3plica/pen/ZGZXjb?editors=101

Array in java-script are mutable so you need to make copy of player and assign it to teams member property.
Just change your code to :
var teams = [
{
id: 1,
name: 'Team 1',
members: angular.copy(players)
},
{
id: 2,
name: 'Team 2',
members: angular.copy(players)
}
];
for more information see : https://docs.angularjs.org/api/ng/function/angular.copy

The only way (if both teams have the same players) is to use a copy of the array for the second team. Now it's logical the second team gets updated, because both teams point to the same reference of players.
You can use angular.copy for that.
var copyofplayers = [];
angular.copy(players, copyofplayers);

also can use jQuery.extend() like
var teams = [
{
id: 1,
name: 'Team 1',
members: jQuery.extend({}, players)
},
{
id: 2,
name: 'Team 2',
members: jQuery.extend({}, players)
}
];

Related

Destructuring first object of array in JavaScript [duplicate]

This question already has an answer here:
To access property of object nested in array using destructuring
(1 answer)
Closed 12 months ago.
Let's say we have the object below:
const page = {
name: 'Page 1',
page_category: [
{
postId: 1,
catId: 1,
category: {
id: 1,
name: 'category 1'
}
},
{
postId: 3,
catId: 2,
category: {
id: 2,
name: 'category 2'
}
},
]
}
To get the first object in the page_category array, in a destructuring manner, We would do this:
const { page_category: [first] } = page
But what would it be if we wanted to get the first object's category field?
You can destructure the object within the array destructuring:
const { page_category: [{category}] } = page;
const page = {
name: 'Page 1',
page_category: [{
postId: 1,
catId: 1,
category: {
id: 1,
name: 'category 1'
}
},
{
postId: 3,
catId: 2,
category: {
id: 2,
name: 'category 2'
}
},
]
};
const { page_category: [{category}] } = page;
console.log(category);
The destructuring assignment syntax is analogous to the syntax of creating the object literal, the below formatting shows how they have the same shape. You can use this idea to assist with your destructuring patterns:
const {
page_category: [
{
category
}
]
} = page;
To destructure the first object's category field.
const {page_category: [ {category} ]} = page;
console.log("category ==>", category);
This way you will find the first category object.

Node How to add Array into array

How can i push an array into an exists array?
Cases[caseid].items = itemscase;
thats what i tried.
I have some "Cases"
for(var c in Cases) {
for each Case(s) i want to push different new "items" to an exists array.
The array looks like this:
'123':
[ { id: 123,
skus: [Array],
name: 'xyz',
img: '/public/images/cases/10018.png'}
now i want to push a new array (itemscase) to that like this
'123':
[ { id: 123,
skus: [Array],
name: 'xyz',
img: '/public/images/cases/10018.png'
items: [Array]}
The array itemscase is correct and working and looks like that
[ { sku: 12345,
name:
'testname',
price: 15 }]
but for some reason the last run will push only to the last "Cases".
So if i have 10 "Cases" only the last gets items all before not.
Here some more Code.
for(var c in Cases) {
var caseid = Cases[c][0].id;
for(var i in itemsres) {
var item = itemsres[i];
itemscase.push({
sku: item.sku,
name: item.name
price: item.suggested_price_floor
});
}
Cases[caseid].items = itemscase;
}
itemsres is also fine, creating itemscase works fine and something.
For me looks like something is wrong with the add an array into another array
I think i do something wrong...
Here the maps adds the items to each node using a map.
NOTE: You are not filtering on what items to add where, I suspect you want to add items that match the skus?
Let me know and we can make the right changes.
let Cases = [{
id: 123,
skus: [1, 2, 3],
name: 'xyz',
img: '/public/images/cases/10018.png'
},
{
id: 234,
skus: [4, 5, 6],
name: 'abc',
img: '/public/images/cases/10019.png'
}
];
let itemres = [{
sku: 12345,
name: 'testname',
price: 15
},
{
sku: 45677,
name: 'testname',
suggested_price_floor: 20
}
];
// add items to cases
Cases = Cases.map(c => {
c.items = itemres.map(i => {
return {
sku: i.sku,
name: i.name,
price: i.suggested_price_floor
};
})
return c;
});
console.log(Cases);
Its hard to test without the full code, but based on your examples, I suggest you to try out this snippet:
Object.keys(Cases).forEach(id => {
Cases[id].forEach(caseItem => {
caseItem.items = itemsres.map(x => ({
sku: x.sku,
name: x.name,
price: x.suggested_price_floor,
}));
});
});
Basically, here I'm looping through all cases using Object.keys() when object, and .forEach() when array. The Array.map() function does what your (empty array + loop + push) is trying to do.

JavaScript - Take out Object from Array and place its contents at the same height

I need to solve the following problem in the easiest and shortest possible way.
How can i take out keys from node object inside array and place them at the same height as the main array:
What i have:
[{ name: 'name 1', id: 1, node: [{ name: 'name2', id: 2 }]}]
What i want:
[{name: 'name 1', id: 1}, {name: 'name 2', id: 2}]
Thank you in advance for your help.
You can try this with reduce. You recursively traverse the nodes and concat an array with name and id only. Hope this helps.
const data = [{ name: 'name 1', id: 1, node: [{ name: 'name2', id: 2 }]}];
const flatten = (array = []) =>
array.reduce((acc, { name, id, node }) =>
acc.concat(flatten(node)).concat({ name, id })
, []);
console.log(flatten(data));
Ok, assuming your structure always looks like that:
Array of objects containing always 1 object, and that object always have a node element (that is another array of objects) you need to do it like this (pseudocode):
mainArray = [{ name: 'name 1', id: 1, node: [{ name: 'name2', id: 2 }]}];
console.log(mainArray);
node = mainArray[0].node[0];
delete mainArray[0].node;
mainArray.push (node);
console.log(mainArray);
Since you don't specify any more about your data structure I can't do anything more specific, but you probably can adapt from that
Here's a piece of code, that does what you're looking for. There's a couple of console.log statements to guide you through the data that's being processed. I'm sure you'll need to tweak it, but it's a start.
There are 3 forEach loops in this solution, so if you're working on a large array/object, and/or running this frequently - there might be more efficient methods to achieve this goal.
Assuming ECMA6:
const arr = [{ name: 'name 1', id: 1, node: [{ name: 'name2', id: 2 }]}];
arr.forEach((item) =>{
console.log("array item:", item);
const keys = Object.keys(item);
console.log("item keys", keys);
keys.forEach((key) =>{
if(item[key] instanceof Object){
if(Array.isArray(item[key])){
item[key].forEach((internalObject) =>{
console.log("intenal object", internalObject);
arr.push(internalObject);
delete item[key];
console.log("New array", arr);
})
}
}
})
});

How can I optimally group a list of objects by their sub object?

I'm trying to group some JavasScript objects by their shared similar object. I can do this effortlessly in Ruby, but for the life of my I (somewhat embarrassingly) can't figure this out in JS in linear time. JS doesn't seem to allow object literals as keys, at least for the purposes of reducing.
I have data shaped like this, as a result from a GraphQL query:
[
{
id: 1,
name: 'Bob',
room: {
id: 5,
name: 'Kitchen'
}
},
{
id: 3,
name: 'Sheila',
room: {
id: 5,
name: 'Kitchen'
}
},
{
id: 2,
name: 'Tom',
room: {
id: 3,
name: 'Bathroom'
}
}
]
In the UI, we're going to display the objects by the room they're in. We need to keep a reference to the room itself, otherwise we'd just sort by a room property.
What I'm trying to do is reshape the data into something like this:
{
{id: 5, name: 'Kitchen'}: [{id: 1, name: 'Bob'}, {id: 3, name: 'Sheila'}],
{id: 3, name: 'Bathroom'}: [{id: 2, name: 'Tom'}]
}
As you can see, the people are grouped together by the room they're in.
It could also be shaped like this...
[
{ room: {id: 5, name: 'Kitchen'}, people: [{id: 1, name: 'Bob', ...}] },
{ room: {id: 3, name: 'Bathroom', people: [{id: 2, name: 'Tom'}]
]
However it comes out, we just need the people grouped by the rooms in linear time.
I've tried lodash's groupBy, using both map and reduce, just doing for loops that put the list together, etc. I'm stumped because without being able to use an object literal (the room) as a hash index, I don't know how to efficiently group the outer objects by the inner objects.
Any help is greatly appreciated.
Update: adding clarity about trying to do it with linear time complexity - the most efficient equivalent of this Ruby code:
h = Hash.new { |h, k| h[k] = [] }
value.each_with_object(h) { |v, m| m[v[:room]] << v }
You can solve this using lodash#groupBy and lodash#map to gather and transform each group. Additionally, we use lodash#omit to remove the room object from each person from the people array.
var result = _(data)
.groupBy('room.id')
.map(people => ({
room: { ...people[0].room },
people: _.map(people, person => _.omit(person, 'room'))
})).value();
var data = [
{
id: 1,
name: 'Bob',
room: {
id: 5,
name: 'Kitchen'
}
},
{
id: 3,
name: 'Sheila',
room: {
id: 5,
name: 'Kitchen'
}
},
{
id: 2,
name: 'Tom',
room: {
id: 3,
name: 'Bathroom'
}
}
];
var result = _(data)
.groupBy('room.id')
.map(people => ({
// make sure to create a new room object reference
// to avoid mutability
room: { ...people[0].room },
people: _.map(people, person => _.omit(person, 'room'))
})).value();
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>
You can use reduce to create an object of people indexed by rooms and then get that object's values, no library needed:
const input=[{id:1,name:'Bob',room:{id:5,name:'Kitchen'}},{id:3,name:'Sheila',room:{id:5,name:'Kitchen'}},{id:2,name:'Tom',room:{id:3,name:'Bathroom'}}]
const output = Object.values(
input.reduce((a, { id, name, room }) => {
const roomName = room.name;
if (!a[roomName]) a[roomName] = { room, people: [] };
a[roomName].people.push({ id, name });
return a;
}, {})
);
console.log(output);
Objects like
{id: 5, name: 'Kitchen'}: [{id: 1, name: 'Bob'}, {id: 3, name: 'Sheila'}],
in your question can't be properties like that unless the structure is a Map. Ordinary Javascript objects can only have string (/ number) properties.
One alternative is to use reduce in order to groupBy the rooms.
const input = [{
id: 1,
name: 'Bob',
room: {
id: 5,
name: 'Kitchen'
}
},
{
id: 3,
name: 'Sheila',
room: {
id: 5,
name: 'Kitchen'
}
},
{
id: 2,
name: 'Tom',
room: {
id: 3,
name: 'Bathroom'
}
}
];
const res = input
.map(person => ({
person: {
id: person.id,
name: person.name
},
room: person.room
}))
.reduce((rooms, person) => {
const room = rooms.find(room => room.id === person.room.id) ||
{ room: person.room };
const idx = rooms.indexOf(room);
room.people = room.people ?
[...room.people, person.person] :
[person.person];
return Object.assign(rooms, {
[idx === -1 ? rooms.length : idx]: room
});
}, []);
console.log(res);

Combine nested result using selectors

I am using reselect to derive my data from the store. I maintain a list of Divisions and Teams and each Division has it's list of teams. I also keep a record of the active Divisions and keep them in an array activeIds.
Basically I have this tree structure:
const divisions = {
activeIds: [], // this contains the selected division IDs
list: {
1: {
name: 'Division 1',
teams: [1,2,3]
}
2: {
name: 'Division 2',
teams: [4,5,6]
}
// and so on...
}
}
const teams = {
1: { name: 'Team 1' }
// and so on...
}
I have a getActiveDivisions selector which iterates through the activeIds array and hydrate it with Division data, and the result is:
// if activeIds contain [1,3]
const activeDivisions = {
1: {
name: 'Division 1',
teams: [1,2,3]
}
3: {
name: 'Division 3',
teams: [7,8,9]
}
}
Now I wanted to create a getActiveDivisionsWithTeams selector which basically gets the same structure as the activeDivisions tree however with hydrated teams, for example:
const activeDivisionsWithTeams = {
1: {
name: 'Division 1',
teams: {
1: { name: 'Team 1' },
2: { name: 'Team 2' },
3: { name: 'Team 3' }
}
}
// and so on...
}
Or should I just keep a different list for the division with hydrated teams?
// Notice there is no `name` on division entry
const activeDivisionsWithTeams = {
1: {
teams: {
1: { name: 'Team 1' },
2: { name: 'Team 2' },
3: { name: 'Team 3' }
}
}
// and so on...
}
Or what would be the best way to approach this scenario?
I don't think it's good practice to fully rehydrate your data.
If you're going to display something for all the teams, pass each id on to a child component, which can then use a selector to get the data it needs.
Or if you're doing some calculation which needs disparate parts of the data, then do this inside the selector, rather than return the fully hydrated data.

Categories

Resources