Angular2 Bind Attribute Value - data-binding

Similar to Angular2 two-way data binding, I have a parent and a child component. In the parent I change the value that is passed to the child component via property. The property of the child is named percentage.
https://gist.github.com/ideadapt/59c96d01bacbf3222096
I want to bind the property value to a html attribute value. Like: <div style="width: {{percentage}}%">. I didn't find any syntax that worked. So I ended up using a change listener that does some manual DOM update:
this.progressElement = DOM.querySelector(element.nativeElement, '.progress');
DOM.setAttribute(this.progressElement, "style", `width: ${this.percentage}%`);
Is there a more elegant way to accomplish this?

You can use percentage binding for CSS properties: [style.width.%]
import {Component, Input} from 'angular2/core';
#Component({
selector: 'progress-bar',
template: `
<div class="progress-bar">
<div [style.width.%]="value"> {{ value }}% </div>
</div>
`,
})
export class ProgressBar {
#Input() private value: number;
}

Use NgStyle, which works similar to Angular 1. Since alpha-30, NgStyle is available in angular2/directives:
import {NgStyle} from 'angular2/directives';
Then include NgStyle in the directives list, this should work (here are some examples):
#View({
directives: [NgStyle]
template: `
<div class="all">
<div class="progress" [ng-style]="{'width': percentage + '%'}"></div>
<span class="label">{{percentage}}</span>
</div>
`
})
Alternatively and without using NgStyle, this would work well too:
<div class="progress" [style.width]="percentage + '%'"></div>

Related

Angular9 get parent node on element added with ng-container and ngIf

I am trying to get the parent element when a ng-template is added with ngIf.
Layout:
<section>
<h2>
Hello!
<ng-container *ngIf="someCondition1; then myTemplate"></ng-container>
</h2>
<div>
Another one!
<ng-container *ngIf="someCondition2; then myTemplate"></ng-container>
</div>
<!-- More markup here that show myTemplate based on conditions -->
</section>
<ng-template #myTemplate>
<img src="path/to/image.png" />
</ng-template>
The above works fine but I want to grab the parent element of wherever it's added and apply some styles to the parent in the typescript file. Can I use one of the lifecycle functions or select the parent another way whenever the template is added to the DOM?
I figured it out. I had to add a template tag on the image and then grab it with ViewChildren of type QueryList. This gave me access to the native element of each one where I could grab the parent node. This has to to be done in the AfterViewInit lifecycle hook.
HTML:
<section>
<h2>
Hello!
<ng-container *ngIf="someCondition1; then myTemplate"></ng-container>
</h2>
<!-- More markup here that show myTemplate based on conditions -->
</section>
<ng-template #myTemplate>
<img #myTemplateImage src="path/to/image.png" />
</ng-template>
Typescript:
import { Component, ViewChildren, ElementRef, QueryList, AfterViewInit } from '#angular/core';
#Component({
selector: 'test-selector',
templateUrl: './test.component.html'
})
export class TestComponent implements AfterViewInit {
#ViewChildren('myTemplateImage') imageList: QueryList<ElementRef>;
ngAfterViewInit() {
this.imageList.forEach((item) => {
item.nativeElement.parentNode.style.fontStyle = 'italic';
});
}
}

Angular HTML class.otherclass explanation

I have seen this HTML line in an Angular project:
<div id="player" class="player" [class.voted]="booleanvar">
The CSS contains a defintion of .player.voted
I'm not really sure what this part means: [class.voted]="booleanvar"
This is one way of dynamically applying a class to an HTML element in Angular.
If booleanvar equates to true then the css class voted will be applied, so long as its defined correctly in CSS file. If it equates to false, then the class will not be applied.
<div id="player" class="player" [class.voted]="booleanvar">
I hope you help it
[class.voted]="booleanvar" this means the element add a class "voted" when "booleanvar" poperty or a variable value is true.
import { Component } from '#angular/core';
#Component({
selector: 'app-root',
template:`
<div id="player" class="player" [class.voted]="booleanvar">
`
})
export class AppComponent {
booleanvar:boolean = true;
}
when booleanvar = false then the render element like '<div id="player" class="player">'
Otherwise it's render <div id="player" class="player voted">

Angular: condition within ngClass attribute always treated as true

I'm trying to set the CSS class within 'EditDialogComponent' below (which is a modal view), depending on an input property called 'showMe' that is set from 'AppComponent':
HTML Code:
<div [ngClass]="showMe? 'ui active modal': 'ui modal'">
<i class="close icon"></i>
<div class="header">
Edit
</div>
<div class="actions">
<div class="ui black deny button">
Cancel
</div>
<div (click)="clk()" class="ui positive right labeled icon button">
OK
<i class="checkmark icon"></i>
</div>
</div>
</div>
TypeScript Code:
import { Component, Input, Output, OnInit } from '#angular/core';
#Component({
selector: 'edit-dialog',
templateUrl: './edit-dialog.component.html',
styleUrls: ['./edit-dialog.component.css']
})
export class EditDialogComponent implements OnInit {
#Input() subject: string
#Input() showMe: boolean
constructor() { }
clk() {
window.alert(this.showMe)
}
ngOnInit() {
}
}
This is the HTML code used to include 'EditDialogComponent' into 'AppComponent':
<edit-dialog showMe="{{show_edit_modal}}" subject='foobar'></edit-dialog>
The problem is that whenever I click on the 'OK' button of the modal, I get always the correct boolean value corresponding to show_edit_modal variable of AppComponent. Yet after testing, I found that ngClass keeps always treating the input value showMe as true.
Why ngClass is always treating the input property as true?
Your showMe input is not being properly bound to show_edit_modal.
Instead of:
<edit-dialog showMe="{{show_edit_modal}}" subject='foobar'></edit-dialog>
You should have:
<edit-dialog [showMe]="show_edit_modal" subject='foobar'></edit-dialog>
This will cause showMe to be set (and updated) by the parent's show_edit_modal.
Generally speaking, you should never need to use interpolation ({{ }}) inside any html tags. There is usually a different, more proper way of expressing what you need with Angular.

Angular 'filter' style binding not work

There is an example
#Component({
selector: 'my-app',
template: `
<div>
<h2 style="background-color:green">
No Filter
</h2>
</div>
<div style="filter:brightness(0.5)">
<h2 style="background-color:green">
Filter with style.
</h2>
</div>
<div [style.filter]="'brightness(' + val + ')'">
<h2 style="background-color:green">
Filter with style binding.
</h2>
</div>
<p>filter binding express value: {{'brightness(' + val + ')'}}</p>
`,
})
export class App {
val = 0.5;
}
https://plnkr.co/edit/gD9xkX5aWrdNDyD6fnIh?p=preview
got the rendered result:
Seem like style binding [style.filter] not work. Anyone know the reason or give another way to control filter brightness style by component member value?
Thanks for any answer!
When we apply the filter style like this:
<div [style.filter]="'brightness(' + val + ')'">
the following message appears in the console:
WARNING: sanitizing unsafe style value brightness(0.5)
The style expression brightness(0.5) is considered unsafe by Angular. We can mark it as safe by calling DomSanitizer.bypassSecurityTrustStyle in a method of the component class or with the help of a custom pipe defined as:
import { Pipe } from "#angular/core";
import { DomSanitizer } from "#angular/platform-browser";
#Pipe({name: 'safe'})
export class SafePipe {
constructor(private sanitizer: DomSanitizer){
}
transform(style) {
return this.sanitizer.bypassSecurityTrustStyle(style);
}
}
which can be applied like this in the template:
<div [style.filter]="'brightness(' + val + ')' | safe">
An alternative, which does not involve sanitization problems, is to use the ngStyle directive:
<div [ngStyle]="{'filter': 'brightness(' + val + ')'}">
Both techniques are shown in this stackblitz.
The problem of unsafe style expressions has been discussed in other posts:
https://stackoverflow.com/a/38663363/1009922
https://stackoverflow.com/a/37267875/1009922

How to open and hide ng-bootstrap datepicker on custom actions?

Currently I am using:
ng-bootstrap 1.0.0-alpha.24
angular/core 4.0.0
bootstrap 4.0.0-alpha.6
I wanted to ask if someone knows how to autoclose the datepicker
when the focus is lost or another datepicker is opened.
Also i wanted to now if it is possible to close the datepicker in the component code with typescript.
It would be nice if someone could provide a working plunker or a code snippet.
My actual implementation:
<div class="input-group">
<input class="rect-border full-width"
placeholder="YYMMDD"
[(ngModel)]="selectedDate"
ngbDatepicker
#datePickerInput="ngbDatepicker"
(keydown.arrowup)="incrementDate()"
(keydown.arrowdown)="decrementDate()"
(ngModelChange)="validate('modelChanged')"
(blur)="validate(null)"
[disabled]="disabled"
[ngClass]="{'input-required': required, 'normal-color': valid, 'picker-disabled': disabled}">
<div class="input-group-addon rect-border"
(click)="disabled ? true : datePickerInput.toggle()"
[ngClass]="{'picker-button-disabled': disabled}">
<img src="assets/img/calendar-icon.svg" class="datpickerToggle"/>
</div>
</div>
Plunker: ng-bootstrap team demo
I have searched a long time and I am also pretty new to angular and these things.
Thank you for your help!
Update:
Possible solution:
There were a lot of good solutions provided.
I also found out by myself that I could use the class NgbInputDatepicker
to close the datePicker (I always used NgbDatepicker, so it didn't work).
#ViewChild('datePickerInput') datePicker: NgbInputDatepicker;
this.datePicker.close();
you can open and close your datepicker from your html itself
for eg:
<div class="input-group">
<input class="rect-border full-width"
placeholder="YYMMDD"
[(ngModel)]="selectedDate"
ngbDatepicker
#datePickerInput="ngbDatepicker"
(keydown.arrowup)="incrementDate()"
(keydown.arrowdown)="decrementDate()"
(ngModelChange)="validate('modelChanged')"
(blur)="validate(null)"
[disabled]="disabled"
[ngClass]="{'input-required': required, 'normal-color': valid, 'picker-disabled': disabled}">
<div class="input-group-addon rect-border"
(click)="disabled ? true : datePickerInput.toggle()"
[ngClass]="{'picker-button-disabled': disabled}">
<img src="assets/img/calendar-icon.svg" class="datpickerToggle"/>
</div>
</div>
<div (click)="datePickerInput.open()"></div>
<span (click)="datePickerInput.close()"></span>
and also there are many functions which you can use in your html. some are close(), isOpen(), manualDateChange(), open(), toggle(), validate() etc. You can refer it in this plunkr http://plnkr.co/edit/G1b6fFrtVZwEz4lsou8n?p=preview
In typescript you can simply define a variable datepickerVisibility and then in your template use *ngIf to show or hide your datepicker component. Here is a demo code:
Template: <datepicker *ngIf="datepickerVisibility" [ngModel]="date"> </datepicker>
Component: private datepickerVisibility: boolean = false;
// Show the datepicker
showDatepicker() {
this.datepickerVisibility = true;
}
Edit:
Therefore you could use jQuery. Add the jQuery js into your index.html and in your typescript component use jQuery as follows:
declare let jQuery: any;
#Component({
moduleId: module.id,
selector: 'test',
templateUrl: 'template.html',
styleUrls: ['test.css'],
})
export class TestComponent {
constructor() {}
public toggleDatepicker() {
jQuery("#datepicker01").toggle();
}
}
And in your template file just add the id datepicker01 to your datepicker div
<div id="datepicker01" ...>
I was looking for a solution to this issue, but in a scenario where the datepicker is wrapped in a custom component and has to expose a function a parent component can call to toggle the datepicker. The answers provided are great and will work for most use case, but not mine, as I didn't want to add a jQuery dependency and calling toggle from the HTML isn't an option.
Here's how I solved it.
I added a ViewChild reference to the datepicker input in the *.component.ts file
#ViewChild('d', {static: true}) d;
that matches the datepicker identifier in the HTML file
<input (dateSelect)="dateSelected($event)" class="form-control" (focus)='d.toggle()' placeholder="yyyy-mm-dd" name="d"
[ngModelOptions]="{standalone: true}" [(ngModel)]="date" ngbDatepicker #d="ngbDatepicker">
and called the toggle function within a method exposed by the component
toggle() {
this.d.toggle();
}
That way, another component can call the toggle() function exposed by this component to toggle the datepicker like so:
In HTML
<app-custom-datepicker #date></app-custom-date-picker>
In .ts file
#ViewChild('date', {static: true}) date;
.
.
.
this.date.toggle();

Resources