How to access the previous sibling through an angular directive? - javascript

At the moment, I'm using ELEMENTREF to access the DOM through the Redenrer2. Here's a basic example:
import { Directive, Renderer2, ElementRef } from '#angular/core';
#Directive({
selector: '[appHighlight]'
})
export class HighlightDirective {
constructor(private renderer: Renderer2, private el: ElementRef) {
this.renderer.setStyle(this.el.nativeElement, 'background', 'yellow');
}
}
The above code was just a test to leave the syntax highlight with the yellow color.
However, I need to know how do I access the previous element and capture the width of it to move to a left-style property?
Ex: Former brother has the width of 400px. The current element has the left of 400px.
I'm counting on the collaboration.

You can get the parent element:
let parent = this.renderer.parentNode(this.elementRef.nativeElement);
and then select his child somehow, maybe give them incrementing ID's:
let sibling = parent.querySelector('#child5');
and then you have siblings width:
let width = sibling.offsetWidth;.
Hope that helps.

Related

Angular Style DOM element issue

I am trying to query the DOM and add a style to it in Angular. One would think its simple but the following does not work and gives an error, is there an Angular specific way to do it?
let target = document.querySelector(".dom-element");
target.style.width = "100%";
You can do it using ngStyle: https://angular.io/api/common/NgStyle
[ngStyle]="{width: variableFromController}"
Or using #ViewChild and ngAfterViewInit: https://angular.io/api/core/ViewChild
template:
<div #domElement></div>
component:
#ViewChild('domElement') element: ElementRef;
public ngAfterViewInit() {
this.domElement.nativeElement.style.width = '100%';
}
What you need is the renderer2, you should avoid any direct DOM manipulation. This should do it:
constructor(private renderer: Renderer2) {
#ViewChild("dom-element") target: ElementRef;
ngAfterViewInit() {
// target is set here
this.renderer.setStyle(this.target.nativeElement, 'width', '100%');
}

text-overflow property custom style

Application is built on angular. In a component, there is a div inside which there is a text. <div>abcdefghijklmnop<div>
Based on the screen size, it should show completely or it should clipped. For this I have found that there is a property 'text-overflow', which clipped the text like abcde.... But the requirement is we have to clip the text in other way,
<first 3 character>...<last 3 character>
So it should look like abc...nop. How can we achieve this? Browser is chrome.
You could use a attribute directive like bellow to do this. For more details please refer Angular DOC
Please Note: You could improve this directive as you wish. This directive is only giving you the basis to implement that feature.
Directive:
import { Directive, ElementRef, OnInit } from '#angular/core';
#Directive({
selector: '[appClip]'
})
export class ClipDirective implements OnInit {
constructor(private el: ElementRef) { }
ngOnInit(): void {
let text: string = this.el.nativeElement.innerHTML;
if(text.length > 6) {
const first3 = text.slice(0, 3);
const last3 = text.slice(text.length - 3)
this.el.nativeElement.innerHTML = `${first3}...${last3}`;
}
}
}
HTML:
<div appClip="">abcdefghijklmnop</div>
Working DEMO

Clone/Copy a Method in Javascript?

How does one clone or copy a method such that no reference to the original method is maintained?
I am trying to copy a click function on an element using the DOM and assign it to another element so I can remove the first element from the DOM without losing the function reference on the other element. I am doing this in a directive.
element.click = parent.click //need a better way to copy
element.click() //works
remove(parent)
element.click() //doesn't work
The reason why I am doing this is because I am removing the parent-wrapper tag, which has a (click) method assigned to it, so that just its inner button template remains. However, because I am removing the wrapper tag, the (click) on the parent tag is not being passed to the template button tag.
For instance, I have an app-button component with a button in its template.
Currently this is rendered:
<app-button (click) = function(1, 2)>
<button>
</button>
</app-button>
I want the parent tag removed, which I am doing via a DOM manipulation, but want to maintain the (click) function, like:
<button (click) = function(1, 2)>
</button>
I'm not quite sure I understand why you are trying to do what you are doing(or what it is exactly), but from my understanding, you could store a reference to the host element '' in the component class, then you can assign a listener to the <button> element in your template that triggers a click event on that reference:
import { BrowserModule } from '#angular/platform-browser';
import { NgModule, Component, ViewChild, ElementRef, Renderer2, OnInit} from '#angular/core';
#Component({
selector: 'app-root',
template: `
<app-button (click)="foo()"></app-button>
`
})
export class AppComponent {
foo() {
console.log('bar');
}// end function
}// end class
#Component({
selector: 'app-button',
template: `<button #button (click)="onClick()">Click me</button>`
})
export class AppButtonComponent implements OnInit {
#ViewChild('button')
private button:ElementRef;
constructor(
private element:ElementRef,
private renderer:Renderer2
) {}
ngOnInit() {
let parent = this.element.nativeElement.parentElement,
element = this.element.nativeElement,
button = this.button.nativeElement;
this.renderer.insertBefore(parent, button, element );
this.renderer.removeChild(parent, element);
}// end function
onClick() {
let element = this.element.nativeElement;
element.click();
}// end function
}// end class

Angular 6: Host binding in directive is not two way binding?

I am working on Angular 6 on a pretty simple example.
I am creating a Directive that I can put on my textareas so that they resize themselves automatically.
However, I have an issue using host binding. I want to check if resize is needed before resizing, but I cannot check: this.height gives undefined by default.
Even worse, if it has been resized manually, this.height remains undefined anyway.
I've tried using the #Input decorator on top of the #HostBinding, but this just sets an initial value, and then when resizing, height doesn't match the real size of the element anymore.
I can't seem to find out why it doesn't work, could you please help ?
Also I am conscious that an alternative to what I'm trying to do would be to just set the height of my directive to the native element scrollheight without checking prior, but then I wouldn't understand why my height value is undefined/doesn't dynamically update.
Here is my code:
simple.component.html
<textarea type="text"
class="form-control mb-1"
appAutoResizeTextArea></textarea>
simple.component.ts
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-simple-component',
templateUrl: './simple.component.html',
styleUrls: ['./simple.component.css']
})
export class SimpleComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}
auto-resize-text-area.directive.ts
import { Directive, ElementRef, HostListener, Renderer2, HostBinding, Input } from '#angular/core';
#Directive({
selector: '[appAutoResizeTextArea]',
})
export class AutoResizeTextAreaDirective {
#HostBinding('style.height.px') height;
#HostListener('input')
onKeyDown(){
console.log(this.height); // gives 'undefined'
if(this.height < this.el.nativeElement.scrollHeight || this.height > this.el.nativeElement.scrollHeight)
this.height = this.el.nativeElement.scrollHeight;
}
constructor(private el:ElementRef, private renderer:Renderer2) { }
}
Thanks for your help

angular 2 bind to component selector

I have a component that I needs to be hidden when a property is true. Is there a way to solve this within the component itself.
Example:
#Component({
selector: 'prio-tab',
changeDetection: ChangeDetectionStrategy.OnPush,
template:
`
<div [hidden]="!active">
stuff
</div>
`
})
export class PrioTabComponent {
#Input() title;
active:boolean = false;
}
Here I would like to have the actual "prio-tab" element to depend on active-flag. Not just the content inside prio-tab.
Or is it maybe possible to use itself when declaring the prio-tab tag, like this:
<prio-tab [hidden]="this.active">
stuff
</prio-tab>
I guess a working solution would be to create a reference to the prio-tab component in its parent and then go through the parent. But how would I do if I have multiple prio-tab's ?
You can use #HostBinding()
export class PrioTabComponent {
#Input() title;
#HostBinding('hidden')
active:boolean = false;
}

Categories

Resources