Angular: condition within ngClass attribute always treated as true - css

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.

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';
});
}
}

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();

Mark required field's label based on assigned validator in Angular 2 form

I have an Angular 2 form with lots of required fields. Those have Validators.required assigned. I want to add an asterisk to these fields' labels.
<form [formGroup]="form">
<div class="form-group row">
<label class="col-sm-3 col-form-label">First Name -> Add asterisk here</label>
<div class="col-sm-9">
<input formControlName="firstName" type="text" class="form-control">
</div>
</div>
...
I have googled and read the docs, but can't find an implementation for this use case.
I know I can add the required attribute manually and work from there, but I would prefer to avoid as this seems redundant with the validator assignment.
Not sure, if its the best ng2-style solution, but what about this:
Let your FormComponent hold an array of required fields. In your template you can simply use something like:
<label for="firstName">
FirstName <span *ngIf="isFieldRequired('firstName')"> *</span>
</label>
You can create separate component for Label with asterisk, if you don't want to repeat the code through your template, for example:
#Component({
selector: 'my-label',
template: `<label for="{{id}}">{{label}} <span *ngIf="isFieldRequired(id)"> *</span></label>`
})
export class MyLabelComponent {
#Input() label: string;
#Input() id: string;
#Input() requires: [];
constructor() { }
isFieldRequired(id) {
return this.requires.indexOf(id) !== -1; // check if the array contains the value
}
}
In your Form Component, you just pass values to the my-label component, like:
<my-label [requires]="requiredFields" [label]="'Name'" [id]="'name'"></my-label>
Here is working plunker of this example: http://plnkr.co/edit/M66IFQGhhe82mNt3ekxw?p=preview
with the idea how to use the required definition together with more custom validators. See app.component.ts

Angular 2 + Semantic UI , component encapsulation breaks style

I'm using Angular2 with Semantic UI as a css library. I have this piece of code:
<div class="ui three stakable cards">
<a class="ui card"> ... </a>
<a class="ui card"> ... </a>
<a class="ui card"> ... </a>
</div>
the cards are rendered nicely with a space between and such.
like this: refer to cards section in the link
since the cards represent some kind of view I thought of making a component out of it, so now the code is:
<div class="ui three stakable cards">
<my-card-component></my-card-component>
<my-card-component></my-card-component>
<my-card-component></my-card-component>
</div>
but now the style is broken, there is no space between them anymore.
Is there any nice way of fixing this ?
the first thing I thought of doing is this:
my-card-component OLD template:
<a class="ui card">
[some junk]
</a>
|||
VVV
my-card-component NEW template:
[some junk]
and instantiating like:
<my-card-component class="ui card"></my-card-component>
or like:
<a href="?" my-card-component></a>
but this is not satisfactory since I want to be able to pass in an object and the component would automatically set the [href]=obj.link.
in AngularJS 1.0 there was a replace: true property which does excatly what i need, is there a similar thing in Angular2 ?
There is no replace=true in Angular2. It is considered a bad solution and deprecated in Angular 1.x as well.
See also Why is replace deprecated in AngularJS?
Use an attribute-selector instead of a tag-selector in your component or directive.
Just change
#Directive({ ..., selector: "my-card-component"})
to
#Directive({ ..., selector: "a[my-card-component]"})
and use it like
<a my-card-component class="ui card"> ... </a>
You might also adjust the encapsulation strategy http://blog.thoughtram.io/angular/2015/06/29/shadow-dom-strategies-in-angular2.html but I think the default emulated should be fine in your case.
Solved it using #GünterZöchbauer Answer together with #HostBinding('href')
so now the code is:
template:
---------
[some junk]
component:
----------
#Component({
selector: 'a[my-card-component].ui.card',
templateUrl: 'urlOfSomeJunk.html',
directives: []
})
export class ProblemCardComponent {
#Input()
obj: MyObject;
#HostBinding('attr.href') get link { return this.obj.link; }
}
instantiating:
--------------
<a class="ui card" my-card-component [obj]="someBindingHere"></a>
that way the href is automatically bound to obj.link and I can rest in piece.

Angular2 Bind Attribute Value

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>

Resources