i have problem looping through a nested array that can contains arrays of itself... that should represent a dynamic menu as follow:
this is how the objects are made:
Interface IMenuNode:
export interface IMenuNode {
title: string;
haveChildren: boolean;
id: string;
node: Array<IMenuNode>;
link: string;
img: string;
value: string;
}
Class DataNode that implements IMenuNode
export class DataNode implements IMenuNode {
title: string;
haveChildren: boolean;
id: string;
node: Array<IMenuNode>;
link: string;
img: string;
value: string;
userMenu: Array<IMenuNode>;
Now i have some informations in the MenuData as follow:
const MenuData: Array<IMenuNode> =
[
new DataNode('Menu 1', true, 'menu1', [
new DataNode('SubMenu 1', true, 'submenu1',[
new DataNode('SubSubMenu1', false ,'subsubmenu1', null, "/", "pathSelectorIcon.png"),
new DataNode('SubSubmenu2', false, 'subsubmenu2', null ,"/", "pathSelectorIcon.png"),
]),
new DataNode('Menu 2', true, 'menu2', [
new DataNode('SubMenu 1', true, 'submenu1',[
new DataNode('SubSubMenu1', false ,'subsubmenu1', null, "/", "pathSelectorIcon.png"),
new DataNode('SubSubmenu2', false, 'subsubmenu2', null ,"/", "pathSelectorIcon.png"),
]),
How can i loop the entire MenuData (even recursively) and dynamically build a new menu (userMenu) based on some conditions
to choose which items (menu and submenu) the new menu should have of?
The function below apparently do what you expect, hope it helps.
userMenu = newUserMenu(MenuData);
function newUserMenu(original: Array<IMenuNode>): Array<IMenuNode> {
const newMenu: Array<IMenuNode> = []
for (let menu of original) {
if (User.hasAccess(menu)) { // Or other conditions
// To ensure new reference
// Note not passing the children, it must pass through recursive method below
const newNode = new DataNode(menu.title, menu.haveChildren, menu.id, null, menu.link, menu.img, menu.value);
newMenu.push(newNode);
if (newNode.haveChildren) {
newNode.node = newUserMenu(menu.node);
}
}
}
return newMenu;
}
I've edited your class and interface too, to ensure that the construction works like the example.
interface IMenuNode {
title: string;
haveChildren: boolean;
id: string;
node?: Array<IMenuNode>;
link?: string;
img?: string;
value?: string;
}
class DataNode implements IMenuNode {
constructor(
public title: string,
public haveChildren: boolean,
public id: string,
public node?: Array<IMenuNode>,
public link?: string,
public img?: string,
public value?: string,
) { }
}
Edit: new example validating the children before adding current level on new menu.
// The new function only add the "dir" menus if they have children where the user have access
function newUserMenu2(original: Array<IMenuNode>): Array<IMenuNode> {
const newMenu: Array<IMenuNode> = [];
for (let menu of original) {
if (User.hasAccess(menu)) {// Or other conditions
// To ensure new reference
// Note not passing the children, it must pass through recursive method below
const newNode = new DataNode(menu.title, menu.haveChildren, menu.id, null, menu.link, menu.img, menu.value);
if (newNode.haveChildren) {
newNode.node = newUserMenu2(menu.node);
}
// Note, only add the menu if it has a link or if it "stores" a menu that the user has access and that has a link
if (Array.isArray(newNode.node) && newNode.node.length > 0 || newNode.link) {
newMenu.push(newNode);
}
}
}
return newMenu;
}
Related
I've been trying to acces an array from my object.
This is my class:
export class Competence {
private _id: string;
private _name: string;
private _isFinished: boolean;
private _subCompetences: string[];
constructor(name: string, isFinished: boolean, subCompetences: string[]) {
this._name = name;
this._isFinished = isFinished;
this._subCompetences = subCompetences;
}
With the getters and setters aswell.
I've been trying to call the subCompetences from a Competence object in this code:
export class StudentModuleDetailsComponent implements OnInit {
private competences: Competence[] = [];
private subcompetences: SubCompetence[] = [];
constructor() { }
ngOnInit() {
this.getData()
}
private showSubCompetences(competence: Competence) {
this.chosenSubCompetences = [];
console.log(competence.subCompetences)
the showSubCompetences() method gets called with a click event and the clicked competence is given as a parameter.
The competence object is initialized in this method that works perfectly fine.
private getData() {
this._apiModulesDataService.getModuleById(this._studentDataService.moduleId).subscribe(
data => {
this._apiModulesDataService;
var self = this;
this.module = data[0];
this.module.competences.forEach(function (comp) {
self._apiCompetenceDataService.getCompetenceById(comp).subscribe(
c => {
if (!self.competences.includes(c)) {
self.competences.push(c[0]);
}
}
);
});
});
}
}
Now when I click the competence it only prints out undefined.
And when I only print the competence like so
console.log(competence)
I get this Json as output
{id: "f39356b0-e2a9-11e8-858b-23856324831a", isfinished: null, name:
"Knippen", subcompetences: Array(2)}
id: "f39356b0-e2a9-11e8-858b-23856324831a"
isfinished: null
name: "Knippen"
subcompetences: Array(2)
0: "08638e20-e2aa-11e8-858b-23856324831a"
1: "0d772570-e2aa-11e8-858b-23856324831a"
length: 2
How do i fix this?
Hmm, first I suggest fixing your model in order to avoid any future errors:
export class Competence {
private _id: string;
private _name: string;
private _isfinished: boolean;
private _subcompetences: string[];
constructor(name: string, isFinished: boolean, subCompetences: string[]) {
this._name = name;
this._isfinished = isFinished;
this._subcompetences = subCompetences;
}
...
}
Then, try logging subcompetences like this:
console.log(competence.subcompetences)
Also, with new model you should be able to properly get isfinished property as well...
Hope this helps.
I'm shortening down my model and method, but either way it represents
my current problem.
Model:
export class OrdersModel {
constructor(public items: [{
itemName: string,
sellerUsername: string,
price: string,
image: string,
itemId: string,
cartId?: string
}]) {
}
}
Method:
checkOut() {
let orderItems = [];
for (let item of this.items) {
orderItems.push({
itemName: item[0].itemName,
sellerUsername: item[0].sellerUsername,
price: item[0].price,
image: item[0].image,
itemId: item[0].itemId
});
}
const order = new OrdersModel(
orderItems
);
this.userProfileService.addToOrders(order)
.subscribe(
data => {
console.log(data);
},
error => console.error(error)
);
}
I'm trying to add multiple items to an order. So the way I've
constructed my model is to have an array of objects (items), and then
store the items as an array of objects in the database. So I'm trying
to loop through my current array of items (the ones to be added to the
order), and add them to my Orders model. If there is an easier way
of doing this, please let me know. But this is my current idea of how
to add the array of items (cart Items) into the Order Model. Here is
my error of orderItems when using is as an argument in the method
checkOut():
Argument of type any[] is not assignable to parameter of type `[{
itemName: string,
sellerUsername: string,
price: string,
image: string,
itemId: string,
cartId?: string
}]`
` Proper ‘0’ is missing in type any[]
I understand that basically I can't assign the array type that I have, but I'm not sure how to fix it.
The problem is that the parameter to the constructor is not an array, it's actually tuple, and tuples have a fixed size. Generally : [type] - tuple with one item of type type, type[] array of type. You can read more about tuples here
constructor(public items: {
itemName: string,
sellerUsername: string,
price: string,
image: string,
itemId: string,
cartId?: string
}[]) {
}
Note I would change you design a bit to use a named interface, so that you can type orderItems correctly as well:
interface OrdersItemModel{
itemName: string,
sellerUsername: string,
price: string,
image: string,
itemId: string,
cartId?: string
}
export class OrdersModel {
constructor(public items: OrdersItemModel[]) {
}
}
function checkOut() {
let orderItems: OrdersItemModel[] = [];
for (let item of this.items) {
orderItems.push({
itemName: item[0].itemName,
sellerUsername: item[0].sellerUsername,
price: item[0].price,
image: item[0].image,
itemId: item[0].itemId
});
}
const order = new OrdersModel(
orderItems
);
}
Hi I am developing web application using Angular 2. I am receiving JSON data using API. I am trying to segregate data. Below is my JSON data.
[
{
"userid":"f8b7b393-b36d-412b-82f7-9500e9eb6924",
"tenantid":"7a4a4ea9-3b39-4ef6-8d00-fcfe7454888c",
"username":"testuser3",
"emailaddress":"testuser3#rkdssravioutlook.onmicrosoft.com",
"isallowed":false,
"userroles":[
{
"userroleid":"c4c64675-ffe0-467b-87a4-00b899e0d48e",
"userid":"f8b7b393-b36d-412b-82f7-9500e9eb6924",
"roleid":"ada09fb2-fa83-4e46-8878-7e4e48c73111",
"tenantappid":1,
"validfrom":"2018-01-24T00:00:00",
"validto":"2018-01-24T00:00:00",
"isactive":true,
"isdeleted":false,
"role":{
"roleid":"ada09fb2-fa83-4e46-8878-7e4e48c73111",
"rolename":"Installer",
"tenantid":"99999999-9999-9999-9999-999999999999",
"isactive":true,
"isdeleted":false,
"actionnames":null,
"scopeids":null,
"scopes":null,
"actionids":null,
"actions":null
}
},
{
"userroleid":"bf632c7b-7540-479e-b8ec-b1471efd7f93",
"userid":"f8b7b393-b36d-412b-82f7-9500e9eb6924",
"roleid":"80dc8c6a-a934-4c2e-9d17-7cdd5b774fc6",
"tenantappid":1,
"validfrom":"2018-01-24T00:00:00",
"validto":"2018-01-24T00:00:00",
"isactive":true,
"isdeleted":false,
"role":{
"roleid":"80dc8c6a-a934-4c2e-9d17-7cdd5b774fc6",
"rolename":"Operator",
"tenantid":"99999999-9999-9999-9999-999999999999",
"isactive":true,
"isdeleted":false,
"actionnames":null,
"scopeids":null,
"scopes":null,
"actionids":null,
"actions":null
}
}
]
},
{
"userid":"8363def7-7547-425c-8d55-2116dd703cfc",
"tenantid":"7a4a4ea9-3b39-4ef6-8d00-fcfe7454888c",
"username":"testuser1",
"emailaddress":"testuser1#rkdssravioutlook.onmicrosoft.com",
"isallowed":false,
"userroles":[
{
"userroleid":"fe2b1f9f-4cd8-48dc-9708-2637e9743c1d",
"userid":"8363def7-7547-425c-8d55-2116dd703cfc",
"roleid":"ada09fb2-fa83-4e46-8878-7e4e48c73111",
"tenantappid":1,
"validfrom":"2018-01-24T00:00:00",
"validto":"2018-01-24T00:00:00",
"isactive":true,
"isdeleted":false,
"role":{
"roleid":"ada09fb2-fa83-4e46-8878-7e4e48c73111",
"rolename":"Installer",
"tenantid":"99999999-9999-9999-9999-999999999999",
"isactive":true,
"isdeleted":false,
"actionnames":null,
"scopeids":null,
"scopes":null,
"actionids":null,
"actions":null
}
}
]
},
{
"userid":"7f359233-5940-4b93-8ec9-fcf39e2fb58f",
"tenantid":"7a4a4ea9-3b39-4ef6-8d00-fcfe7454888c",
"username":"testuser2",
"emailaddress":"testuser2#rkdssravioutlook.onmicrosoft.com",
"isallowed":false,
"userroles":[
{
"userroleid":"c479b1c0-5275-40b2-893e-fc82dc55f1a5",
"userid":"7f359233-5940-4b93-8ec9-fcf39e2fb58f",
"roleid":"4dd2803b-e723-4356-8381-7c514ba13247",
"tenantappid":1,
"validfrom":"2018-01-24T00:00:00",
"validto":"2018-01-24T00:00:00",
"isactive":true,
"isdeleted":false,
"role":{
"roleid":"4dd2803b-e723-4356-8381-7c514ba13247",
"rolename":"Engineer",
"tenantid":"99999999-9999-9999-9999-999999999999",
"isactive":true,
"isdeleted":false,
"actionnames":null,
"scopeids":null,
"scopes":null,
"actionids":null,
"actions":null
}
}
]
}
]
Below are my corresponding models.
export class UserModel {
public userid: string;
public tenantid: string;
public isallowed: boolean;
public emailaddress: string;
public upn: string;
public userroles: UserRole[];
public roleid: string;
public isactive: boolean;
public tenantappid: string;
public username: string;
public userrolestext: string;
public validfrom: string;
public validto: string;
}
Below is role model
export class UserRole {
public userid: string;
public roleid: string;
public role: Role;
}
Below is the sample data i am trying to get
[
{
"userid":"f8b7b393-b36d-412b-82f7-9500e9eb6924",
"tenantid":"7a4a4ea9-3b39-4ef6-8d00-fcfe7454888c",
"rolename":"Installer",
"rolename":"Operator",
},
{
//rest of the data
}
]
First array of above object contains userid and below it contains again array of userroles. So i am trying to get each rolename associated with userid in a single row.
Below code i tried.
users.forEach(eachObj => {
eachObj.userroles.forEach(nestedeachObj => {
});
});
I am not able to go forward in the above foreach loop. Can someone help me to segregate above data? Any help would be appreciated. Thank you.
Hey I really don't know if my code example will achieve what you are looking for but what my example is creating looks like this:
RESULT:
[
{
tenantid: "7a4a4ea9-3b39-4ef6-8d00-fcfe7454888c",
userid: "f8b7b393-b36d-412b-82f7-9500e9eb6924",
rolename: "Operator"
},
{
tenantid: "7a4a4ea9-3b39-4ef6-8d00-fcfe7454888c",
userid: "8363def7-7547-425c-8d55-2116dd703cfc",
rolename: "Installer"
},
{
tenantid: "7a4a4ea9-3b39-4ef6-8d00-fcfe7454888c",
userid: "7f359233-5940-4b93-8ec9-fcf39e2fb58f",
rolename: "Engineer"
}
]
CODE:
const getRelevantData = (array) => {
data.forEach((user) => {
const obj = {};
obj.tenantid = user.tenantid;
obj.userid = user.userid;
user.userroles.forEach((userrole) => {
obj.rolename = userrole.role.rolename;
});
array.push(obj);
});
};
I have added below code and worked fine.
this.userroleData = [];
results.forEach(eachObj => {
eachObj.userroles.forEach(nestedeachObj => {
this.userroleData.push({
username: eachObj.username,
userrolestext: nestedeachObj.role.rolename,
});
});
});
I have 3 arrays here of type channel array.
currentPickSelection: Array<channel>;
draggedChannel: channel;
droppedChannel: channel;
What I am trying to do is remove an item(the droppedChannel array item)from the currentPickSelection array and insert the draggedChannel item array onto the same index of the removed item.
Here is what I did so far, everything works except the insert part:
let index = this.currentPickSelection.findIndex(item => item === this.droppedChannel);
this.currentPickSelection.splice(index, 1, this.draggedChannel);
An this is the way I have the channel model declared:
export class CompChannel {
constructor(public compChannelCbsCode: string,
public compChannelName: string,
public compChannelLogo: string) {}
}
export class channel {
public pickCode: string;
public cbsCode: string;
public channel: string;
public logo: string;
public compChannel: CompChannel[];
constructor(pickCode: string, cbsCode: string, channel: string,
logo: string, compChannel: CompChannel[]) {
this.pickCode = pickCode;
this.cbsCode = cbsCode;
this.channel = channel;
this.logo = logo;
this.compChannel = compChannel;
}
}
Please advise what is wrong!
The droppedChannel object and the item found in currentPickSelection may not the exact same copy/clone of each other.
Try to compare with an unique value(like pickCode or cbsCode) in findIndex method instead of comparing with the whole object.
let currentPickSelection: any[] = [
{ id: 1, label: 'Test1' },
{ id: 2, label: 'Test2' },
{ id: 3, label: 'Test3' }
];
let draggedChannel: any = { id: 5, label: 'Test5' };
let droppedChannel: any = { id: 3, label: 'Test3' };
let index = currentPickSelection.findIndex(item => {
return item.id == droppedChannel.id; //use unique value instead of item object
});
if (index > -1)
currentPickSelection.splice(index, 1, draggedChannel);
Object creation is happening without error:
let paginationParams: Common.Models.PaginationModel = {
PageNumber: this.pageNumber,
PageSize: this.pageSize,
SearchText: this.denominationFilter,
Ascending: true
};
But when trying to create that object like this:
let pagParams = new Common.Models.PaginationModel(
this.pageNumber,
this.pageSize,
true,
this.denominationFilter);
Getting error:
There is a snippet at TS playground
I would say, that we can think about this interface and its implementation
namespace Common.Models
{
export interface IPaginationModel {
PageNumber: number;
PageSize: number;
SearchText: string;
Ascending: boolean;
}
export class PaginationModel implements IPaginationModel {
constructor(
public PageNumber: number,
public PageSize: number,
public SearchText: string,
public Ascending: boolean
){}
}
}
and then we can use it like this
// we use an Interface to assure that the type is as it should be
// we create object which fits to IPaginationModel structure
let paginationParams: Common.Models.IPaginationModel = {
PageNumber: this.pageNumber,
PageSize: this.pageSize,
SearchText: this.denominationFilter,
Ascending: true
};
// here we use a class
// to call its constructor
let pagParams = new Common.Models.PaginationModel(
this.pageNumber,
this.pageSize,
this.denominationFilter,
true);
// and we can even use class as interface (as the first example)
let paginationParamsAsClassAPI: Common.Models.PaginationModel = {
PageNumber: this.pageNumber,
PageSize: this.pageSize,
SearchText: this.denominationFilter,
Ascending: true
};
So, we can use interface and class as a type, while building plain JS object (first and third example) or we can use the class constructor to build such instance.
Check it here