content[i] is undefined when push into array in angularjs - javascript

I have json data like below
var data = [{
id: 1,
name: 'mobile',
parentid: 0,
limit:3
}, {
id: 2,
name: 'samsung',
parentid: 1
}, {
id: 3,
name: 'moto',
parentid: 1
}, {
id: 4,
name: 'redmi',
parentid: 1
}, {
id: 5,
name: 'honor',
parentid: 1
}, {
id: 6,
name: 'tv',
parentid: 0,
limit:3
}, {
id: 7,
name: 'tv1',
parentid: 6
}, {
id: 8,
name: 'tv2',
parentid: 6
}, {
id: 9,
name: 'tv3',
parentid: 6
}, {
id: 10,
name: 'tv4',
parentid: 6
}, {
id: 11,
name: 'tv5',
parentid: 6
}];
i took parentid zero from json and made a loop in ng-repeat
$scope.cat = categories.filter(function(category) {
return category && category.parentId === 0
});
i have created ng-repeat for this category.whgen i click category all corresponding sub categories pushed into array but when i tried to push my data into array i am getting an error
$scope.category_modal = function(id)
{
for(var i =0;i<=$scope.content.length;i++)
{
if($scope.content[i].parentId === id && typeof $scope.content[i] != 'undefined')
{
$scope.newcat.push($scope.content[i]);
}
}
}
my view page looks like below
<div ng-repeat="item in cat">
{{item.name}}
<button ng-click="category_modal(item.parentid)"></button>
</div>
here i got an error as $scope.content[i] is undefined

Are you getting values in $scope.content?
If yes , check have you declared properly
$scope.content = [];

Related

Grouping array of objects by multiple properties

I have an array of notifications that I want to group by certain conditions (like facebook's notifications)
var data = [
{ id: 1, type: 'shop.follower', by: { id: 2, name: 'User B', }, in: null, read_at: '2021-01-03 10:15:43', created_at: '2020-08-02 05:21:20' },
{ id: 2, type: 'product.liked', by: { id: 2, name: 'User B' }, in: { id: 1, ... }, read_at: '2021-01-03 10:15:43', created_at: '2020-08-02 05:24:45' },
{ id: 3, type: 'product.commented', by: { id: 3, name: 'User C' }, in: { id: 1, ... }, read_at: '2021-02-20 20:01:39', created_at: '2021-02-19 16:21:43' },
{ id: 4, type: 'product.liked', by: { id: 4, name: 'User D' }, in: { id: 1, ... }, read_at: '2021-03-29 15:14:21', created_at: '2021-03-28 08:11:50' },
{ id: 5, type: 'product.liked', by: { id: 3, name: 'User C' }, in: { id: 1, ... }, read_at: null, created_at: '2021-03-28 08:12:24' },
{ id: 6, type: 'shop.follower', by: { id: 5, name: 'User E' }, in: null, read_at: null, created_at: '2021-05-23 10:02:21' },
{ id: 7, type: 'shop.follower', by: { id: 3, name: 'User C' }, in: null, read_at: null, created_at: '2021-07-18 10:31:12' },
{ id: 8, type: 'comment.replied', by: { id: 4, name: 'User D' }, in: { id: 6, ... }, read_at: null, created_at: '2021-07-24 08:34:25' },
]
Let's say I want to group by date in descending order
So I have this code:
function sortByDate(array, desc = true) {
if (desc === false) {
// Ascending order
return array.sort((a, b) => {
if (new Date(a.created_at) > new Date(b.created_at)) {
return 1
} else {
return -1
}
return 0
})
}
// Descending order
return array.sort((a, b) => {
if (new Date(a.created_at) < new Date(b.created_at)) {
return 1
} else {
return -1
}
return 0
})
}
So now we have array like this:
[
{ id: 8, type: 'comment.replied', by: { id: 4, name: 'User D' }, in: { id: 6, ... }, read_at: null, created_at: '2021-07-24 08:34:25' },
{ id: 7, type: 'shop.follower', by: { id: 3, name: 'User C' }, in: null, read_at: null, created_at: '2021-07-18 10:31:12' },
{ id: 6, type: 'shop.follower', by: { id: 5, name: 'User E' }, in: null, read_at: null, created_at: '2021-05-23 10:02:21' },
{ id: 5, type: 'product.liked', by: { id: 3, name: 'User C' }, in: { id: 1, ... }, read_at: null, created_at: '2021-03-28 08:12:24' },
{ id: 4, type: 'product.liked', by: { id: 4, name: 'User D' }, in: { id: 1, ... }, read_at: '2021-03-29 15:14:21', created_at: '2021-03-28 08:11:50' },
{ id: 3, type: 'product.commented', by: { id: 3, name: 'User C' }, in: { id: 1, ... }, read_at: '2021-02-20 20:01:39', created_at: '2021-02-19 16:21:43' },
{ id: 2, type: 'product.liked', by: { id: 2, name: 'User B' }, in: { id: 1, ... }, read_at: '2021-01-03 10:15:43', created_at: '2020-08-02 05:24:45' },
{ id: 1, type: 'shop.follower', by: { id: 2, name: 'User B', }, in: null, read_at: '2021-01-03 10:15:43', created_at: '2020-08-02 05:21:20' },
]
Now that our array is sorted, I created a function:
// https://www.tutorialspoint.com/most-efficient-method-to-groupby-on-an-array-of-objects-in-javascript
function groupByProperty(array, property) {
return array.reduce((acc, object) => {
const key = object[property]
if (! acc[key]) {
acc[key] = []
}
acc[key].push(object)
return acc
}, {})
}
Then, I run this code
Object.values(groupByProperty(data, 'type'))
Which return:
[
[
{ id: 8, type: 'comment.replied', by: { id: 4, name: 'User D' }, in: { id: 6, ... }, read_at: null, created_at: '2021-07-24 08:34:25' }
],
[
{ id: 7, type: 'shop.follower', by: { id: 3, name: 'User C' }, in: null, read_at: null, created_at: '2021-07-18 10:31:12' },
{ id: 6, type: 'shop.follower', by: { id: 5, name: 'User E' }, in: null, read_at: null, created_at: '2021-05-23 10:02:21' },
{ id: 1, type: 'shop.follower', by: { id: 2, name: 'User B', }, in: null, read_at: '2021-01-03 10:15:43', created_at: '2020-08-02 05:21:20' }
],
[
{ id: 5, type: 'product.liked', by: { id: 3, name: 'User C' }, in: { id: 1, ... }, read_at: null, created_at: '2021-03-28 08:12:24' },
{ id: 4, type: 'product.liked', by: { id: 4, name: 'User D' }, in: { id: 1, ... }, read_at: '2021-03-29 15:14:21', created_at: '2021-03-28 08:11:50' },
{ id: 2, type: 'product.liked', by: { id: 2, name: 'User B' }, in: { id: 1, ... }, read_at: '2021-01-03 10:15:43', created_at: '2020-08-02 05:24:45' }
],
[
{ id: 3, type: 'product.commented', by: { id: 3, name: 'User C' }, in: { id: 1, ... }, read_at: '2021-02-20 20:01:39', created_at: '2021-02-19 16:21:43' }
],
]
I want to group these notifications by these categories:
Same type (I already covered this in my function groupByProperty())
Same in: { id: ... } Except for type: shop.follower
If #1 and #2 were true, check for similar objects with created_at: ... date interval between 10 minutes
If we have a case like #3 (multiple), if one among it has read_at = null, then it will be an unread notification, get the latest (newest) date
In id: 4 and id: 5, interval between timestamp are less than 10 minutes, so I want it to group as one
example EXPECTED OUTPUT:
[
[
{ by: {id: 4, name: "User D"}, created_at: "2021-07-24 08:34:25", id: 8, in: {id: 6}, read_at: null, type: "comment.replied" }
],
[
{ by: {id: 3, name: "User C"}, created_at: "2021-07-18 10:31:12", id: 7, in: null, read_at: null, type: "shop.follower" }
],
[
{ by: {id: 5, name: "User E"}, created_at: "2021-05-23 10:02:21", id: 6, in: null, read_at: null, type: "shop.follower" }
],
[
{ by: {id: 3, name: "User C"}, created_at: "2021-03-28 08:12:24", id: 5, in: {id: 1}, read_at: null, type: "product.liked" },
{ by: {id: 4, name: "User D"}, created_at: "2021-03-28 08:11:50", id: 4, in: {id: 1}, read_at: "2021-03-29 15:14:21", type: "product.liked" }
],
[
{ by: {id: 3, name: "User C"}, created_at: "2021-02-19 16:21:43", id: 3, in: {id: 1}, read_at: "2021-02-20 20:01:39", type: "product.commented" }
],
[
{ by: {id: 2, name: "User B"}, created_at: "2020-08-02 05:24:45", id: 2, in: {id: 1}, read_at: "2021-01-03 10:15:43", type: "product.liked" }
],
[
{ by: {id: 2, name: "User B"}, created_at: "2020-08-02 05:21:20", id: 1, in: null, read_at: "2021-01-03 10:15:43", type: "shop.follower" }
],
]
example IN BROWSER:
|------------------------------------------------------------------------------|
| - (UNREAD) User D replied to your comment ....., 2021-07-24 08:34:25 |
| - (UNREAD) User C start follow your shops ....., 2021-07-18 10:31:12 |
| - (UNREAD) User E start follow your shops ....., 2021-05-23 10:02:21 |
| - (UNREAD) User C and D liked your product ....., 2021-03-28 08:12:24 | <= (Please pay attention)
| - (READ) User C commented on your product ....., 2021-02-19 16:21:43 |
| - (READ) User B liked your product ....., 2020-08-02 05:24:45 |
| - (READ) User B start follow your shops ....., 2020-08-02 05:21:20 |
This is the code I tried to find interval between 10 minutes
function inRangeBetween(val, min, max) {
if (val >= min && val <= max) {
return true
}
return false
}
var startingPoint = { min: 0, max: 0, type: null },
newData = []
for (var i = 0; i < data.length; i++) {
if (startingPoint.min < 1
&& startingPoint.max < 1
&& startingPoint.type === null) {
console.log('Starting point')
var start = new Date(data[i].created_at)
startingPoint.min = start.getTime()
startingPoint.max = start.getTime() + (10 * 60000)
startingPoint.type = data[i].type
newData[data[i].type] = []
} else {
// startingPoint has values
if (inRangeBetween(new Date(data[i].created_at).getTime(), startingPoint.min, startingPoint.max
&& data[i].type === startingPoint.type) {
console.log(`Pushing new object to key ${data[i].type}`)
newData[data[i].type].push(data[i])
} else {
// Set new values for startingPoint, and start again comparing
console.log('Starting point values changes')
startingPoint.min = new Date(data[i]).getTime()
startingPoint.min = new Date(data[i]).getTime() + (10 * 60000)
startingPoint.type = data[i].type
newData[data[i].type] = []
newData[data[i].type].push(data[i])
}
}
}
// Not working
How to achieve this? (Stuck in this problem for 5 days)
Thanks in advance
Try like this:
var data = [
{ id: 1, type: 'shop.follower', by: { id: 2, name: 'User B', }, in: null, read_at: '2021-01-03 10:15:43', created_at: '2020-08-02 05:21:20' },
{ id: 2, type: 'product.liked', by: { id: 2, name: 'User B' }, in: { id: 1 }, read_at: '2021-01-03 10:15:43', created_at: '2020-08-02 05:24:45' },
{ id: 3, type: 'product.commented', by: { id: 3, name: 'User C' }, in: { id: 1 }, read_at: '2021-02-20 20:01:39', created_at: '2021-02-19 16:21:43' },
{ id: 4, type: 'product.liked', by: { id: 4, name: 'User D' }, in: { id: 1 }, read_at: '2021-01-03 10:15:43', created_at: '2021-03-28 08:11:50' },
{ id: 5, type: 'product.liked', by: { id: 3, name: 'User C' }, in: { id: 1 }, read_at: null, created_at: '2021-03-28 08:12:24' },
{ id: 6, type: 'shop.follower', by: { id: 5, name: 'User E' }, in: null, read_at: null, created_at: '2021-05-23 10:02:21' },
{ id: 7, type: 'shop.follower', by: { id: 3, name: 'User C' }, in: null, read_at: null, created_at: '2021-07-18 10:31:12' },
{ id: 8, type: 'comment.replied', by: { id: 4, name: 'User D' }, in: { id: 6 }, read_at: null, created_at: '2021-07-24 08:34:25' }
]
function sortByDate(array, desc = true) {
if (desc === false) {
// Ascending order
return array.sort((a, b) => {
if (new Date(a.created_at) > new Date(b.created_at)) {
return 1
} else {
return -1
}
return 0
})
}
// Descending order
return array.sort((a, b) => {
if (new Date(a.created_at) < new Date(b.created_at)) {
return 1
} else {
return -1
}
return 0
})
}
function groupByProperties(array, properties) {
return Object.values(array.reduce((acc, object) => {
const key = properties.reduce((acc, property) => {
return acc + (object[property] ? JSON.stringify(object[property]) : '')
}, '')
if (! acc[key]) {
acc[key] = []
}
acc[key].push(object)
return acc
}, {}))
}
function groupByInterval(data, interval) {
var group;
for(var i = 0; i < data.length; i++) {
if(1 < data[i].length) {
var max_date = new Date(data[i][0].created_at);
for(var j = data[i].length - 1; 0 < j; j--) {
var next_date = new Date(data[i][j].created_at)
if(interval < max_date - next_date) {
if(!group) {
group = i + 1;
data.splice(group, 0, [])
}
data[group].splice(0, 0, data[i][j])
data[i].splice(j, 1)
};
};
if(group) {
return groupByInterval(data, interval)
};
}
data[i].sort((a, b) => {
if(!a.read_at) {
return -1
}
if(!b.read_at) {
return 1
}
return 0
})
}
data.sort((a, b) => new Date(b[0].created_at) - new Date(a[0].created_at))
return data
}
sortByDate(data)
//1. Same type
//2. Same in: { id: ... } (Except for type: shop.follower)
data = groupByProperties(data, ['type', 'in'])
//3. If #1 and #2 true, check for similar objects with created_at: ... date gap between 10 minutes
//4. If we have a case like #3 (multiple), if one among it has read_at = null, then it unread notification, then get the latest (newest) date
data = groupByInterval(data, 1000 * 60 * 10) //10min
console.log(data)
groupByProperties() is based on groupByProperty(), but accepts multiple properties for grouping (categories 1 and 2). It checks whether the value of the property is falsy (such as null), excluding it from grouping criteria if so.
groupByInterval() added to separate groups according to a specified interval in milliseconds (categories 3 and 4). It then sorts the groups according to read_at being falsy, so that objects with read_at == null appear first in each group. It then sorts across groups to achieve the order in the expected result.
Mr.sbgib is absolutely correct, but i just modified sortByDate function to a little short as follows to reduce duplicate codes,
function sortByDate(array, desc = true) {
return array.sort((a, b) => {
var compare = new Date(a.created_at) < new Date(b.created_at);
return (desc == true) ? ((compare == true) ? 1 : -1) : ((compare == false) ? 1 : -1);
})
}

Remove duplicate elements of an array, in an object of arrays, dynamically

I have checked other solutions but none fit the criterion of my problem
This solution does not have the ability to dynamically check each node
Problem summarized
I wish to create an algorithm that is able to check an object that has nodes of different data types, for duplicated objects in nodes that are specifically of the datatype array.
I have the following dataset:
task = {
content: "lorem....",
customer: [
{ id: 1, name: "hello" },
{ id: 2, name: "sup" },
],
end: "2020-08-13 10:09:48",
project: [{ id: 1 }, { id: 1 }, { id: 2 }],
vendor: [{ id: 2 }, { id: 2 }, { id: 3 }],
};
I wish to be able to dynamically check which of the objects (or nodes? and the algo has to recognize that it is an array) has duplicates, and reduce them to be in this form:
task = {
content: "lorem....",
customer: [
{ id: 1, name: "hello" },
{ id: 2, name: "sup" },
],
end: "2020-08-13 10:09:48",
project: [{ id: 1 }, { id: 2 }],
vendor: [{ id: 2 }, { id: 3 }],
};
EDIT
The algorithm needs to be able to handle a dynamic number of nodes (example 1), however , the duplicates will only happen 1 level down (Thanks for pointing out).
example 1 (there is 1 less node here ) :
task = {
content: "lorem....",
customer: [
{ id: 1, name: "hello" },
{ id: 2, name: "sup" },
],
end: "2020-08-13 10:09:48",
project: [{ id: 1 }, { id: 2 }],
};
Here is my proposed solution to remove duplicate elements from any array in the task object:
const uniq = array => {
const map = {};
const result = [];
for (let i = 0; i < array.length; i++) {
// since elements can be objects, need to do a deep comparison.
const element = JSON.stringify(array[i]);
if (map[element] === undefined) {
map[element] = true;
result.push(array[i]);
}
}
return result;
}
const task = {
content: "lorem....",
customer: [
{ id: 1, name: "hello" },
{ id: 2, name: "sup" },
],
end: "2020-08-13 10:09:48",
project: [{ id: 1 }, { id: 1 }, { id: 2 }],
vendor: [{ id: 2 }, { id: 2 }, { id: 3 }],
};
for (const key in task) {
if (Array.isArray(task[key])) {
task[key] = uniq(task[key])
}
}
console.log('deduped:', task);

Javascript re-order array of object by value

How do I re-order array of object showing below by follow value. If follow value is not -1, move the item below to the item that has the id value same as follow value.
Here is the example.
let charObj = [
{ id: 8, name: 'Catelyn Stark', follow: -1 },
{ id: 7, name: 'Jaime Lannister', follow: 8 },
{ id: 3, name: 'Jon Snow', follow: -1 },
{ id: 4, name: 'Daenerys Targaryen', follow: 7 },
{ id: 5, name: 'Sansa Stark', follow: 4 }
];
Expected output will be;
let charObj = [
{ id: 8, name: 'Catelyn Stark', follow: -1 },
{ id: 7, name: 'Jaime Lannister', follow: 8 },
{ id: 4, name: 'Daenerys Targaryen', follow: 7 },
{ id: 5, name: 'Sansa Stark', follow: 4 },
{ id: 3, name: 'Jon Snow', follow: -1 }
];
Not sure if I can use sort(). What is the best way to re-order this object?
I think this will do what you're asking. I'm sure it could be made more efficient, but unless your list gets quite large that shouldn't make much practical difference. Also, this assumes any character will only have one follower. If that's not the rule, then the function will have to be adjusted.
let charObj = [
{ id: 8, name: "Catelyn Stark", follow: -1 },
{ id: 7, name: "Jaime Lannister", follow: 8 },
{ id: 3, name: "Jon Snow", follow: -1 },
{ id: 4, name: "Daenerys Targaryen", follow: 7 },
{ id: 5, name: "Sansa Stark", follow: 4 }
];
function sortChars(chars) {
let result = [];
let leaders = chars.filter(c => c.follow === -1);
for (let i = 0; i < leaders.length; i++) {
let current = leaders[i];
while (current) {
result.push(current);
let next = charObj.find(c => c.follow === current.id);
current = next;
}
}
return result;
}
console.log(sortChars(charObj));

Reorder array of objects based on attribute

I have an array of objects, each with an 'id' and a 'name'. I'm retrieving an 'id' from the server and need to reorder the array starting from this id.
Example code:
var myList = [
{
id: 0,
name: 'Joe'
},
{
id: 1,
name: 'Sally'
},
{
id: 2,
name: 'Chris'
},
{
id: 3,
name: 'Tiffany'
},
{
id: 4,
name: 'Kerry'
}
];
Given an 'id' of 2, how can I reorder the array so my output is as follows:
var newList = [
{
id: 2,
name: 'Chris'
},
{
id: 3,
name: 'Tiffany'
},
{
id: 4,
name: 'Kerry'
},
{
id: 0,
name: 'Joe'
},
{
id: 1,
name: 'Sally'
}
];
Try this:
function orderList(list, id){
return list.slice(id).concat(list.slice(0,id));
}
Link to demo
You could slice the array at given index and return a new array using spread syntax.
const myList = [{id:0,name:'Joe'},{id:1,name:'Sally'},{id:2,name:'Chris'},{id:3,name:'Tiffany'},{id:4,name:'Kerry'}];
const slice = (arr, num) => [...arr.slice(num), ...arr.slice(0, num)];
console.log(slice(myList, 2));
myList.sort(function(a,b){
return a.id>2===b.id>2?a.id-b.id:b.id-a.id;
});
newList=myList;
http://jsbin.com/kenobunali/edit?console
You could splice the wanted part and use splice to insert it at the end of the array.
var myList = [{ id: 0, name: 'Joe' }, { id: 1, name: 'Sally' }, { id: 2, name: 'Chris' }, { id: 3, name: 'Tiffany' }, { id: 4, name: 'Kerry' }],
id = 2;
myList.splice(myList.length, 0, myList.splice(0, myList.findIndex(o => o.id === id)));
console.log(myList);
using es6 spread syntax
var myList = [{ id: 0, name: 'Joe' }, { id: 1, name: 'Sally' }, { id: 2, name: 'Chris' }, { id: 3, name: 'Tiffany' }, { id: 4, name: 'Kerry' }],
id = 2;
var index = myList.findIndex(o => o.id == id);
var arr = myList.splice(0, index);
var result = [...myList, ...arr];
console.log(result);

Manually change data items in datasource

I have the following datasource with data set to an array.
var dataArray = [
{ Id: 1, Name: "RootA", ParentId: null },
{ Id: 2, Name: "ChildA", ParentId: 1 },
{ Id: 3, Name: "RootB", ParentId: null },
{ Id: 4, Name: "ChildB", ParentId: 3 },
{ Id: 5, Name: "RootC", ParentId: null }
];
var treeListDataSource = new kendo.data.TreeListDataSource({
data: dataArray,
schema: {
model: {
id: "Id",
fields: {
parentId: { field: "ParentId", type: "number", nullable: true },
Id: { field: "Id", type: "number" }
}
}
}
});
This works.
Now I want to change the items in dataArray to:
var newData = [
{ Id: 6, Name: "RootD", ParentId: null },
{ Id: 7, Name: "ChildD", ParentId: 6 },
{ Id: 8, Name: "RootE", ParentId: null }
];
I tried:
Just setting it: dataArray = newData;
Setting via the data() method in the kendo datasource: treeListDataSource.data(newData)
But the grid doesn't display the new values. Instead is just says "no records".
Here's a demo.
I think there is some kind of bug that parentId field won't look up to modified field ParentId after initiation.
You can solve this with create the whole datasource definition again.
Your code should be like this:
<kendo-treelist id="treelist" k-options="treelistOptions"></kendo-treelist>
$scope.change = function() {
var treelist = $("#treelist").data().kendoTreeList;
var newData = [
{ Id: 6, Name: "RootD", ParentId: null },
{ Id: 7, Name: "ChildD", ParentId: 6 },
{ Id: 8, Name: "RootE", ParentId: null }
];
var newDs = new kendo.data.TreeListDataSource({
data: newData,
schema: {
model: {
id: "Id",
fields: {
parentId: { field: "ParentId", nullable: true },
Id: { field: "Id", type: "number" }
}
}
}
});
treelist.setDataSource(newDs);
};
I managed to get it working using the transport API. http://dojo.telerik.com/OBUSU/4
var treeListDataSource = new kendo.data.TreeListDataSource({
transport: {
read: function (options) {
var data = dataArray;
options.success(data);
}
},
...
});
function change() {
var newData = [
{ Id: 6, Name: "RootD", ParentId: null },
{ Id: 7, Name: "ChildD", ParentId: 6 },
{ Id: 8, Name: "RootE", ParentId: null }
];
dataArray = newData;
treeListDataSource.read();
};

Categories

Resources