I have sidebar-items.ts
export const ROUTES: RouteInfo[] = [
{
path: 'dashboard',
title: 'dashboard',
moduleName: 'dashboard',
role: [Role.COMMUNITY_ADMIN, Role.BOARD_MEMBER,Role.CHAIRMAN,Role.OWNER,Role.TENANT],
submenu: [],
},
{
path: '',
title: 'users',
moduleName: 'users',
role: [Role.COMMUNITY_ADMIN, Role.OWNER, Role.TENANT, Role.BOARD_MEMBER, Role.CHAIRMAN],
submenu: [
{
path: 'persons',
title: 'persons',
moduleName: 'persons',
role: [Role.COMMUNITY_ADMIN, Role.OWNER, Role.TENANT, Role.BOARD_MEMBER, Role.CHAIRMAN],
submenu: [],
},
{
path: 'users',
title: 'users',
moduleName: 'users',
role: [Role.COMMUNITY_ADMIN],
submenu: [],
},
{
path: 'owner/list',
title: 'owner',
moduleName: 'owner',
role: [Role.COMMUNITY_ADMIN, Role.OWNER, Role.TENANT, Role.BOARD_MEMBER, Role.CHAIRMAN],
submenu: [],
}
],
},
{....}]
My user login has role "TENANT".
I want to show menu with only Role.TENANT for this I create a filter like code below. This filter is only for menu, not for submenu. I want a filter for submenu, users's submenu. When I login with account that has role TENANT, in menu doesn't show users/users because users/users has only role: [Role.COMMUNITY_ADMIN].
this.allowedCommunity = 'community/create';
this.currentUserLoggedIn = this.authService.currentUserLoggedInAccount;
const userRolesFiltered = this.currentUserLoggedIn.user?.user_roles?.filter(
(userRole: any) =>
formatDate(userRole.end_date, 'yyyy-MM-dd', 'en_US') >=
formatDate(new Date(), 'yyyy-MM-dd', 'en_US')
);
this.sidebarItems = ROUTES.filter(
(x) =>
userRolesFiltered?.some((userRole: any) =>
x.role.includes(userRole.role.name)
)
)
Any idea please?
There you go. Check my implementation at StackBlitz
i have this situation.
CheckboxesComponent
<section
*ngFor="let group of model.groups | myfilter:term; let index = index">
<div>
<mat-checkbox
[checked]="group.allChecked"
[ngModel]="group.allChecked"
color="primary">
{{ group.name }}
</mat-checkbox>
</div>
<div>
<ul>
<li *ngFor="let checkbox of groups.checkboxes;">
<mat-checkbox
[checked]="checkbox.check"
[(ngModel)]="checkbox.check"
color="primary">
{{ checkbox.displayName }}
</mat-checkbox>
</li>
</ul>
</div>
</section>
In a second component i have
<mat-form-field
appearance="outline">
<mat-label>
Search by
</mat-label>
<input
matInput
type="text"
[(ngModel)]="filter">
<mat-icon matPrefix fontIcon="icon-search"></mat-icon>
</mat-form-field>
<app-checkbox-group
[datasource]="claims"
[term]="filter"
>
</app-checkbox>
and this pipe
#Pipe({
name: 'roleFilter',
pure: false
})
export class myfilter implements PipeTransform {
transform(groups: [], term: string): [] {
if (!term) {
return groups;
}
return groups
.map(obj => {
return Object.assign({}, obj, {
checkboxes: obj.checkboxes.filter(el => el.displayName.includes(term))
})
})
.filter(obj => obj.checkboxes.length > 0)
}
}
and groups is a dataset like this
[
{
name: 'Group 1',
allChecked: false,
isIndeterminate: false,
checkboxes: [
{
check: true,
displayName: 'first',
name: 'first',
id: '1',
isMandatory: false
},
{
check: false,
displayName: 'second',
name: 'second',
id: '2',
isMandatory: false
},
{
check: false,
displayName: 'third',
name: 'third',
id: '3',
isMandatory: false
},
{
check: false,
displayName: 'fourth',
name: 'fourth',
id: '4',
isMandatory: false
},
{
check: false,
displayName: 'fifth',
name: 'fifth',
id: '5',
isMandatory: false
},
{
check: false,
displayName: 'sixth',
name: 'sixth',
id: '6',
isMandatory: false
},
{
check: false,
displayName: 'seventh',
name: 'seventh',
id: '7',
isMandatory: false
},
{
check: false,
displayName: 'eighth',
name: 'eighth',
id: '8',
isMandatory: false
},
]
}
]
When i start typing on the input filter, to reduce the dataset, if i start typing with a letter that not match with any displayName all groups are hidden and it's work like expected.
The problem appears when i start typing with a letter that match with some of the displayName property of the checkboxes.
I don't understand why but all page freeze and the map function is called infinite times.
The problem seem to be in
Object.assign in the map method. Because if i change this line with
obj.checkboxes = checkboxes: obj.checkboxes.filter(el => el.displayName.includes(term)) it works but replace the original checkboxes with the filtered one.
In accordion to #Andrei comment
try to add trackByIndex(idx) {return idx;} method and pass it to both ngFor insatnces like this *ngFor="let checkbox of groups.checkboxes; trackBy: trackByIndex"
The solution was using the trackBy pipe on both *ngFor directives.
I am trying to build a menu where only some of the menu items would have submenus. I am using ng-repeat and ui-router. For example, these are a reduced set of main menu items:
vm.routes = [
{ name: 'Home', path: 'home' },
{ name: 'Streams', path: 'streams' },
{ name: 'Overlays', path: 'overlays' },
{ name: 'Admin', path: 'admin' }
];
In the HTML I am using this:
<li class="vic-menu-item"
ng-repeat="route in vm.routes"
<a ui-sref="{{route.path}}">{{route.name}}</a>
</li>
Now I want to add sub-menus to the Admin menu. But other menu items may not have submenus, like Home for example. So its inclusion would have to be conditional on some property in my vm.routes array.
Question: using the Angular way, how do I use conditionals in the ng-repeat so I can build the menu ul tag with optional sub menu items?
I have looked at some of the similar questions but they are confusing to me and none appear to answer this specific technique.
Thanks,
-Andres
First of all you should create array with same structure
vm.routes = [
{ name: 'Home', path: 'home', submenu:[
{name: 'Submenu-1', path: ''},
{name: 'Submenu-2', path: ''}
] },
{ name: 'Streams', path: 'streams' },
{ name: 'Overlays', path: 'overlays' },
{ name: 'Admin', path: 'admin' }
];
After that in html:
<li class="vic-menu-item"
ng-repeat="route in vm.routes"
<a ui-sref="{{route.path}}">{{route.name}}</a>
<ul ng-if='route.submenu'>
<li ng-repeat='submenu in route.submenu'>
<a ui-sref="{{submenu.path}}">{{submenu.name}}</a>
</li>
</ul>
</li>
I am displaying data I get from a json but ng-repeat display it in asc order I want to just display as it is in the json and skip sorting.
Here is my html:
div ng-repeat="(key, data) in List">
<div class="component-title">{{key}}</div>
<div ng-repeat="(key, value) in data">
<div ng-repeat="(key, item) in value">
<div class="row test-label" ng-if="key === 'name'">
<div class="pull-left">
<span class="glyphicon glyphicon-ban-circle"></span>
{{item}}
</div>
<div class="pull-right">
<ul class="pull-right nav nav-pills">
<li><span class="glyphicon glyphicon-pencil"></span></li>
<li>|</li>
<li><span class="glyphicon glyphicon-ban-circle"></span></li>
</ul>
</div>
</div>
</div>
</div>
</div>
My .js file:
(function () {
'use strict';
angular.module('main')
.directive('chTest', function () {
return {
templateUrl: '/templates/chTestDirective.html',
controller: ['$scope', function ($scope) {
$scope.List = {
n: [
{
is_enabled: false,
status: '',
id: 'set',
name: 'set',
result: ''
},
{
is_enabled: false,
status: 'failed',
id: 'list_of_tests',
name: 'list_of_tests',
result: ''
},
{
is_enabled: false,
status: 'failed',
id: 'single_test',
name: 'single_test',
result: ''
},
{
is_enabled: false,
status: 'passed',
id: 'all_tests',
name: 'all_tests',
result: ''
},
{
is_enabled: false,
status: 'passed',
id: 'specific_regex',
name: 'specific_regex',
result: ''
}
],
c: [
{
is_enabled: false,
status: 'running',
id: 'boot-runcommand-delete',
name: 'bootruncommanddelete',
result: ''
},
{
is_enabled: false,
status: 'failed',
id: 'boot_runcommand_delete_custom_image',
name: 'boot_runcommand_delete_custom_image',
result: ''
},
{
is_enabled: false,
status: 'running',
id: 'boot-runcommand-delete-with-disk',
name: 'bootruncommanddeletewithdisk',
result: ''
}
],
ce: [
{
is_enabled: false,
status: '',
id: 'create_delete_node_group_templates',
name: 'create_delete_node_group_templates',
result: ''
},
{
is_enabled: false,
status: 'running',
id: 'create_scale_delete_cluster',
name: 'create_scale_delete_cluster',
result: ''
},
{
is_enabled: false,
status: 'failed',
id: 'create_and_delete_cluster',
name: 'create_and_delete_cluster',
result: ''
},
{
is_enabled: false,
status: 'passed',
id: 'create_and_list_node_group_templates',
name: 'create_and_list_node_group_templates',
result: ''
}
],
k: [
{
is_enabled: false,
status: 'passed',
id: 'boot',
name: 'boot',
result: ''
},
{
is_enabled: false,
status: 'failed',
id: 'list-servers',
name: 'listservers',
result: ''
}
],
neutron: [
{
is_enabled: false,
status: 'running',
id: 'create-and-delete-node',
name: 'createanddeletenode',
result: ''
},
{
is_enabled: false,
status: 'passed',
id: 'create-and-list-node',
name: 'createandlistnode',
result: ''
}
],
g: [
{
is_enabled: false,
status: 'running',
id: 'create-and-delete-image',
name: 'createanddeleteimage',
result: ''
},
{
is_enabled: false,
status: 'passed',
id: 'create-and-list-image',
name: 'createandlistimage',
result: ''
},
{
is_enabled: false,
status: 'failed',
id: 'create-image-and-boot-instances',
name: 'createimageandbootinstances',
result: ''
},
{
is_enabled: false,
status: 'failed',
id: 'list_images',
name: 'list_images',
result: ''
}
],
s: [
{
is_enabled: false,
status: 'passed',
id: 'keystone',
name: 'keystone',
result: ''
},
{
is_enabled: false,
status: '',
id: 'token_validate_cinder',
name: 'token_validate_cinder',
result: ''
},
{
is_enabled: false,
status: '',
id: 'token_validate_neutron',
name: 'token_validate_neutron',
result: ''
},
{
is_enabled: false,
status: 'failed',
id: 'token_validate_heat',
name: 'token_validate_heat',
result: ''
},
{
is_enabled: false,
status: 'passed',
id: 'token_validate_glance',
name: 'token_validate_glance',
result: ''
},
{
is_enabled: false,
status: 'passed',
id: 'token_validate_nova',
name: 'token_validate_nova',
result: ''
}
],
q: [
{
is_enabled: false,
status: 'failed',
id: 'nova-update-and-delete',
name: 'novaupdateanddelete',
result: ''
},
{
is_enabled: false,
status: 'running',
id: 'nova-update',
name: 'novaupdate',
result: ''
},
{
is_enabled: false,
status: 'passed',
id: 'neutron-update',
name: 'neutronupdate',
result: ''
},
{
is_enabled: false,
status: 'passed',
id: 'cinder-update',
name: 'cinderupdate',
result: ''
},
{
is_enabled: false,
status: 'passed',
id: 'cinder-update-and-delete',
name: 'cinderupdateanddelete',
result: ''
}
]
};
}]
};
});
})();
How can be this achieved? Thanks
In short: Upgrade to 1.4
https://docs.angularjs.org/api/ng/directive/ngRepeat
You need to be aware that the JavaScript specification does not define
the order of keys returned for an object. (To mitigate this in Angular
1.3 the ngRepeat directive used to sort the keys alphabetically.)
Version 1.4 removed the alphabetic sorting. We now rely on the order
returned by the browser when running for key in myObj. It seems that
browsers generally follow the strategy of providing keys in the order
in which they were defined, although there are exceptions when keys
are deleted and reinstated. See
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete#Cross-browser_issues
If this is not desired, the recommended workaround is to convert your
object into an array that is sorted into the order that you prefer
before providing it to ngRepeat. You could do this with a filter such
as toArrayFilter or implement a $watch on the object yourself.
I use plugin zabuto_calendar(https://github.com/zabuto/calendar).
$("#calendar").zabuto_calendar({
language: "ru",
show_previous: true,
show_next: true,
cell_border: true,
today: true,
show_days: true,
weekstartson: 1,
nav_icon: {
prev: '<i class="fa fa-chevron-circle-left"></i>',
next: '<i class="fa fa-chevron-circle-right"></i>'
},
ajax: {
url: "/cabinet/info/show_calendar_data.php",
modal: true
}
});
It's need update calendar when select input changed. I must to add new GET parameter "category", which is select input's value, in ajaxSettings.url.
How can I get $("#calendar") options?