Re-rendering a particular component in Angular 2 release version - javascript

I have two components: BuilderComponent and InputTextComponent.
With drag and drop I put a directive in the sortableList element of the BuilderComponent template. With the inspector I can see the directive appears in the sortablelist DOM element:
<div class="row">
<div class="col-md-12">
<ul id="sortableList">
<zbjfb-input-text></zbjfb-input-text>
</ul>
</div>
How can I force the BuilderComponent to detect that the content of the template is changed since the last compile and then re-render the template with the new added directive so I can see the new compiled InputTextComponent.
BuilderComponent:
import { Component } from '#angular/core';
#Component({
selector: 'zbjfb-builder',
template: '
<div class="row">
<div class="col-md-12">
<ul id="sortableList">
</ul>
</div>
</div>
'
})
export class BuilderComponent {}
InputTextComponent:
import { Component } from '#angular/core';
#Component({
selector: 'zbjfb-input-text',
templateUrl: './input-text.component.html',
styleUrls: ['./input-text.component.css']
})
export class InputTextComponent {}
Any idea?
Thanks in advance.

If your drag'n'drop solution is HTML5 based, maybe you can make use of HostListener decorator from '#angular/core' to hack your drag and drop exchange logic:
Add something like this on your drop area component:
#HostListener('drop', ['$event'])
onDrop(event: any) {
//do something
}
And something like this on your draggable component:
#HostListener('dragstart', ['$event'])
onDrag(event: any) {
//do something
}
HostListeners provide you ways to implement conventional listeners for element events like onmousedown, onkeyup, ondrop, ondrag.
Then think of some logic to identifiy what's being dragged/dropped and change the drag area component model. Here's some functional code I've made inspired by W3Schools topic on drag'n'drop:
import { Component, HostListener, Input } from '#angular/core';
// The draggable component
#Component({
selector: 'dragme',
template: `
<div draggable="true">
Drag {{name}}!
</div>
`,
styles: [`
[draggable] {
-moz-user-select: none;
-khtml-user-select: none;
-webkit-user-select: none;
user-select: none;
-khtml-user-drag: element;
-webkit-user-drag: element;
background-color: #AAA;
border: 1px solid black;
padding: 24px;
margin: 12px;
}
`]
})
export class DragMe {
#Input()
name:string = "";
#HostListener('dragstart', ['$event'])
onDrag(event:any){
event.dataTransfer.setData("name",this.name);
}
}
// The drop area component
#Component({
selector: 'drop',
template: `
<div class="drop">
Drop over me!
<ul>
<li *ngFor="let i of items">{{i}}</li>
</ul>
</div>
`,
styles: [`
.drop{
border: 1px solid black;
padding: 24px;
}
`]
})
export class DropOverMe {
items:string[] = [];
#HostListener('dragover', ['$event'])
onDragover(event:any){
event.preventDefault();
}
#HostListener('drop', ['$event'])
onDrop(event:any){
event.preventDefault();
var name = event.dataTransfer.getData("name");
this.items.push(name);
}
}
// The functional example
#Component({
selector: "drag-example",
template: `
<dragme name="Bob"></dragme>
<dragme name="Alice"></dragme>
<dragme name="Carl"></dragme>
<drop></drop>
`
})
export class DragExample{
}
Full code at: https://github.com/rafaelodon/angular2-html5-dragndrop-example

Related

How to add styling to the root component dom element (angular selector component)

I have the following component:
// Typescript
#Component({
selector: 'form-button',
templateUrl: './form-button.component.html',
styleUrls: ['./form-button.component.scss']
})
export class FormButtonComponent {}
//form-button.component.html
<div class="form-button-wrapper">
<div class="content"></div>
</div>
//form-button.component.scss
.form-button-wrapper {
width: 100%;
height: 100%
}
In the html, will looks like this:
<head>...</head>
<body>
....
<form-button>
<div class="form-button-wrapper">
<div class="content"></div>
</div>
</form-button>
....
</body>
I want t defined a width and weight to the <form-button> instead of in the <div class="form-button-wrapper">.
How can I do that?
Yes, just use the :host selector. It gives you access to the wrapping angular element.
//form-button.component.scss
:host {
// insert your styles here
}
.form-button-wrapper {
width: 100%;
height: 100%
}

Angular Template Reference : Bind height of one div to height of another

I want to bind the height of one angular component to the height of a div. I am trying to use template reference to fetch the height.
Is it possible to do so using this method in a clean way? I want to do it something like this in snippet below.
<div [style.height.px]="section1.offsetHeight"></div>
<app-custom-tag #section1>
</app-custom-tag>
I want the height of <div> to be equal to height of <app-custom-tag>
I can't use css column layout for this as these two elements are not positioned together.
I think there are a few extra things you'll have to do.
When you reference a component inside the view, you'll get the class instance. With that in mind, you can inject the ElementRef so you can get information about the native element.
Consider this example:
foo.component.ts
#Component({
selector: 'foo',
template: `foo`,
styles: [`:host { color: red; display: block; height: 300px; } `]
})
export class FooComp {
get offsetHeight () {
return this.el.nativeElement.offsetHeight;
}
constructor (private el: ElementRef) { }
}
app.component.ts
#Component({
selector: 'my-app',
template: `
<foo #f></foo>
{{ f.offsetHeight }}
<br>
<div style="border: 1px solid black" [style.height.px]="f.offsetHeight"></div>
<!-- <div style="border: 1px solid black" [ngStyle]="{ height: f.offsetHeight + 'px' }"></div> -->
<br>
<input #i id="demo" type="text">
{{ i.id }}
`,
})
export class AppComponent { }
When you reference a DOM element in the view, you'll get that DOM element.
ng-run demo.

Unable to find CSS in angular

I have generated component using cli
"ng generate component registration"
it created following files
registration.component.html
registration.component.scss
registration.component.spec.ts
registration.component.ts
Now, I haved added a css class in scss file
.loginBox {
width: 260px;
}
Now in the html file
<p class="loginBox"> test </p>
It pointed out that loginBox is undefined CSS in my IDE and when I tested in ng serve it didnt show the css was applied.
When I do autocomplete on the class= I saw there are alots of css that I didnt add such as L0, L1, L2, L3 ....so where does those css coming from and why doesnt my local css work? Edit: those css seems like bootstrap css or somewhat buildin css there are something like mat-action-row or other type of css I dont think I included them.
The ts file I have included styleUrls: ['./registration.component.scss']
Edit: even if I added it the global styles.scss it is still says the loginBox is undefined CSS. It is likely some config or something is missing....I cant figure out what it is...
Edit:
registration.component.ts
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-registration',
templateUrl: './registration.component.html',
styleUrls: ['./registration.component.scss']
})
export class RegistrationComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}
registration.component.scss
.loginBox {
/* color: #4C4633; */
/* font-size: 12px; */
/* margin-bottom: 10px; */
/* padding: 10px 0px 10px 10px; */
width: 260px;
}
registration.component.html
<p class="loginBox">
registration works!
</p>
<div class="loginBox"> test </div>
Above registration folder..
app.component.html
<div class="container-fluid p-0">
<router-outlet></router-outlet>
</div>
app.module.ts
const routes: Routes = [
{ path: '', component: RegistrationComponent}
];
#NgModule({
declarations: [RegistrationComponent],
imports: [
BrowserModule,
RouterModule.forRoot(routes)
],
providers: [PreviousUrlService, {provide: APP_BASE_HREF, useValue : '/' }],
bootstrap: [AppComponent]
})
export class AppModule { }
See this answer here. Use encapsulation: ViewEncapsulation.None in the #component definition.
is scss correctly read? try to run this command
ng config schematics.#schematics/angular:component.styleext scss
then, re-run you project
try:
:host ::ng-deep{
.loginBox {
width: 260px;
}
}

How to bind on click event on dynamically created button in Angular 6?

I am trying to create a dynamic button with an onclick event. The showname() defined the on same Component.ts. But there is no response on clicking the button
Component.ts
createtooltip() {
this.tooltip = document.createElement('div');
this.tooltip.style.cssText =
'position:absolute; background:black; color:white; padding:4px;z-index:10000;' +
'border-radius:2px; font-size:12px;box-shadow:3px 3px 3px rgba(0,0,0,.4);' +
'opacity:0;transition:opacity 0.3s';
this.tooltip.innerHTML = '<button id="popup" (click)="showname()" >Copy!</button>';
document.body.appendChild(this.tooltip);
}
showname() {
console.log("Hi User");
}
Could anyone help me to find the solution?
You won't have access to the document object everywhere.
So, you shouldn't be using document functions to do DOM manipulations. All these DOM Manipulations should be done only using Rendere2. If there's anything that you want to access on the DOM, you should do it using #ViewChild
Here's an Example:
import { Component, Renderer2, ElementRef, ViewChild } from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
name = 'Angular';
#ViewChild('tooltip') tooltip: ElementRef;
constructor(private renderer: Renderer2) {}
createtooltip() {
this.renderer.setAttribute(this.tooltip.nativeElement, 'class', 'my-button');
const button = this.renderer.createElement('button');
this.renderer.setProperty(button, 'id', 'popup');
this.renderer.setProperty(button, 'innerText', 'Copy');
this.renderer.listen(button, 'click', (event) => {
this.showname();
})
this.renderer.appendChild(this.tooltip.nativeElement, button);
}
showname() {
console.log("Hi User");
}
}
In template:
<button (click)="createtooltip()">Create Tooltip</button>
<div #tooltip>
</div>
In CSS:
p {
font-family: Lato;
}
.my-button {
position:absolute;
background:black;
color:white;
padding:4px;
z-index:10000;
border-radius:2px;
font-size:12px;
box-shadow:3px 3px 3px rgba(0,0,0,.4);
opacity:0;
transition:opacity 1s linear;
}
Here's a Sample StackBlitz for your reference.
I solved this problem by the other way
<a ngFor="let link of links" (click)="actions[link]()">Click</a>
`
actions: any = {
link1: () => this.func1(),
link2: () => this.func2()
}
`
angular doesnt compile the dynamic created HTML elements . u have to use ng-template like this :
<ng-template #myTemplate>
<div styles="...">
<button id="popup" (click)="showname()" >Copy!</button>
</div>
</ng-template>
It would be better to create the button with directs like *ngFor or *ngIf rather than create the elements like you do with Jquery.
This is due to the nature of Angular, which prioritizes and eases the usage of directives over simple javascript.
to do this you can :
HTML :
<button id="popup" (click)="showname()" *ngIf='elements.showNameButton==true' >Copy!</button>
** TS :**
elements={
showNameButton:false
}
createtooltip(){
this.elements.showNameButton =true;
}
showname() {
console.log("Hi User");
}

Angular JS 2.0 switch stylesheets based on User Input

How can I switch the stylesheets based on the button click in an AngularJS 2.0 application?
As right now I am including stylesheets on the head section of index.html page.
#Component({
selector: ...,
template: ...,
styles: [`
:host(:not(.some-class)) {
border: solid 1px red;
}
:host(.some-class) {
border: solid 3px green;
}
`
]})
export class MyComponent {
#HostBinding('class.some-class') isSomeClass = true;
}
Plunker example
I would leverage the ngStyle directive:
<h1 [ngStyle]="{'font-style': style, 'font-size': size, 'font-weight': weight}">
Change style of this text!
</h1>
<div (click)="changeStyle()">Update style</div>
Updading the style, size values from a method (linked to a click event) will update your style:
export class SomeComponent {
style = 'normal';
weight = 'normal';
size = '20px';
changeStyle($event: any) {
this.style = 'italic';
}

Categories