nz-dropdown-menu called from *ngFor - ng-zorro-antd

I have and simple ngFor and I would like for each entry to have a button with dropdown and each menu item should call a different function for the specific item in the ngFor.
The code below works and the behaviour is what I expect.
<div *ngFor="let order of orders">
<nz-dropdown>
<button nz-button nz-dropdown [nzType]="'primary'" nzGhost>
<span>Almighty Dropdown</span><i nz-icon nzType="ellipsis"></i>
</button>
<ul nz-menu>
<li nz-menu-item (click)="fc1(order)">Function 1</li>
<li nz-menu-item (click)="fc2(order)">Function 2</li>
</ul>
</nz-dropdown>
</div>
However I get the error:
ng-zorro-antd-core.js:658 [NG-ZORRO]: deprecated: 'nz-dropdown' Component > is going to be removed in 9.0.0. Please use 'nz-dropdown-menu' instead.
The code suggested by NG-ZORRO is:
<button nz-button nz-dropdown [nzDropdownMenu]="menu">Actions<i nz-icon nzType="down"></i></button>
<nz-dropdown-menu #menu="nzDropdownMenu">
<ul nz-menu>
<li nz-menu-item>
<a>1st item</a>
</li>
<li nz-menu-item>
<a>2nd item</a>
</li>
<li nz-menu-item>
<a>3rd item</a>
</li>
</ul>
</nz-dropdown-menu>
If I use code like NG-ZORRO suggest in the documentation, how can I pass the 'order' item from the ngFor to the 'clicks' on the submenus?

Pass the order to the click function as your first example code, and it still works.
<div class="order" *ngFor="let order of orders">
{{order.name}}
<button nz-button nz-dropdown [nzDropdownMenu]="menu">Actions<i nz-icon nzType="down"></i></button>
<nz-dropdown-menu #menu="nzDropdownMenu">
<ul nz-menu>
<li nz-menu-item>
1st item
</li>
<li nz-menu-item>
2nd item
</li>
<li nz-menu-item>
3rd item
</li>
</ul>
</nz-dropdown-menu>
</div>
You can check this example out:
https://stackblitz.com/edit/ng-zorro-antd-start-hnxupx

Related

Tabs click not working when using ng-repeat

I have a script to add custom tabs on runtime.All the tabs are being created but for some reason those created with ng-repeat can't be selected, is like a plain label. What am I missing?
<ul class="clearfix tabs-list tabamount6 tabs">
<li data-tab="tab-1">News</li>
<li data-tab="tab-2">Meet the team</li>
<li class="current" data-tab="tab-3">Related articles</li>
<li data-tab="tab-4">Videos</li>
<li ng-repeat="t in tabs" data-tab="ctab-{{t.Id}}">{{t.Title}}</li>
<asp:Literal ID="AddNewTab" runat="server"></asp:Literal>
</ul>

Is this the correct implementation of the BEM naming convention for navigation?

I am trying to implement a main menu (including sub menu) for a website using the BEM CSS naming convention. I have found myself nesting elements which I think is an antipattern of the convention?
<ul class="nav__list">
<li class="nav__item">
<a class="nav__link" href="#">Main item</a>
<div class="nav__submenu">
<div class="nav__group">
<h3>Nav group</h3>
<ul class="nav__group__list">
<li class="nav__group__item">
<a class="nav__group__link" href="#">Nav item</a>
</li>
</ul>
</div>
</div>
</li>
</ul>
It's always though to nest deep. You can not have Element of Element in the BEM methodology. So this nav__group__list is not correct, could be nav__group-list for example.
The correct BEM markup could look something like this.
<ul class="nav">
<li class="nav__item">
<a class="nav__link" href="#">Main item</a>
<div class="nav__submenu">
<div class="nav__group">
<h3>Nav group</h3>
<ul class="nav__group-list">
<li class="nav__group-item">
<a class="nav__group-link" href="#">Nav item</a>
</li>
</ul>
</div>
</div>
</li>
</ul>
However you can separate the "Group list", especially if it can be reused elsewhere in your project.
Your menu with separated links-group Block would look something like this:
<ul class="nav">
<li class="nav__item">
<a class="nav__link" href="#">Main item</a>
<div class="nav__submenu">
<div class="links-group">
<h3 class="links-group__heading">Nav group</h3>
<ul class="links-group__list">
<li class="links-group__item">
<a class="links-group__link" href="#">Nav item</a>
</li>
</ul>
</div>
</div>
</li>
</ul>
I've been there and I know what you're trying to do - avoid styling by nesting for every price. Believe me it's not the way. Try to keep it simple, don't be afraid of making elements intended to be nested inside the other but don't use second-level nesting in your naming to avoid "really__long__class__names" and renaming everything in case you want to change the HTML structure. Think of BEM as a method of isolating components, breaking a complex UI into simple chunks easy to understand and maintain. In you specific case I'd probably go with something like this:
<nav class="nav">
<ul class="nav__list">
<li class="nav__item">
<a class="nav__link" href="#">Main item</a>
<div class="nav--submenu">
<div class="nav__group">
<h3 class="nav__header">Nav group</h3>
<ul class="nav__list">
<li class="nav__item">
<a class="nav__link" href="#">Nav item</a>
</li>
</ul>
</div>
</div>
</li>
</ul>
</nav>
Than I'd add a different styling for elements nested inside .nav--submenu. What you do want to avoid is cross-nesting between blocks, but inside them go with whatever feels right and if the block is getting too complex, think of extracting it's part to a new one.

Bootstrap dropdown - changing display property of menu items

I am using Bootstrap dropdown menu with angular. I want to make some menu items visible and invisible using the display property. Class hidden_item is defined as display:none. When the user logs in, it does show the "Messages" menu item but clicking on it does not show Inbox and Sent links. Later if I refresh the page, everything works as expected and Inbox and Sent become visible. How can I make it work without refreshing the page?
<li [ngClass]="isLoggedIn() ? 'dropdown' : 'hidden_item'">
<a [routerLink]="['Mailbox', {'boxname': 'inbox'}]" class="dropdown-toggle">Messages <span class="nav-up-carret"></span></a>
<ul class="dropdown-menu" role="menu">
<li><a [routerLink]="['Mailbox', {'boxname': 'inbox'}]">Inbox</a> </li>
<li><a [routerLink]="['Mailbox', {'boxname': 'sent'}]">Sent</a></li>
</ul>
</li>
You can use *ngIf and try it this way:
li *ngIf="isLogedIn()">
<a [routerLink]="['Mailbox', {'boxname': 'inbox'}]" class="dropdown-toggle">Messages <span class="nav-up-carret"></span>
</a>
<ul class="dropdown-menu" role="menu">
<li><a [routerLink]="['Mailbox', {'boxname': 'inbox'}]">Inbox</a> </li>
<li><a [routerLink]="['Mailbox', {'boxname': 'sent'}]">Sent</a></li>
</ul>
</li>
This way, angular will automatically remove the block from the dom if isLogedIn() returns false but will add it if it returns true.
If I understood your problem correctly, you are missing a data-toggle="dropdown" property in your 'Messages' anchor element.
It should be
<li [ngClass]="isLogedIn() ? 'dropdown' : 'hidden_item'">
<a [routerLink]="['Mailbox', {'boxname': 'inbox'}]" class="dropdown-toggle" data-toggle="dropdown">Messages <span class="nav-up-carret"></span></a>
<ul class="dropdown-menu" role="menu">
<li><a [routerLink]="['Mailbox', {'boxname': 'inbox'}]">Inbox</a> </li>
<li><a [routerLink]="['Mailbox', {'boxname': 'sent'}]">Sent</a></li>
</ul>
</li>

CSS selector within stacked lists

I am trying to style the nav in a template theme that I neither wrote nor picked. The nav uses lists in its structures and the children at various levels have the same class. I'm hoping someone can help me find the right CSS selector to pick the third level down. Here is the basic structure:
<nav class="nonbounce desktop vertical">
<ul>
<li class="item sub active">
<a class="itemLink" href="https://sitename/tools/" title="Tools">Tools</a>
<ul class="subnav">
<li class="subitem">
<a class="subitemLink" href="https://sitename/tools/outdoors/" title="Outdoors">Outdoors</a>
<ul class="subnav">
<li class="subitem">
<a class="subitemLink" href="https://www.safenready.net/tools/outdoors/mowers/" title="mowers">Mowers</a> THIS ONE!!!
</li>
</ul>
</li>
</ul>
</li>
</ul>
</nav>
What I need to do is grab the 3rd level down (called Mowers in example).
My ultimate goal is to style this level and move it vertically but first I need to be able to modify only that level with CSS.
This is a new site but I can provide the real site URL if that would help.
jc
You can try this
.subitemLink[title~="mowers"] {
font-size:20px;
}
<nav class="nonbounce desktop vertical">
<ul>
<li class="item sub active">
<a class="itemLink" href="https://sitename/tools/" title="Tools">Tools</a>
<ul class="subnav">
<li class="subitem">
<a class="subitemLink" href="https://sitename/tools/outdoors/" title="Outdoors">Outdoors</a>
<ul class="subnav">
<li class="subitem">
<a class="subitemLink" href="https://www.safenready.net/tools/outdoors/mowers/" title="mowers">Mowers</a> THIS ONE!!!
</li>
</ul>
</li>
</ul>
</li>
</ul>
</nav>

ng-repeat only populates last entry in array when used with uib-dropdown

I'm trying to populate a drop down menu using UI Bootstrap's uib-dropdown and ng-repeat but only the last record in the array is being populated.
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li ng-class="{active: isActive('/resources/')}" class="dropdown" uib-dropdown>
<a uib-dropdown-toggle class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="true">Resources <span class="caret"></span></a>
<ul ng-repeat="resource in TN.resourceList" class="dropdown-menu">
<li>{{ resource.ResourceText }}</li>
</ul>
</li>
</ul>
</div>
I've confirmed that TN.resourceList has 3 records.
If I remove: class="dropdown-menu"
from: <ul ng-repeat="resource in TN.resourceList" class="dropdown-menu">
then all the records display but it no longer renders as a drop down menu.
I also tried adding the uib-dropdown-menu directive to the <ul> with the ng-repeat on it as well as the role attributes as suggested in this answer: Bootstrap Dropdownlist Issue in angular JS
But it had no effect.
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li ng-class="{active: isActive('/resources/')}" class="dropdown" uib-dropdown>
<a uib-dropdown-toggle class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="true">Resources <span class="caret"></span></a>
<ul class="dropdown-menu">
<li ng-repeat="resource in TN.resourceList">{{ resource.ResourceText }}</li>
</ul>
</li>
</ul>
</div>
Notice the ng-repeat on the li instead of the ul dom element (ng-repeat repeats elements where it added to and it's childeren).
You're repeating the dropdown-menu itself. You should have one dropdown-menu and repeat the li instead:
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li ng-class="{active: isActive('/resources/')}" class="dropdown" uib-dropdown>
<a uib-dropdown-toggle class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="true">Resources <span class="caret"></span></a>
<ul class="dropdown-menu">
<li ng-repeat="resource in TN.resourceList">{{ resource.ResourceText }}</li>
</ul>
</li>
</ul>
</div>
Easiest answer is to consider looking at the ng-repeat itself as a loop. Within normal html, you wouldn't want to have multiple lists or 'ul' tags would you? You would want one list with multiple entries or 'li' tags.
Consider the answers above as direct answers, but realistically, you should be able to look at your code and figure out that you want to repeat the list entries and not the list itself.

Resources