Is Angular2 Injectables and creating instance or same? - javascript

I am new to es6, typescript and Angular2 stuff, I have tried directive example. It looks like following..
import { Directive, ElementRef, Input, Renderer } from '#angular/core';
#Directive({ selector: '[myHighlight]' })
export class HighlightDirective {
constructor(el: ElementRef, renderer: Renderer) {
renderer.setElementStyle(el.nativeElement, 'backgroundColor', 'green');
}
}
and i have tried following variants, but didn't work as i expected..
import { Directive, ElementRef, Input, Renderer } from '#angular/core';
#Directive({ selector: '[myHighlight]' })
export class HighlightDirective {
constructor() {
console.log(new ElementRef())
//renderer.setElementStyle(el.nativeElement, 'backgroundColor', 'green');
}
}
also tried this..
import { Directive, ElementRef, Input, Renderer } from '#angular/core';
#Directive({ selector: '[myHighlight]' })
export class HighlightDirective {
constructor(ElementRef, Renderer) {
console.log(new ElementRef())
//renderer.setElementStyle(el.nativeElement, 'backgroundColor', 'green');
}
}
I didn't get the difference between el: ElementRef syntax and normal object instance creation with new ElementrRef .. Please Explain The Difference And Logic Behind Them and el: ElementRef relation and equivalent in normal or es6 js.. Thanks in advance :)

This is the basic building stone of angular 2 Dependency Injection (DI) mechanism. In short: if you need in your component reference to some service etc., you can must ask Angular via constructor. With line constructor(el: ElementRef, renderer: Renderer) you are basically asking the framework: "When you will construct the highlight directive for me, give me these two objects, ElementRef and Renderer. Without them, I as a highlight directive cannot live."
And how are these two objects obtained? Through DI framework during lifecycle of directive. I strongly suggest to read this awesome article for better understanding (it is a must): http://blog.thoughtram.io/angular/2015/05/18/dependency-injection-in-angular-2.html
In second and third examples (where your constructor is empty so nothing is injected to your directive on creation), you cannot simply create ElementRef through new(), because it requires more dependencies, for example nativeElement, as stated here: https://angular.io/docs/js/latest/api/core/index/ElementRef-class.html
But you are not providing these and simply cannot.

Related

angular 6 click not working html code present in typescript file

This question maybe asked, but it is not resolve my issue. I have Angular 6 project. In my ts component I added button tag. And I try to call remove method, but it is not working.
import { Component, OnInit } from '#angular/core';
import { Router, ActivatedRoute } from '#angular/router';
import { FormBuilder, FormGroup, Validators } from '#angular/forms';
declare var $:any;
#Component({templateUrl: 'login.component.html'})
export class detectionRuleComponent implements OnInit {
constructor(
private formBuilder: FormBuilder,
private route: ActivatedRoute,
private router: Router) {}
ngOnInit() {}
addNewRow(){
var new_row = `<button (click)="remove($event)">Remove</button>`;
}
remove(){
alert();
}
}
here when I click remove button alert() not coming. Please help me solve this issue.
Why do you have added a template in one method?
If you want to show the remove button in your template just do like this.
In this component login.component.html
<button (click)="remove($event)">Remove</button>;
Then in your TS write only your logic.
remove(event) {
alert(event);
}
And a question why do you need the jQuery tag $ ?
Angular works in such a way that if you inject an HTML snippet through the ts file for manipulating DOM, Angular doesn't register that directives inside the snippet you injected. Hence it is best practice to not manipulate DOM like that!
So for your issue, your remove method has not been registered at all for the click directive thus doesn't get called. It also doesn't have a proper parameter.
<!--HTML--->
<button (click)="addCicked($event)">Add</button>
<div *ngIf="isNewRowAdded">
<button (click)="removeCicked($event)">remove</button>
</div>
addCicked(event){
this.isNewRowAdded = true;
}
removeCicked(event){
alert('Remove Clicked')
}
And if you really want to manipulate DOM directly you can use ElementRef for that!

Angular - How to reuse a component in a different level?

Imagine we have this component structure:
app1
-- app1.component.html
-- app1.component.ts
parent1
parent2
app2
-- app2.component.html
-- app2.component.ts
How could I reuse the app2 component in the app1? For example, reuse a table (both HTML and logic on typescript) instead of copy and paste code.
I have searched for solutions like ng-template, but failed. Also, call the tag didn't work as well.
If the tag didn't work inside app1 I assume that you are importing app2 component inside another module. If we want to use component over multiple modules you need to import app2 ONLY in shared module then import that module to modules where you want to have that component.
Make sure to export that component inside shared module.
Need to use componentFactoryResolver https://angular.io/guide/dynamic-component-loader
For example you want to use ThirdComponent inside FirstComponent
//HTML
<section #firstComp></section>
//TS
import { AfterViewInit, Component, ComponentFactoryResolver, OnInit, ViewChild, ViewContainerRef } from '#angular/core';
import { ThirdComponent } from '../third/third.component';
#Component({
selector: 'app-first',
templateUrl: './first.component.html',
styleUrls: ['./first.component.scss']
})
export class FirstComponent implements OnInit, AfterViewInit {
#ViewChild('firstComp',{read: ViewContainerRef}) firstComp: ViewContainerRef;
constructor(
private componentFactoryResolver: ComponentFactoryResolver
) { }
ngOnInit(): void {
}
ngAfterViewInit() {
const componentFactory = this.componentFactoryResolver.resolveComponentFactory(ThirdComponent);
const componentRef = this.firstComp.createComponent<ThirdComponent>(componentFactory);
}
}

Angular wrapper of JS library doesn't load styles

I want to use this library https://bootstrap-datepicker.readthedocs.io/en/latest/markup.html#date-range in my application. But it has to be angular component so for the first time in my short career I wanted to create wrapper of library but I think I did something wrong becouse It doesn't looke like original picker.
This is how it should looks like:
And this is how it looks like as my angular component:
Also when I want to select only month or year it looks weird:
Ok so now time to see my component code:
import {AfterViewInit, Component, ElementRef, Input, OnInit} from
'#angular/core';
import 'bootstrap-datepicker';
declare var $;
#Component({
selector: 'cb-daterangepicker',
templateUrl: './daterangepicker.component.html',
styleUrls: ['./daterangepicker.component.scss']
})
export class DaterangepickerComponent implements OnInit, AfterViewInit {
#Input()
datepickerOptions: DatepickerOptions;
constructor(private elementRef: ElementRef) {
}
ngOnInit() {
}
ngAfterViewInit(): void {
// $(this.elementRef.nativeElement).datepicker();
$('.input-daterange input').each(function() {
$(this).datepicker('clearDates');
});
}
}
As You see there is no for example selection of range, or just start and end dates, it simply looks different so I thought it becouse not loaded styles but I might be wrong. I need Your help Guys, maybe my wrapper isn't correctly done?
*Network console with styles:
Addin styles to index.html and angular.json helped with some things:
But still range between dates is not highlighted..
Are you sure that bootstrap is correctly loaded ? you have to check this first and you have to check if the css for the library is loaded afterwards.
try to check that with the browser network console :)
othewise try to call the library style with the cdn :
https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.8.0/css/bootstrap-datepicker.min.css

How to use composition instead of inheritance when sharing logic between components in Angular 6?

I have a module in Angular that is structured likes this:
moduleName
componentA
componentB
Now componentA and componentB are very similar, as they share some attributes and methods, e.g.:
protected available: boolean = true;
As I don't want to repeat myself, I've created a base class, that stores all this:
export abstract class BaseComponent {
protected available: boolean = true;
}
And both controllers inherit from that class:
import { BaseComponent } from '../base.component';
export class ComponentA extends BaseComponent implements OnInit {
constructor() {
super();
}
ngOnInit() {
console.log(this.available);
}
}
This works just fine. However, when I research this soultion a lot of people are saying:
Don't use inheritance, use composition in this case.
Alright, but how can I use composition instead? And is the gain really that big over the current solution?
Thanks a lot for your time.
For composing objects in angular you need to have a reference to that object inside of your class, which shares data and functionality. To do that you need to use Angular services, and inject them to your class, and there should be 1 instance of service per component.
Create a new service by running ng g s my-service, remove providedIn: 'root' from your service annotation (We want to provide instance per component)
Add public available: boolean = true; to the service
provide the service through the components, in #Component configs on your components
inject the service in your both component constructors, constructor(private myService:MyService)
Now you have a composition that keeps data and functionality
#Component({
selector: 'app',
templateUrl: './app.my-component.html',
styleUrls: ['./app.my-component.css'],
providers: [MyService]
})
export class MyComponent {
constructor(private myService: MyService) {
}
}
If you create same components with big part same logic. you can use inheritance for example controlSelectComponent and controlInputComponent stackblitz example
For composition you need to create service and provide it to both components. But you dont keep component state in service becose all service are singletone. And when one component change state another component crash.
You also can provide service to each component in providers section
#Component({
selector: 'app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
providers: [MyService]
})
export class AppComponent {
constructor(private myService: MyService) {
}
}
But in case with saving state in service is not the best solution
Conclusion
Use services and composition for share helper methods between components.
Use abstract class and inheritance for components with same logic and state changes.
I would also recommend to read about Composition over Inheritance. The syntax(InversifyJs) is very similar that Angular uses. Please see this blog

Injecting angular1 service in angular2 directive

I'm reading lots of articles on this matter like this, and this and also this but each one of these articles starts from a situation in which the NG1 service is a class and can be exported.
I'm in a very different situation, i often have multiple services in the same file and they are defined in a very old style manner like
angular.module('App.services').factory('SessionService',
function() {
var defer = $q.defer();
[...]
}
);
No class, no export.
And this stuff is directly linked in the page with an old fashioned <script src="...">
At the same time i'm trying to create new directives in Angular2 and these directives need those old fashioned services.
I get i should be able to write something like this
import {Injector,Component, Directive, ElementRef, Input, View} from 'angular2/core';
var injector = Injector.resolveAndCreate([
SessionService
]);
var SessionService = injector.get(SessionService);
#Component({
selector: 'nav-bar'
})
#View({
templateUrl: '/app/components/navbar/navBar.html'
})
export class navBar {
constructor() {
}
}
but of course SessionService object is not found.
How can i get out of this mess?
[Additional Info]
Using babel as transpiler
angular2-annotations plugin added
A great article to understand the difference between Annotations and Decorators in angular2: http://blog.thoughtram.io/angular/2015/05/03/the-difference-between-annotations-and-decorators.html
You simply need to leverage #Inject:
#Component({
selector: 'nav-bar'
templateUrl: '/app/components/navbar/navBar.html'
})
export class navBar {
constructor(private #Inject('SessionService') sessionService) {
}
}
See this plunkr for more details: http://plnkr.co/edit/U6ygjUUQ04mTGAAaC1pZ?p=preview
You can notice that with factory you can't use classes. It's only possible with services...
If you use ES6 only, you could try this:
#Component({
selector: 'nav-bar'
templateUrl: '/app/components/navbar/navBar.html'
})
export class navBar {
constructor(sessionService) {
}
static get parameters() {
return [[ new Inject('...'), new Inject('...') ]];
}
}

Categories

Resources