Bind class based on knockout foreach index - html

I need to make the first item in a tab group, active. I am attempting to use the index for the foreach, and set the class based on that.
<ul class="nav nav-tabs" data-bind="foreach: TemplateGroups">
<li data-bind="css: {active: $index==0}"><a data-toggle="tab" href="#tb1"><span data-bind="text: Description"></span></a></li>
</ul>
However, the item isn't becoming active. What am I missing?

From Binding context
$index is an observable and is updated whenever the index of the item changes
And an observable is a function.
Then, you are comparing a function with a number, and always is false.
You should use active: $index() == 0 or $index() === 0.
Example: Codepen

Related

Laravel - Add class to any nav-link if its generated url matches the current route

I'm working with Bootsrtap 4 and I'm trying to add the class active to my nav-item elements whenever their nav-link href attribute is the same as the current url.
On the html side, I uesd a basic url generator as shown below:
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" href="{{ url('/brands') }}" role="button">Brands</a>
</li>
<!-- ... -->
</ul>
And then I used a jQuery method to compare them with the current url:
$('.navbar-nav .nav-item .nav-link').each( () => {
// If the current path and the link url are the same...
if ($(this).attr('href').indexOf(location.pathname) !== 1) {
// ...then add the class 'active' to 'nav-item', its parent
$(this).parent().addClass('active')
}
})
However, I noticed that $(this).attr('href') was undefined, probably because it's a generated url, and therefore nav-item doesn't get the active class.
EDIT: as an example, for now it's a very basic url, without parameter, which looks like this:
http://domain.example/brands
Does anyone know how to solve this problem? Thanks in advance.
I'd recommend you to go another way. Instead of "activating" the link with jQuery, you could easily do it server-side with Laravel:
<ul class="navbar-nav">
<li class="nav-item">
<a class="{{ Request::is('brands*') ? 'nav-link active' : 'nav-link' }}"
href="{{ url('/brands') }}"
role="button">Brands</a>
</li>
<!-- ... -->
</ul>
Explanation:
Laravel uses the template-engine twig for rendering the HTML server-side. Instead of manipulation the DOM client-side, you can easily add an conditional to check for the current request parameters. Laravel gives you nativeliy the possibility to check the request path even with a wildcard.
Your problem is most likely caused by the difference between using () => {} or function () {}
When you use the arrow syntax the prop this is unbound. Meaning that also $(this) will return an empty jQuery object instead of returning the anchor. Any follow up jQuery chaining will return something empty/undefined.
So, changing .each( () => { to .each(function() { will at least fix your undefined problem.
Information about the arrow syntax: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
Okay this is what i do generally do in all my laravel projects when it comes to make sidebar or any link "active" on click :-
<li class="nav-item {{ in_array(Route::currentRouteName(),[
'admin.dashboard',
'admin.updates',
])? 'active show' : ''}}">
<i class="typcn typcn-clipboard"></i>Dashboard
<nav class="nav-sub">
Home
</nav>
</li>
Now notice this {{ BladeHelper::sideBar_link_isActive('admin.dashboard') }}
I created dynamic helper function to get the current url and return "active" class
Path : app\Helpers\BladePageHelper
<?php
namespace App\Helpers;
use Route;
class BladePageHelper
{
public static function sideBar_link_isActive($selectedLink){
$currentRouteName = Route::currentRouteName();
if($selectedLink === $currentRouteName){
return 'active';
}else{
return '';
}
}
}
I'm using route name here like
Route::("/","MyController#mymethod")->name("myname")
You can do this with url too.
I hope this helps.
Happy Coding

How to change active list item in typescript

I have some list items which are treated as Tabs in my UI. I also have a 'next' button under every tab and last tab have a 'finish' button. I need to move to next tab when i clicked on 'Next' button. I am working on an Angular2 project with typescript version 2.3.4. So i need some typescript code to work on button click.
While searching, i got some jquery code like,
$('.nav-tabs > .active').next('li').find('a') from how to display next bootstrap tab on button click.
I tried it in my button click(.ts file) and it works!. But i am not sure about the using of jquery in my project. Is it possible to get the element(html) in its typescript file? Or is this is the good possible way to do this?
My list is like,
<div class="row">
<ul class="nav nav-tabs bg-white">
<li class="active"><a data-toggle="tab" href="#BasicInfo">BasicInfo</a></li>
<li id="idAddInfoTab"><a data-toggle="tab" href="#AdditionalInfo">AdditionalInfo</a></li>
<li id="idPlayerIdentity" class="active-border"><a data-toggle="tab" href="#PlayerIdentity">PlayerIdentity</a></li>
</ul>
</div>
Thanks in advance!
I would do something like this
page.ts
//declare 3 variables
isT1Active:boolean = true;
isT2Active:boolean = false;
isT3Active:boolean = false;
...
activate(elem){
//deactivate all first
this.isT1Active = false;
this.isT2Active = false;
this.isT3Active = false;
switch(elem){
case 't1':{this.isT1Active = true;break;}
case 't2':{this.isT2Active = true;break;}
case 't3':{this.isT3Active = true;break;}
}
}
page.html
<div class="row">
<ul class="nav nav-tabs bg-white">
<li [ngClass]="{'active': isT1Active}" (click)="activate("t1")"><a data-toggle="tab" href="#BasicInfo">BasicInfo</a></li>
<li [ngClass]="{'active': isT2Active}" (click)="activate("t2")" id="idAddInfoTab"><a data-toggle="tab" href="#AdditionalInfo">AdditionalInfo</a></li>
<li [ngClass]="{'active': isT3Active}" (click)="activate("t3")" id="idPlayerIdentity" class="active-border"><a data-toggle="tab" href="#PlayerIdentity">PlayerIdentity</a></li>
</ul>
</div>
And you can do same thing to the next button, In assume that each tab will have a next button
I would stay away from jQuery, but instead learn how to better use Angular to control the view. Basically, you want the active class in your template tab to be bound to your component selected model, so that when the selected model is updated, Angular will automatically apply the active class to the matching tab.
In your component, define the array that stores the tab info and define a selectedTab that refers to the specific tab that should be active:
export class AppComponent {
tabs = [
{id:'idBasicInfo', href:'...',label:'BasicInfo'},
{id:'idAddInfo', href:'...',label:'AdditionalInfo'},
{id:'idPlayerIdentity',href:'...',label:'PlayerIdentity'}
];
selectedTab = this.tabs[0]; // which is active by default
}
Then in your template, use these properties to drive the view:
<ul>
<li *ngFor="let t of tabs" [id]="t.id" [class.active]="t===selectedTab">
<a data-toggle="tab" [href]="t.href" (click)="selectedTab=t"> {t.label}} </a>
</li>
</ul>
When a tab is clicked, it will be made the selectedTab and its active class will be set.

Angular [attr.href] condition with ng-click

I have an Angular5 application with a bootstrap tab control. I set the href of a tab to # if the property modelChanged is true, otherwise I set it to #tab1 (or #tab2):
<ul class="nav nav-tabs">
<li class="active">
<a (click)="changeTab()" [attr.href]="modelChanged ? '#':'#tab1'" data-toggle="tab">Tab 1</a>
</li>
<li>
<a (click)="changeTab()" [attr.href]="modelChanged ? '#':'#tab2'" data-toggle="tab">Tab 2</a>
</li>
</ul>
So basically I am able to change the tab if modelChanged is set to false, othwerise not.
Now I wan't to use a function called changeTab() where I change the modelChanged property to false and would expect that the tab change from 1 to 2 but it doesn't until I click the tab again:
changeTab() {
modelChanged = false;
}
Anyone knows a solution for that?
Sorry that I don't have a working plunker but I think some of you will be able to answer my question anyway.
2 ways to do the same
1) in your click specify modelChanged = !modelChanged,
[click]="modelChanged = !modelChanged"
2) [click]="modelChanged = changeTab()"
and in your controller specify the changeTab function like this
function changeTab(){
//do something
return false;
}

Appending additional classes to HTML elements based on condition in Angular [duplicate]

What is wrong with my Angular code? I am getting the following error:
Cannot read property 'remove' of undefined at BrowserDomAdapter.removeClass
<ol>
<li *ngClass="{active: step==='step1'}" (click)="step='step1'">Step1</li>
<li *ngClass="{active: step==='step2'}" (click)="step='step2'">Step2</li>
<li *ngClass="{active: step==='step3'}" (click)="step='step3'">Step3</li>
</ol>
Angular version 2+ provides several ways to add classes conditionally:
type one
[class.my_class] = "step === 'step1'"
type two
[ngClass]="{'my_class': step === 'step1'}"
and multiple option:
[ngClass]="{'my_class': step === 'step1', 'my_class2' : step === 'step2' }"
type three
[ngClass]="{1 : 'my_class1', 2 : 'my_class2', 3 : 'my_class4'}[step]"
type four
[ngClass]="step == 'step1' ? 'my_class1' : 'my_class2'"
You can find these examples on the documentation page
[ngClass]=... instead of *ngClass.
* is only for the shorthand syntax for structural directives where you can for example use
<div *ngFor="let item of items">{{item}}</div>
instead of the longer equivalent version
<template ngFor let-item [ngForOf]="items">
<div>{{item}}</div>
</template>
See also https://angular.io/docs/ts/latest/api/common/index/NgClass-directive.html
<some-element [ngClass]="'first second'">...</some-element>
<some-element [ngClass]="['first', 'second']">...</some-element>
<some-element [ngClass]="{'first': true, 'second': true, 'third': false}">...</some-element>
<some-element [ngClass]="stringExp|arrayExp|objExp">...</some-element>
<some-element [ngClass]="{'class1 class2 class3' : true}">...</some-element>
See also https://angular.io/docs/ts/latest/guide/template-syntax.html
<!-- toggle the "special" class on/off with a property -->
<div [class.special]="isSpecial">The class binding is special</div>
<!-- binding to `class.special` trumps the class attribute -->
<div class="special"
[class.special]="!isSpecial">This one is not so special</div>
<!-- reset/override all class names with a binding -->
<div class="bad curly special"
[class]="badCurly">Bad curly</div>
Another solution would be using [class.active].
Example :
<ol class="breadcrumb">
<li [class.active]="step=='step1'" (click)="step='step1'">Step1</li>
</ol>
That's the normal structure for ngClass is:
[ngClass]="{'classname' : condition}"
So in your case, just use it like this...
<ol class="breadcrumb">
<li [ngClass]="{'active': step==='step1'}" (click)="step='step1'">Step1</li>
<li [ngClass]="{'active': step==='step2'}" (click)="step='step2'">Step2</li>
<li [ngClass]="{'active': step==='step3'}" (click)="step='step3'">Step3</li>
</ol>
with the following examples you can use 'IF ELSE'
<p class="{{condition ? 'checkedClass' : 'uncheckedClass'}}">
<p [ngClass]="condition ? 'checkedClass' : 'uncheckedClass'">
<p [ngClass]="[condition ? 'checkedClass' : 'uncheckedClass']">
You can use ngClass to apply the class name both conditionally and not in Angular
For Example
[ngClass]="'someClass'">
Conditional
[ngClass]="{'someClass': property1.isValid}">
Multiple Condition
[ngClass]="{'someClass': property1.isValid && property2.isValid}">
Method expression
[ngClass]="getSomeClass()"
This method will inside of your component
getSomeClass(){
const isValid=this.property1 && this.property2;
return {someClass1:isValid , someClass2:isValid};
}
Angular provides multiple ways to add classes conditionally:
First way
active is your class name
[class.active]="step === 'step1'"
Second way
active is your class name
[ngClass]="{'active': step=='step1'}"
Third way
by using ternary operator class1 and class2 is your class name
[ngClass]="(step=='step1')?'class1':'class2'"
You should use something ([ngClass] instead of *ngClass) like that:
<ol class="breadcrumb">
<li [ngClass]="{active: step==='step1'}" (click)="step='step1; '">Step1</li>
(...)
In Angular 7.X
The CSS classes are updated as follows, depending on the type of the expression evaluation:
string - the CSS classes listed in the string (space delimited) are added
Array - the CSS classes declared as Array elements are added
Object - keys are CSS classes that get added when the expression given in the value evaluates to a truthy value, otherwise they are removed.
<some-element [ngClass]="'first second'">...</some-element>
<some-element [ngClass]="['first', 'second']">...</some-element>
<some-element [ngClass]="{'first': true, 'second': true, 'third': false}">...</some-element>
<some-element [ngClass]="stringExp|arrayExp|objExp">...</some-element>
<some-element [ngClass]="{'class1 class2 class3' : true}">...</some-element>
Additionally, you can add with method function:
In HTML
<div [ngClass]="setClasses()">...</div>
In component.ts
// Set Dynamic Classes
setClasses() {
let classes = {
constantClass: true,
'conditional-class': this.item.id === 1
}
return classes;
}
to extend MostafaMashayekhi his answer for option two>
you can also chain multiple options with a ','
[ngClass]="{'my-class': step=='step1', 'my-class2':step=='step2' }"
Also *ngIf can be used in some of these situations usually combined with a *ngFor
class="mats p" *ngIf="mat=='painted'"
You can use [ngClass] or [class.classname], both will work the same.
[class.my-class]="step==='step1'"
OR
[ngClass]="{'my-class': step=='step1'}"
Both will work the same!
While I was creating a reactive form, I had to assign 2 types of class on the button. This is how I did it:
<button type="submit" class="btn" [ngClass]="(formGroup.valid)?'btn-info':''"
[disabled]="!formGroup.valid">Sign in</button>
When the form is valid, button has btn and btn-class (from bootstrap), otherwise just btn class.
We can make class dynamic by using following syntax. In Angular 2 plus, you can do this in various ways:
[ngClass]="{'active': arrayData.length && arrayData[0]?.booleanProperty}"
[ngClass]="{'active': step}"
[ngClass]="step== 'step1'?'active':''"
[ngClass]="step? 'active' : ''"
Let, YourCondition is your condition or a boolean property, then do like this
[class.yourClass]="YourCondition"
The directive operates in three different ways, depending on which of three types the expression evaluates to:
If the expression evaluates to a string, the string should be one or more space-delimited class names.
If the expression evaluates to an object, then for each key-value pair of the object with a truthy value the corresponding key is used as a class name.
If the expression evaluates to an array, each element of the array should either be a string as in type 1 or an object as in type 2. This means that you can mix strings and objects together in an array to give you more control over what CSS classes appear. See the code below for an example of this.
[class.class_one] = "step === 'step1'"
[ngClass]="{'class_one': step === 'step1'}"
For multiple options:
[ngClass]="{'class_one': step === 'step1', 'class_two' : step === 'step2' }"
[ngClass]="{1 : 'class_one', 2 : 'class_two', 3 : 'class_three'}[step]"
[ngClass]="step == 'step1' ? 'class_one' : 'class_two'"
ngClass syntax:
[ngClass]="{'classname' : conditionFlag}"
You can use like this:
<ol class="breadcrumb">
<li [ngClass]="{'active': step==='step1'}" (click)="step='step1'">Step1</li>
<li [ngClass]="{'active': step==='step2'}" (click)="step='step2'">Step2</li>
<li [ngClass]="{'active': step==='step3'}" (click)="step='step3'">Step3</li>
</ol>
This is what worked for me:
[ngClass]="{'active': dashboardComponent.selected_menu == 'profile'}"
For elseif statement (less comparison) use like that: (For example you compare three statement)
<div [ngClass]="step === 'step1' ? 'class1' : (step === 'step2' ? 'class2' : 'class3')"> {{step}} </div>
Not relevant with [ngClass] directive but I was also getting the same error as
Cannot read property 'remove' of undefined at...
and I thought to be the error in my [ngClass] condition but it turned out the property I was trying to access in the condition of [ngClass] was not initialized.
Like I had this in my typescript file
element: {type: string};
and In my [ngClass] I was using
[ngClass]="{'active', element.type === 'active'}"
and I was getting the error
Cannot read property 'type' of undefined at...
and the solution was to fix my property to
element: {type: string} = {type: 'active'};
Hope it helps somebody who is trying to match a condition of a property in [ngClass]
<div class="collapse in " [ngClass]="(active_tab=='assignservice' || active_tab=='manage')?'show':''" id="collapseExampleOrganization" aria-expanded="true" style="">
<ul> <li class="nav-item" [ngClass]="{'active': active_tab=='manage'}">
<a routerLink="/main/organization/manage" (click)="activemenu('manage')"> <i class="la la-building-o"></i>
<p>Manage</p></a></li>
<li class="nav-item" [ngClass]="{'active': active_tab=='assignservice'}"><a routerLink="/main/organization/assignservice" (click)="activemenu('assignservice')"><i class="la la-user"></i><p>Add organization</p></a></li>
</ul></div>
Code is good example of ngClass if else condition.
[ngClass]="(active_tab=='assignservice' || active_tab=='manage')?'show':''"
[ngClass]="{'active': active_tab=='assignservice'}"
Try Like this..
Define your class with ''
<ol class="breadcrumb">
<li *ngClass="{'active': step==='step1'}" (click)="step='step1; '">Step1</li>
<li *ngClass="{'active': step==='step2'}" (click)="step='step2'">Step2</li>
<li *ngClass="{'active': step==='step3'}" (click)="step='step3'">Step3</li>
</ol>
The example is a bit big, but triggering a class instead of typing inline is my first preferred approach.
this way you can add as many possibilities as you want to your element.
There may be a way for those who want to bind more than one [ngClass] to a single element.
<span class="inline-flex items-center font-medium" [ngClass]="addClass">{{ badge.text }}</span>
import { ChangeDetectionStrategy, Component, Input } from '#angular/core';
type Badge = {
size?: 'basic' | 'large';
shape?: 'basic' | 'rounded';
color?: 'gray' | 'red' | 'yellow' | 'green' | 'blue' | 'indigo' | 'purple' | 'pink';
dot?: boolean;
removeButton?: false;
text?: string;
}
#Component({
selector: 'bio-badge',
templateUrl: './badge.component.html',
styleUrls: ['./badge.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class BioBadgeComponent {
#Input() badge!: Badge;
get addClass() {
return {
'px-2.5 py-0.5 text-sx': this.badge.size === 'basic',
'px-3 py-0.5 text-sm': this.badge.size === 'large',
'rounded-full': this.badge.shape === 'basic',
'rounded': this.badge.shape === 'rounded',
'bg-gray-100 text-gray-800': this.badge.color === 'gray',
'bg-red-100 text-red-800': this.badge.color === 'red',
'bg-yellow-100 text-yellow-800': this.badge.color === 'yellow',
'bg-green-100 text-green-800': this.badge.color === 'green',
'bg-blue-100 text-blue-800': this.badge.color === 'blue',
'bg-indigo-100 text-indigo-800': this.badge.color === 'indigo',
'bg-purple-100 text-purple-800': this.badge.color === 'purple',
'bg-pink-100 text-pink-800': this.badge.color === 'pink',
}
}
}
If user want to display the class on basis of && and ||
then below one is work for me
[ngClass]="{'clasname_1': condition_1 && condition_2, 'classname_2': condition_1 && condition2, 'classname_3': condition}"
Example:
[ngClass]="{'approval-panel-mat-drawer-side-left': similar_toil_mode==='side' && showsTheSimilarToilsWithCloseIcon, 'approval-panel-mat-drawer-side-right': similar_toil_mode==='side' && !showsTheSimilarToilsWithCloseIcon, 'approval-panel-mat-drawer-over': similar_toil_mode==='over'}"

Avoid writing multiple variable values in Angular 2 when changing class of clicked items

I hope this is a good question and I am not just missing something total simple. I am very new to Angular 2 and I am always into saving code lines and time :)
I want to change the active css class of my tabs (I dont want to use router!) and I ended up with something like this:
activeTab: string;
switchActiveTab(newTab: string) {
this.activeTab = newTab;
}
<div class="buttonLine">
<ul class="nav nav-pills">
<li role="presentation" [ngClass]="{'active': activeTab === 'Example Tab 1'}" (click)="switchActiveTab('Example Tab 1');">
<a>Example Tab 1</a>
</li>
<li role="presentation" [ngClass]="{'active': activeTab === 'Example Tab 2'}" (click)="switchActiveTab('Example Tab 2');">
<a>Example Tab 2</a>
</li>
</ul>
</div>
So I had to declare the string value "Example Tab 1" three times in my HTML. This is pretty annoying, especially when I would have 5 or more tabs here.
Is it possible to avoid reapeating the expression "Example Tab 1" three times in my HTML? Or is it possible to do this kind of stuff in a more elegant way?
Method 1
To simplify the template code, you can declare the list of tabs in the component class:
public tabList: Array<string> = ["Example Tab 1", "Example Tab 2"];
and generate the li elements with the *ngFor directive:
<li *ngFor="let tab of tabList" [ngClass]="{'active': activeTab === tab}" (click)="switchActiveTab(tab);" role="presentation">
<a>{{tab}}</a>
</li>
Method 2
To keep the code more declarative, each item could refer to itself with a template reference variable instead of using the tab caption (as illustrated in this plunker):
<div class="buttonLine">
<ul class="nav nav-pills">
<li #tab1 [ngClass]="{'active': activeTab === tab1}" (click)="switchActiveTab(tab1);" role="presentation">
<a>Example Tab 1</a>
</li>
<li #tab2 [ngClass]="{'active': activeTab === tab2}" (click)="switchActiveTab(tab2);" role="presentation">
<a>Example Tab 2</a>
</li>
</ul>
</div>
The code would be modified accordingly:
activeTab: HTMLElement;
switchActiveTab(newTab: HTMLElement) {
this.activeTab = newTab;
}