Trying to use the new md-tab-nav-bar like this:
<nav md-tab-nav-bar>
<a md-tab-link routerLink="/admin/management" routerLinkActive #rla="routerLinkActive" [active]="rla.isActive">Management</a>
</nav>
but get an error
TypeError: Cannot read property 'some' of undefined
Seems like this way should work after commit: https://github.com/angular/angular/commit/c9f58cf78cce420762c7f8c51172a10a497468ea
Pls add a plunkr with repro.
Please use the issue template which helps us reproduce and diagnose the issue. Including a plunkr with this bug will help us determine what is happening.
This is exactly how I am trying to use this feature as well, super easy way to keep your tabs in line with your location. I am working on a plunkr but I am running into some issues just getting it set up.
[active]="someBoolean"
directive to the anchor, I get yelled at by the compiler: VM1000 zone.min.js:1 Unhandled Promise rejection: Template parse errors:
Can't bind to 'active' since it isn't a known property of 'a'. ("ks" color="primary">
<a md-tab-link *ngFor="let child of directory; let i = index;"
[ERROR ->][active]="routerLinkActive"
(click)="activateLink(i)">
I am assuming this is because it is a pretty new feature. I looked through systemjs.config and it seems to be asking for the latest, so I don't know where to go from here.
If someone can help me resolve these two issues I can finish up the plunkr and we can get this feature working.
Thanks for the fast update. I updated the plunkr. All the relevant code is in app.component.html
. I commented the hell out of it explaining what we are looking for. Hopefully it is just a syntactic mistake. Please let me know if I can help in any way. Thanks for all your hard work, this is an amazing set of components and I hope that I can contribute soon.
I just tried adding the safe navigation operator to the rla
template variable i.e. [active]="rla?.isActive
. I was hoping that perhaps it just need time to load its values, but no dice, I am still getting the same error messages.
I'm getting the same error when trying to use the value in to set a class:
[ngClass]="{'icon icon_contact' : (rla && rla.isActive)}"
Results in
core.umd.js:2838 EXCEPTION: Error in /js/app/templates/nav-primary.html:18:38 caused by: Cannot read property 'some' of undefinedErrorHandler.handleError ....
If you just need to add a class to the active link and remove it when it's not active, Angular has a built in directive that does that.
<a routerLink="/someUrl" [routerLinkActive]="['class1', 'class2']"> A cool link </a>
So, yours would be:
<a routerLink="/someUrl" [routerLinkActive]="['icon ', 'icon_contact']"> A cool link </a>
Here are some docs that might help.
Here is a plunkr where .class1
and .class2
follow the active link.
You will notice that it updates the classes even if the redirect comes from a link outside of the md-tab-link
, but Material's border-bottom
only registers ng-reflect-active="true"
if redirected by the md-tab-link
. Though it would follow the active link if we can get [active]="rla.isActive"
to work.
Yes, I use that else where. The problem I am trying to solve is that I want to apply a class to something that is a child or my routerlink. Like this:
<a routerLink="/someUrl"><span [routerLinkActive]="['class1', 'class2']">I want the class on this span</span></a>
From what I can tell that is what the RouterLinkActive directive export was trying to solve and it works fine if I throw it in as interpolation like class="{{rla.isActive?'icon_contact':''}}",
but blows up when I try to use it inside the ngClass directive with the rla variable. If that routerLinkActive is supposed to work on children and I'm just doing something wrong please let me know.
If you can update that plunkr to demonstrate what you are looking for, I think I should be able to help you.
Here is a fork of that plunkr. My goal is to be able to apply a class to something within the router link rather than the routerlink itself. I think it is the same issue as the OP because they are both trying to access the isActive within an expression.
Okay... I've done everything I can think of. It seems these particular attributes ,[active]
and [ngClass]
, don't want to wait for rla.isActive
to load and return a boolean. They won't wait even when using the Safe Navigation Operator ?.
, which is explicitly telling them to.
You can however use class bindings even in the child of the element containing routerLinkActive
:
<a md-tab-link routerLink="someLink"
routerLinkActive
#rla="routerLinkActive">
<span [class.someClass]="rla.isActive">Working child link</span>
</a>
I would argue that this is actually cleaner than using ngClass
. Here is the plunkr.
Can anyone help me get the same functionality out of [active]='rla.isActive'
? I can't understand why binding to one attribute works perfectly while binding to another refuses to.
@DzmitryShylovich will your pull request #13341 address these issues?
@nayfin yes, but it's not clear when it will be merged
@DzmitryShylovich AFAICS your PR doesn't introduce backwards incompatible changes at the moment, please correct me if I'm wrong.
@andrewseguin considering @DzmitryShylovich's PR is safe to merge, could you raise the priority of this issue. I believe this is pretty much how tabs component will be used in the most of the apps.
/cc @jelbourn
P.S. Sorry for bothering during the holidays 😉. Happy Christmas! 🎄 🎅
Good afternoon!
I just ran into this very same issue today. When debugging my own code stil left me blocked, I turned to the web and found this thread. It changed the way I was looking at the issue and that helped me find a way to work around it in the immediate term.
I haven't enough time to draft an example at the moment. I will follow up with one later on if this description is unclear, but want to offer what I have now in the meantime.
It looks like the problem here is that the RouterLinkActive.isActive() method is dependent upon a @ViewChildren query-induced injection to occur. AFAIK, that happens during the content initialization stage of compilation. The property annotated with @ViewChildren is "this.links".
The call to RouterLinkActive.isActive( ) is part of the same content model where RouterLinkActive is getting links injected from RouterLink. which explains why "this.links.changes.some( )" causes "Cannot read property 'some' of undefined" to be thrown--it isn't injected by the time the first call to isActive() expects it to be there, and the implementation of isActive( ) doesn't have a defensive check allowing it to return false when it's called so early.
I confirmed that adding that undefined check in isActive( ) solved my issue, but modifying the framework isn't really a viable workaround. I couldn't make the framework tolerate an early call to isActive(), so I forced my component to defer its first call.
Before workaround:
<a md-tab-link routerLink="/lobby" routerLinkActive #rla="routerLinkActive" [active]="rla.isActive">Lobby</a>
After workaround:
<a md-tab-link routerLink="/lobby" routerLinkActive #rla="routerLinkActive" [active]="
rlaSafe &&rla.isActive">Lobby</a>
And in the Component code
export class MyNavbarComponent implements AfterViewInit {
private rlaSafe: boolean = false;
public ngAfterViewInit() {
this.rlaSafe = true;
}
The additional boolean stops the flow control from reaching isActive() until after the view initialization lifecycle event has passed, by which time the response to RouterLinkActive's @ViewChildren query has been injected and the call to isActive( ) therefore no longer gets tripped up on an uninitialized reference.
Its not transparent, so its a work-around and not a solution, but it unblocked the rest of what I have yet to do early this week, so I'm comfortable with it for now.
@jheinnic thanks. That's very helpful as I ran into this today as well!
I had to make a small change to this to keep zone.js happy.
private rlaSafe: boolean = false;
constructor(private changeDetectionRef: ChangeDetectorRef) {}
public ngAfterViewInit() {
this.rlaSafe = true;
// Fix "Expression has changed after it was checked" exception from Zone.js
this.changeDetectionRef.detectChanges();
}
@andrewseguin This looks like it's a bug in Angular, specifically router_link_active.ts
. The function:
private hasActiveLink(): boolean {
return this.links.some(this.isLinkActive(this.router)) ||
this.linksWithHrefs.some(this.isLinkActive(this.router));
}
Should guard against links
and linksWithHrefs
being null/undefined. This is something we could fix.
Just a note: each <a md-tab-link></a>
element must have a unique variable name for its routerLinkActive object or it will not correctly set its tab to active.
Is there maybe a way to reference specifically the element variable (e.g. #rla="routerLinkActive" [active]="#rla.isActive"
)
app.component.html
<nav md-tab-nav-bar>
<a md-tab-link routerLink="browse-pets" routerLinkActive #rla="routerLinkActive" [active]="rlaSafe && rla.isActive">Browse Pets</a>
<a md-tab-link routerLink="/sell-pet" routerLinkActive #rlab="routerLinkActive" [active]="rlaSafe && rlab.isActive">Sell Pet</a>
</nav>
app.component.ts
import { Component, AfterViewInit, ChangeDetectorRef } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements AfterViewInit{
constructor(private changeDetectionRef: ChangeDetectorRef) {}
private rlaSafe: boolean = false;
ngAfterViewInit() {
this.rlaSafe = true;
this.changeDetectionRef.detectChanges();
}
}
Thanks for the help and simple workaround until merge. Here is a plunkr of workaround for anyone who would like a full example.
Hi everyone, I found this error after a sleepless night of thinking I was doing something wrong while trying to implement the documented MdTabNavBar Directive example shown at the bottom of https://material.angular.io/components/component/tabs#tabs-and-navigation (under "Tabs and Navigation")..
Obviously, since this is still an open issue, that example (written verbatim) wont work.
I think it would be great if someone put a quick note next to that example pointing to this issue so that people dont waste too much time thinking they are not following what they may think is documented correctly. Something like the following would suffice.
Note: In it's current form, example above has a known bug and will not work, please consult Issue #1967 for more details and for for a work around whilst this issue is being resolved by the Angular team.
After racking my head quite a while, I came to the same conclusion as @jelbourn. I think it's essential that in RouterLinkActive.hasActiveLink()
, the values RouterLinkActive.links
and RouterLinkActive.linksWithHrefs
are checked for null/undefined values as a guard, before doing the activeLink testing.
Has anyone raised this as an issue in the https://github.com/angular/angular repo yet? Or perhaps created a quick PR?
I would additionally like to suggest the change below to the MdTabLink
class in this repo.
The reason again is for safety, so that we are only updating the nav bar's active link when the view / content is ready. Haven't had time to test yet but, what do you all think?
(Refer to: tab-nav-bar.ts)
/* ... */
// New MdTabLink
@Directive({
selector: '[md-tab-link], [mat-tab-link]',
})
export class MdTabLink implements AfterContentInit {
private _isActive: boolean = false;
/** Whether the link is active. */
@Input()
get active(): boolean {
return this._isActive;
}
set active(value: boolean) {
this._isActive = value;
this._setActiveNavLink();
}
//flag to help double check that nav update only occurs when content is ready
private _contentReady: boolean = false;
ngAfterContentInit(){
this._contentReady = true;
this._setActiveNavLink();
}
private _setActiveNavLink(){
if (this.active && this._contentReady) {
this._mdTabNavBar.updateActiveLink(this._element.nativeElement);
}
}
constructor(private _mdTabNavBar: MdTabNavBar, private _element: ElementRef) {}
}
@somombo yes, there is a PR open in the @angular/angular repo. It's been reviewed and discussed for about a month now.
Should we mention in the docs this rlaSafe
workaround? I've spent a lot of time figuring out what I was doing wrong... There is differences between git Readme.md, material.angular.io docs and what we really should do.
Just say the words and I can update the README.md to point this issue and th rlaSafe
workaround.
@vinagreti It does not look like they want to update any of the docs to address this bug. Instead they are trying to get the bug resolved ASAP. My PR to update the docs was declined.
It looks like the PR in the core is waiting on review still.
Angular 2.4.4 fixes the error and tabs change successfully; however [active] is not being set.
Setting version to Angular 2.4.5 fixed it for me!
Ok I got [active] set correctly this way:
<nav md-tab-nav-bar>
<a md-tab-link routerLink="/admin/management" routerLinkActive #rla1="routerLinkActive" [active]="rla1.isActive">Management</a>
<a md-tab-link routerLink="/admin/profile" routerLinkActive #rla2="routerLinkActive" [active]="rla2.isActive">Profile</a>
</nav>
Thanks to all who helped fix this.
This still seems to be an open issue on Angular 4 with Angular Material 2.0.0-beta5. I could get neither the example on material io nor the fix proposed in this thread to resolve the issue. The browser console says Can't bind to 'active' since it isn't a known property of 'a'.
angular 4.4.0-RC0 and material 2.0.0-beta.10 and this issue still occurs. none of the work-arounds work. any ideas ? is there another way to add components to each selected tab besides
It's still an issue. Im using the following routes:
{
path: 'organisation/:id',
component: OrganisationComponent,
children: [
{path: '', component: OrganisationEditComponent},
{path: 'locations', component: LocationsComponent},
]
}
Then this as my component html:
<nav md-tab-nav-bar>
<a md-tab-link
[routerLink]="['./']"
routerLinkActive #rla="routerLinkActive"
[active]="rla.isActive">Algemeen</a>
<a md-tab-link
[routerLink]="['./locations']"
routerLinkActive #rlb="routerLinkActive"
[active]="rlb.isActive">Locaties</a>
</nav>
<router-outlet></router-outlet>
So now it works on the initial load, but whenever I go back to the './' route the md-tab-link active doesn't get updated.
UPDATE:
I've fixed it by add this [routerLinkActiveOptions]="{exact: true}"
to the first link, can someone explain why this is needed?
Seems like recent deprecation of md-
prefix broke the templates. For anyone still struggling with these, try using mat-
..
Same issue with latest Angular 5.1.2 and Angular Material 5.02. My hacky/flaky workaround:
ngAfterViewChecked() {
setTimeout(() => {
this.changeDetectionRef.detectChanges();
});
}
@aretheregods Same issue with latest Angular 5.2.1 and Angular Material 5.1.0;
I believe it's that [active] should be bond to mat-tab-link directive but instead it was bond to \
so any workaround would be to delay the [active] as later than mat-tab-link had bootstrapped
Edit:
it seems mat-tab-link has more problem than [active]. style looks weird too
This should be long ago fixed in Angular.
and i'm still having it
I'm having the same problem here :(
@jelbourn This is still an open issue for me on the latest version. Please consider reopening this.
I have the same problem here 👎
Having a similar issue, sadly I dont have the time to create a repro.
The method suggested by @ravishivt worked for me as workaround
If you are affected, please re-open if you can provide a reproduction of the issue, otherwise we won't be able to investigate.
Having the same error.
In my case the error was fixed by importing MatTabsModule
from @angular/material
This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.
Read more about our automatic conversation locking policy.
_This action has been performed automatically by a bot._
Most helpful comment
Ok I got [active] set correctly this way:
Thanks to all who helped fix this.