how change style value of previous element - html

i have elements and when click down with the mouse the color of text changing from black to red
my problem is that i want when i click an another element so this elemnt changing to red and the previous element return to be black
#Directive({
selector: '[appSelect]'
})
export class SelectDirective implements OnInit {
constructor(private elRef: ElementRef, private renderer: Renderer2) {
}
ngOnInit() {
}
#HostListener('mousedown') onmousedown() {
if (this.elRef.nativeElement.style.color !== 'red') {
this.renderer.setStyle(this.elRef.nativeElement, 'color', 'red');
} else {
this.renderer.setStyle(this.elRef.nativeElement, 'color', 'black');
}

Using a directive to change style is using a sledgehammer to crack a nut. But you can do adding a Output to your directive.
In general -without directive- we can do some like
<div *ngFor="let item of [0,1,2,3,4];let i=index"
[style.color]="selectedIndex==i?'red':'black'"
(click)="selectedIndex=i" >
click me
</div>
when we has defined a variable like
selectedIndex:number=-1;
If you want use a directive we can do some similar. We defined a variable like
control:any={}
And we write some like
<div *ngFor="let item of [0,1,2,3,4]"
[appSelect]="control"
(onSelect)="control=$event" >
click me
</div>
Where our directive is
export class SelectDirective implements AfterViewChecked {
#Input('appSelect') control;
#Output() onSelect:EventEmitter<any> = new EventEmitter<any>();
constructor(private elRef: ElementRef, private renderer: Renderer2) {
}
ngAfterViewChecked() {
if (this.elRef.nativeElement==this.control)
this.renderer.setStyle(this.elRef.nativeElement, 'color', 'red');
else
this.renderer.setStyle(this.elRef.nativeElement, 'color', 'black');
}
#HostListener('mousedown') onmousedown() {
this.onSelect.emit(this.elRef.nativeElement);
}
}
See that we change the color in the event AfterViewChecked. You can see the result of both solutions in the stackblitz

Related

ngx-intl-tel-input can't able to give custom tabindex

I have used ngx-intl-tel-input as a separate component and tried to
give custom tabindex but it's not taking to country box field and
input box field actually how can i make it possible?
<ngx-intl-tel-input *ngIf="!tooltip && type == 'phone' && !showPasswordIcon" [inputId]="fcn ? fcn : 'mobileNumber'" cssClass="form-control input-md" class="phone-box" [enablePlaceholder]="enablePlaceholder" [selectedCountryISO]="CountryISO.Australia" [maxLength]="15" [separateDialCode]="true" [formControl]="form.controls[fcn]" [phoneValidation]="true" container="body" (paste)="onlyNumbers($event)" (drop)="onlyNumbers($event)" triggers="manual" #inputContainer customPlaceholder="Mobile number"> </ngx-intl-tel-input>
You may consider creating a directive that can help you to add tabIndex on desired input element.
#Directive({
selector: '[addTabIndex]',
})
export class AddTabIndexDirective {
#Input() addTabIndex;
#Input() targetElement = 'input';
constructor(private el: ElementRef, private render: Renderer2) {}
ngAfterViewInit() {
const input = this.el.nativeElement.querySelector(this.targetElement);
if (input && this.addTabIndex) {
this.render.setAttribute(input, 'tabindex', this.addTabIndex);
}
}
}
Usage
<ngx-intl-tel-input tabIndex="2"
Stackblitz

How to dynamically change attribute name in Angular template?

How to dynamically change which property is set on an HTML element in the template?
I have an anchor wrapper component, which accepts both href and routerLink properties. Only one of them needs to be set. I want to write it's template, so that I'm setting only one of href and routerLink attributes on <a> element, whichever is defined.
Is it possible without separately defining both cases with *ngIf?
anchor.component.ts
import { Component, Input, OnInit } from '#angular/core';
#Component({
selector: 'my-anchor',
templateUrl: './anchor.component.html',
styleUrls: ['./anchor.component.scss'],
})
export class AnchorComponent implements OnInit {
#Input() public label: string;
// Only one of href and routerLink must be specified
#Input() public href?: string;
#Input() public routerLink?: string;
ngOnInit() {
this.ensureEactlyLinkTargetDefined();
}
private ensureEactlyLinkTargetDefined(): void {
if (!((this.href && !this.routerLink) || (!this.href && this.routerLink))) {
throw new Error("Exactly one of the properties 'href' and 'routerLink' must be defined");
}
}
}
anchor.component.html
<a
<!--
Here lies the problem. I only want to set one of those
attributes, not both simultaneously, as then href is not
respected, as routerLink directive overwrites it
-->
[href]="href"
[routerLink]="routerLink"
<!--
Something like [attr]="setAttribute(attributeName, attributeValue)"
-->
>
{{ label }}
</a>
Well instead of binding an attribute/directive, you should bind an event :
<a (click)="doSomething($event)">My link</a>
doSomething(event: MouseEvent) {
if (condition) this.router.navigate(url); // [routerLink]
else window.location.href = url; // href
}
EDIT If you want to achieve that, simply put this code into a directive
#Directive({ selector: 'navigator' })
export class NavigatorDirective {
#Input('navigator.condition') condition: boolean;
constructor(private router: Router) {}
#HostBinding('click', ['$event'])
doSomething(event: MouseEvent) {
if (this.condition) this.router.navigate(url); // [routerLink]
else window.location.href = url; // href
}
}
<a [navigator]="url" [navigator.condition]="myCondition">My link</a>

Ionic2 - invisible tabs - when generated from an observable

My tabs.ts (simpilified) - data used to generated tabs with *ngFor is brought from php backend:
import ...
export interface Group {
id: number;
group: string;
};
#Component( {
template: `
<ion-tabs #myTabs selectedIndex="0">
<ion-tab *ngFor="let tab of userGroups" [root]="page" [rootParams]="tab.id" [tabTitle]="tab.group" tabIcon="pulse"></ion-tab>
</ion-tabs>
`
})
export class GroupsTabsPage {
userGroups: Group[];
page: any = TabStudentsPage;
constructor( public app: App, public api: Api, public navParams: NavParams ) {
this.api.getGroupsList()
.subscribe(
data => {
this.userGroups = data;
},
err => {
this.app.getRootNav().push( LoginPage )
}
);
// ionViewDidEnter() {
// }
}
}
The result is invisible tabs. But when you hover your mouse ovet them, the cursor changes into 'hand' and you can click them. When clicked, the whole tabs bar becomes visible and all works as expected.
When I used #ViewChild to refer to the tabs elements, the interesting thing is that its 'length' property is always 0 (I checked in ionViewDidLoad event). Trying to select one of the tabs programatically also fails - they are like ghosts;)
Also when you place at least one static tab next to *ngFor ones in the template, all *ngFor ones show up but the static is always selected no matter what you select programatically or in selectedIndex property on tabs element.
Any idea guys? I've wasted three days..
that's a known bug, take a look at the element css, the subview's .tabbar has opacity of 0. I've just fixed it with a an override of opacity: 1. Ugly, but works...
Creating ion-tab from observable (dynamically) has some bugs (duplicates, wrong rendering etc) I use a workaround to avoid it, it consist of removing and loading the ion-tabs runtime every time then observable changes.
Parent template:
<div #pluginTabContainer></div>
Parent component:
#ViewChild("pluginTabContainer", {read: ViewContainerRef}) pluginTabContainer:ViewContainerRef;
...
plugins$.subscribe((pluginTabs:Array<PluginTabType>) => { let componentFactory = this.componentFactoryResolver.resolveComponentFactory(PluginTabContainerComponent); this.pluginTabContainer.clear(); this.pluginTabContainertRef = this.pluginTabContainer.createComponent(componentFactory); this.pluginTabContainertRef.instance.data = pluginTabs;
...
ngOnDestroy() { this.pluginTabContainertRef.destroy(); }
Loaded ion-tabs template:
<ion-tabs> <ion-tab *ngFor="let tab of data" [root]="'PluginTabPage'" [rootParams]="tab"></ion-tab> </ion-tabs>
Loaded ion-tabs component (getting parameter):
#Input() data: PluginTabType;
Hope will be helpful for you.
I had a similar issue during development and I was able to solve this by making ngOninit async and calling a timeout to set the selected tab.
view
<ion-tabs #ctrlPanelTabs class="tabs-basic">
<ion-tab *ngFor="let appTab of appTabs" tabTitle={{appTab.name}} [root]="rootPage"></ion-tab>
</ion-tabs>
1) ngOninit is async
2) this.ctrlPanelTabs.select(0); is set inside a timeout function
import { Component, OnInit, ViewChild } from '#angular/core';
import { NavController, Tabs } from 'ionic-angular';
import { AppSettings } from '../../common/app.config';
import { AppTab } from '../../models/app-tab';
import { AppTabService } from '../../services/app-tab.service';
import { PanelTabComponent } from './panel-tab';
#Component({
selector: 'page-control-panel',
templateUrl: 'control-panel.html',
providers: [AppTabService]
})
export class ControlPanelPage implements OnInit {
#ViewChild("ctrlPanelTabs") ctrlPanelTabs: Tabs;
appTabs: AppTab[] = [];
message: string;
rootPage = PanelTabComponent;
constructor(public navCtrl: NavController,
private appTabService: AppTabService) {
console.log("Control Panel Page : Constructor called..");
}
async ngOnInit() {
console.log("Control Panel Page : Entering ngOninit..");
await this.loadAppTabs();
setTimeout(() => {
this.ctrlPanelTabs.select(0);
}, 100);
console.log("Control Panel Page : Exiting ngOninit..");
}
async loadAppTabs() {
console.log("Control Panel Page : Entering loadAppTabs..");
await this.appTabService.getAppTabsHierarchyBySlaveDeviceId(AppSettings.selSlaveDeviceId)
.then((response: any) => {
this.appTabs = JSON.parse(response.result);
console.log(this.appTabs);
console.log("Control Panel Page : Exiting loadAppTabs..");
});
}
}

Angular2: Having a fixed element positioned by relation to its parent

I want to have a fixed element by posisioned according to its parent and not the browser. I have thus design a (quick and dirty) angular2 directive :
My template
<div class="main" style="position: relative">
<div style="position: absolute" positioningFromParent="left" [additionalPixels]=20>
...
</div>
</div>
My Angular2 Directive
import { Directive, ElementRef, Input, OnInit } from "angular2/core"
#Directive({
selector: "[positioningFromParent]"
})
export class PositioningFromParent implements OnInit {
private el:HTMLElement
#Input() positioningFromParent: string = ""
#Input() additionalPixels: number = 0
constructor(el: ElementRef) {
this.el = el.nativeElement
}
ngOnInit() {
let v = this.el.parentNode.getBoundingClientRect()[this.positioningFromParent]
this.el.style[this.positioningFromParent] = (v + this.additionalPixels).toString() + "px"
}
}
However, it doesn't work as the width of my main element is set dynamically (I can't specify it). When the ngOnInit runs, it gives me a width of 0 as its width only comes later. How could I "watch" the parent's width in angular2 ?
Thanks
The view is not ready in ngOnInit() use ngAfterViewInit() instead.
import { Directive, ElementRef, Input, AfterViewInit } from "angular2/core"
#Directive({
selector: "[positioningFromParent]"
})
export class PositioningFromParent implements AfterViewInit {
private el:HTMLElement
#Input() positioningFromParent: string = ""
#Input() additionalPixels: number = 0
constructor(el: ElementRef) {
this.el = el.nativeElement
}
ngAfterViewInit() {
let v = this.el.parentNode.getBoundingClientRect()[this.positioningFromParent]
this.el.style[this.positioningFromParent] = (v + this.additionalPixels).toString() + "px"
}
}
You should use the ngAfterViewInit lifecycle hook instead of ngOnInit, because this will be called after the actual DOM elements have been created (ngOnInit is only called once the component's inputs have been resolved). Using ngAfterViewInit should mean the parent's width is non-zero by the time the code inside that function runs.

Angular2 watching parent's css attribute

I have a directive which adds the number of pixels corresponding to its parent right css attribute
import { Directive, ElementRef, AfterViewInit } from "angular2/core"
#Directive({
selector: "[d]"
})
export class PositioningFromParent implements AfterViewInit {
private el:HTMLElement
constructor(el: ElementRef) {
this.el = el.nativeElement
}
ngAfterViewInit() {
let v = this.el.parentNode.getBoundingClientRect().right
this.el.style[left] = v + "px"
}
}
It works just fine. However, if I do resize my window, my parent is changing and its right value as well. My directive doesn't adapt that value at the minute. How could I watch the this.el.parentNode.getBoundingClientRect().right value in Angular2 ?
Thanks
Listen to resize and update when the event is fired:
#Directive({
selector: "[d]"
})
export class PositioningFromParent implements AfterViewInit {
private el:HTMLElement
constructor(el: ElementRef) {
this.el = el.nativeElement
}
ngAfterViewInit() {
this.updateLeft();
}
#HostListener('window:resize')
updateLeft() {
let v = this.el.parentNode.getBoundingClientRect().right
this.el.style[left] = v + "px"
}
}
See also angular2: How to use observables to debounce window:resize to limit the rate the code is executed during resize.