Angular 2 Directive for a component overrides ng-content? - javascript

I have a Component that is called ButtonComponent:
import { Component } from "angular2/core";
#Component({
selector: 'btn',
template: '<div class="btn"><ng-content></ng-content></div>'
})
export class ButtonComponent { }
and Directive:
import { Directive, Input } from 'angular2/core';
#Directive({
selector: 'btn[dialog-data]'
})
export class DialogButtonDirective {
#Input('dialog-data')
public dialogData: any;
}
But if I try to use it like this:
<btn [dialog-data]="dart()">DART</btn>
Then button have nothing inside of it.
Why? When I'm not using this directive everything's fine.

OK, it's a bit confusing but I found the answer. This code isn't working because DialogButtonDirective declared in 'directives' field before ButtonComponent.
So I've changed this:
directives: [DialogButtonDirective, ButtonComponent]
To this:
directives: [ButtonComponent, DialogButtonDirective]
And it solved the problem. Thanks!

Related

custom if directive does not show expected results

in this tutorial
https://www.sitepoint.com/practical-guide-angular-directives/
i am learning how to create a customised directive. i followed the steps as shown in the code posted below, but despite added the exact code as explained in the aforemenrtioned website, when i run the command
ng serve --open
i get something as shown in the image posted below.
please let me know why myCustomIf is not working. i say that myCustomIf is not working because what i got on the localhost:4200 is something as shown in the image posted
please let me know how to make the myCustomIf works as explained in the tutorial in the above posted link
app.component.ts:
import { Component } from '#angular/core';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'ngDirective1';
name = 'Angular';
condition = false;
}
app.myCustomeIfDirective.ts:
import { Directive, Input, TemplateRef, ViewContainerRef } from '#angular/core';
#Directive({
selector: '[myCustomIf]'
})
export class MyCustomeIfDirective{
constructor(private templateRef: TemplateRef<any>,private viewContainer: ViewContainerRef){ }
#Input()
setMyCustomIf(condition : boolean) {
if(condition) {
this.viewContainer.createEmbeddedView(this.templateRef);
} else {
this.viewContainer.clear();
}
}
}
app.module:
import { Directive, Input, TemplateRef, ViewContainerRef } from '#angular/core';
#Directive({
selector: '[myCustomIf]'
})
export class MyCustomeIfDirective{
constructor(private templateRef: TemplateRef<any>,private viewContainer: ViewContainerRef){ }
#Input()
setMyCustomIf(condition : boolean) {
if(condition) {
this.viewContainer.createEmbeddedView(this.templateRef);
} else {
this.viewContainer.clear();
}
}
}
app.component.html:
<h1 my-error>Hello {{name}}</h1>
<h2 *myCustomIf="condition">Hello {{name}}</h2>
<button (click)="condition = !condition">Click</button>
image:
If you open console it should show smth like:
NG0303: Can't bind to 'myCustomIf' since it isn't a known property of
'h2'
An Angular structural directive, that is written in a short syntax(with *) and that takes one input or more inputs, must have an #Input with the same name as directive's attribute selector(other inputs follow another rule described here What is the exact grammar for Angulars structural directives), e.g.:
#Directive({
selector: '[anyAttr]'
})
export class MyCustomeIfDirective{
#Input()
anyAttr: any;
or
#Directive({
selector: '[anotherAttr]'
})
export class MyCustomeIfDirective{
#Input()
set anotherAttr(val: any) {}
Why is it so?
That's because *ngIf is just a shortcut for expanded version:
<ng-template [ngIf]="...">...
or
*anyAttr => <ng-template [anyAttr]="...">...
Now, let's look at your code:
#Directive({
selector: '[myCustomIf]'
})
export class MyCustomeIfDirective{
#Input()
setMyCustomIf(condition : boolean) {
Several things to notice:
setMyCustomIf is just a method in your case
if you convert it to a setter set MyCustomIf then MyCustomIf doesnt match myCustomIf because js is case-sensitive.
The solution is:
#Input()
set myCustomIf(condition : boolean) {
Ng-run Example
in your directive (app.myCustomeIfDirective.ts), you need to match the name of your input to the name of the directive (because the condition is passed with that attribute):
#Input("myCustomIf")
set myCustomIf(condition : boolean) {
if(condition) {
this.viewContainer.createEmbeddedView(this.templateRef);
} else {
this.viewContainer.clear();
}
}
(note you can also change the name of the function to match the directive name)
stackblitz demo

Integrate xterm.js to Angular

I'm new to Angular.
I'm trying to use xterm.js (https://xtermjs.org/) but it display badly.
Here is the render :
Render
I created a xterm component. The xterm.component.ts file code is :
import { Component, OnInit } from '#angular/core';
import { Terminal } from "xterm";
#Component({
selector: 'app-xterm',
templateUrl: './xterm.component.html',
styleUrls: ['./xterm.component.css'],
})
export class XtermComponent implements OnInit {
public term: Terminal;
container: HTMLElement;
constructor() { }
ngOnInit() {
this.term = new Terminal();
this.container = document.getElementById('terminal');
this.term.open(this.container);
this.term.writeln('Welcome to xterm.js');
}
}
My xterm.component.html only contains this :
<div id="terminal"></div>
I don't really know what to do more ...
Thanks in advance guys
You must set the component encapsulation
#Component({
encapsulation: ViewEncapsulation.None,
...
})
Encountered the same problem and found this page.
Maybe this is too late for the OP, but could be useful for others.
The styles are wrong because 1) the xterm.css is not loaded, and 2) the encapsulation.
My solution to 1) was to add #import 'xterm/dist/xterm.css'; in the scss file for this component.
And 2) can be solved by setting encapsulation: ViewEncapsulation.None as Victor96's answer, or better setting encapsulation: ViewEncapsulation.ShadowDom.
Hope this helps.
I know this is old, but I had to put terminal initialation in ngAfterViewInit. Otherwise the DOM elements are undefined.
Try to use in template reference variable by using the hash symbol
<div #myTerminal></div>
and in component
#ViewChild('myTerminal') terminalDiv: ElementRef;
In ngOnInit
ngOnInit() {
this.term = new Terminal();
this.term.open(this.terminalDiv.nativeElement);
this.term.writeln('Welcome to xterm.js');
}

Javascript Angular 4 using eventEmitter though several layers of components

I am having a bit of a problem with getting the following situation done in Angular.
I am using Angular 4 and this is the situation.
app.component.html contains a wrapper div which I would like to be able to change it's color by adding a class to it.
My problem is that I have different layers of components.
For example, if I wanted to change the class in app.component.html it would have this:
app.component - root
button-wrapper.component - holds the button
button.component - message comes from there.
Normally I could do this:
import { Component } from '#angular/core';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
title = 'app';
myClass = '';
handleEvent(value) {
console.log(value);
myClass = value;
}
}
and in app.component.html have this:
<div [ngClass]="myClass">
<app-button (outputEvent)="handleEvent($event)"></app-button>
</div>
BUT, my problem is that app-button component is inside button-wrapper component so it looks like this:
<div [ngClass]="myClass">
<button-wrapper></div>
</div>
So where would I put this:
(outputEvent)="handleEvent($event)"
How can I go round this issue?
You can chain events as long as their direct children:
button.component.ts (selector: app-button)
startChainEvent() {
this.outputEvent.emit('className');
}
button-wrapper.component.html
<app-button (outputEvent)="handleEvent($event)"></app-button>
button-wrapper.component.ts (selector: app-button-wrapper)
handleEvent(e) {
this.outputEvent.emit(e);
}
app.component.html
<app-button-wrapper (outputEvent)="handleEvent($event)"></app-button-wrapper>
app.component.ts
handleEvent(e) {
myClass = e;
}

Angular #Output not working

Trying to do child to parent communication with #Output event emitter but is no working
here is the child component
import { Component, OnInit, Output, Input, EventEmitter } from '#angular/core';
#Component({
selector: 'app-emiter',
templateUrl: './emiter.component.html',
styleUrls: ['./emiter.component.css']
})
export class EmiterComponent implements OnInit {
#Output() emitor: EventEmitter<any>
constructor() { this.emitor = new EventEmitter()}
touchHere(){this.emitor.emit('Should Work');
console.log('<><><><>',this.emitor) // this comes empty
}
ngOnInit() {
}
}
this is the html template
<p>
<button (click)=" touchHere()" class="btn btn-success btn-block">touch</button>
</p>
The console.log inside the touchHere it shows nothing
even if I put this inside the parent component it show nothing as well
parent component
import { Component , OnInit} from '#angular/core';
// service I use for other stuff//
import { SenderService } from './sender.service';
// I dont know if I have to import this but did it just in case
import { EmiterComponent } from './emiter/emiter.component'
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'app';
user: any;
touchThis(message: string) {
console.log('Not working: ${message}');
}
constructor(private mySessionService: SenderService) { }
}
and here is the html template
<div>
<app-emiter>(touchHere)='touchThis($event)'</app-emiter>
</div>
Parent component template:
<app-emitor (emitor)='touchThis($event)'></app-emiter>
In parent template #Output should be 'called', not the child method.
Also, see: https://angular.io/guide/component-interaction#parent-listens-for-child-event
Here’s an example of how we write a component that has outputs:
#Component({
selector: 'single-component',
template: `<button (click)="liked()">Like it?</button>`
})
class SingleComponent {
#Output() putRingOnIt: EventEmitter<string>;
constructor() {
this.putRingOnIt = new EventEmitter();
}
liked(): void {
this.putRingOnIt.emit("oh oh oh");
}
}
Notice that we did all three steps: 1. specified outputs, 2. created an EventEmitter that we attached
to the output property putRingOnIt and 3. Emitted an event when liked is called.
If we wanted to use this output in a parent component we could do something like this:
#Component({
selector: 'club',
template: `
<div>
<single-component
(putRingOnIt)="ringWasPlaced($event)"
></single-component>
</div>`
})
class ClubComponent {
ringWasPlaced(message: string) { console.log(`Put your hands up: ${message}`);
} }
// logged -> "Put your hands up: oh oh oh"
Again, notice that:
putRingOnIt comes from the outputs of SingleComponent
ringWasPlaced is a function on the ClubComponent
$event contains the thing that wasemitted, in this case a string
<app-emiter (emitor)="touchThis($event)" ></app-emiter>
By using #Output() you should apply the event you need to emit in the directive of the emitter component.Adding the name of the variable to the the directive and but the emitted over function inside the quotation passing the $event.
touchHere() is the method from which you are binding some value to emit with your EventEmitter. And your EventEmitter is 'emitor'.
So your code will work if you simply do the below:
<app-emiter (emitor)='touchThis($event)'></app-emiter>

Angular 2 using both typescript and javascript

I have angular 2 application written on javascript. I want to migrate it to typescript.
JS code is:
(function (app) {
app.SomeService = ng.core
.Class({
constructor: [app.AnotherService, function SomeService(s) {
this._anotherService = s;
}],
someFunction: function(){
...
}
.....
});
})
(window.app || (window.app = {}));
I want to inject this service into my typescript component. How can I do that?
I tried to use it like this:
#Component({...})
export class SomeComponent {
constructor(public someService: window.app.SomeService) {
}
}
But it does not work.
The way I've managed to mix JS and TS is to have a file with the JS, in your case let's say it's src/app.js , with the code you posted above.
At this point you can do one of two things:
You create a component that is going to use said JS code, something like:
import {Component} from "angular2/core";
#Component({
selector: 'app',
template: ` <a> <onclick='app()'>When the function is clicked, use app() code</a>
,
directives: []
})
export class App {
constructor(){
}
}
The template is going to depend on what your code is supposed to do. I often use onClick, but here you have an example of what it might look like:
template: `<input value="Select Date" type="text" class="datepicker" onclick ="myCalendar()" >
`
Another option is to call the JS code from the constructor
import {Component} from 'angular2/core';
#Component({
selector: 'app',
template: `
<div>
</div>
`,
directives: []
})
export class MyApp {
name:string;
constructor() {
this.name='Angular 2';
app();
}
}
So it depends on what you want to do, and when, as far as I can tell. There are people with more experience but I tried to not say anything wrong, and provide code similar to what I have working right now.

Categories