Mike Me
Mike Me

Reputation: 2392

Change dinamically attributes for Bootstrap Progress-Bar in Angular 5

I have the following code and I want to 2 things:

  1. Change the bar color depending on the output of verifyDifficulty(text1) (returns the length of the input text - mocks the difficulty of a password)

    a. if verifyDifficulty(text1)<=3 then bar color=red (progress-easy in css)
    b. if verifyDifficulty(text1)>3 && verifyDifficulty(text1)<=6 then bar color=yellow (progress-medium in css)
    c. if verifyDifficulty(text1)>6 && verifyDifficulty(text1)<=9 then bar color=light green (progress-hard in css)
    d. if verifyDifficulty(text1)==10 then bar color=dark green (progress-very-hard in css)

  2. modify aria-valuenow value to be verifyDifficulty(text1)*10 but when I try doing property binding I receive this error: Can't bind to 'aria-valuenow' since it isn't a known property of 'div'

My .ts:

import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  name = 'Angular 6';
  text1 = '';

  verifyDifficulty(text) {
    const result = text.length;
    return result;
  }
}

My .html:

<hello name="{{ name }}"></hello>
<div class="pb-1">
  <input [(ngModel)]="text1" maxlength="10" placeholder="Text">
</div>
<p>{{verifyDifficulty(text1)}}</p>
<div  *ngIf="verifyDifficulty(text1)<=3" class="progress">
  <div class="progress-bar progress-easy" role="progressbar" aria-valuenow="60" aria-valuemin="0"
    aria-valuemax="100" [style.width]="verifyDifficulty(text1)*10+'%'">
    {{verifyDifficulty(text1)*10}}
  </div>
</div>

My .css:

p {
  font-family: Lato;
}

.progress-bar.progress-easy{
  background-color: #fd0801;
}

.progress-bar.progress-medium{
  background-color: #c1b706;
}

.progress-bar.progress-hard{
  background-color: #8bdb06;
}

.progress-bar.progress-very-hard{
  background-color: #00b006;
}

A live demo of this code is here

Upvotes: 2

Views: 6422

Answers (2)

prettyfly
prettyfly

Reputation: 3130

All of your CSS can be handled using ngClass. ngClass allows you to apply styles to an element based on conditions, so you might do something like the following for your progress bar:

<div class="progress-bar progress-easy" 
     role="progressbar" 
     aria-valuenow="60" 
     aria-valuemin="0"
     aria-valuemax="100"
     [style.width]="verifyDifficulty(text1)*10+'%'"
     [ngClass]="{
        'progress-easy' : verifyDifficulty(text1)<=3,
        'progress-medium' : verifyDifficulty(text1)>3 && verifyDifficulty(text1)<=6,
        'progress-hard' : verifyDifficulty(text1)>6 && verifyDifficulty(text1)<=9,
        'progress-very-hard' :  verifyDifficulty(text1)==10
     }">
     {{verifyDifficulty(text1)*10}}
</div>

Although, to keep your template cleaner, I might apply [ngClass] with a function, rather than raw conditions in your template. e.g

<div class="progress-bar progress-easy" 
     role="progressbar" 
     aria-valuenow="60" 
     aria-valuemin="0"
     aria-valuemax="100"
     [style.width]="verifyDifficulty(text1)*10+'%'"
     [ngClass]="getStyleClass(text1)">
     {{verifyDifficulty(text1)*10}}
</div>

Where getStyleClass(text1) is a function in your component that returns the class based on input.

Now, for your aria issue, first, to apply an attribute in Angular, you use the attr binding, as already mentioned, so in your case:

[attr.aria-valuenow]="whatever"

The alternative, and perhaps better, depending on your school of thought, is to use Renderer2 to apply the aria dynamically, as such, you need to inject it in your component, and make your progress bar a ViewChild.

@ViewChild('progressBar') progressBar: ElementRef;

constructor(private renderer2: Renderer2) { }

Now your template becomes:

<div #progressBar class="progress-bar progress-easy" 
     role="progressbar" 
     aria-valuenow="60" 
     aria-valuemin="0"
     aria-valuemax="100"
     [style.width]="verifyDifficulty(text1)*10+'%'"
     [ngClass]="getStyleClass(text1)">
     {{verifyDifficulty(text1)*10}}
</div>

Note the additions of #progressBar - This marks the element as a viewchild, under that reference.

Now, when you need to change your aria value, you can do it dynamically with:

this.renderer2.setAttribute(this.progressBar.nativeElement, 'aria-valuenow', 'whatever value');

Job's a good'un! 👌🏻

Upvotes: 4

Amaan Kulshreshtha
Amaan Kulshreshtha

Reputation: 560

Try using

attr.aria-valuenow="60"

or

[attr.aria-valuenow]="60"

Upvotes: 0

Related Questions