Angular 2 Inheritance components - asp.net

I have a basewindow.component which will be the base component for all my components. This basewindow.component will be having buttons like save, delete etc and while clicking "New" button I would like to call basewindow function ufbNew() after executing it should execute parent window function ufNew(). Please check my code and help me whether I'm doing it correctly. I'm able to call base function but parent not
//basewindow.component///
import { Component } from '#angular/core';
#Component({
selector: 'basewindow',
templateUrl: './Basewindow.component.html',
styleUrls: ['./Basewindow.component.css']
})
export class BasewindowComponent {
/////////////////////// User Base Functions ///////////////////
ufbNew() {
this.ufNew();
}
ufbSave() {
this.ufSave();
}
/////////////////////// User Functions for parent ///////////////////
ufNew() {
alert("I m In Base ufbNew")
}
ufSave() {
}
}
//// Basewindow.component.html
<div class="container">
<h1>Hero Form</h1>
<form>
<div class="form-group">
<button (click)="ufbNew()">New</button>
<button (click)="ufbSave()">Save</button>
</div>
</form>
</div>
/////////////////////////// AccountsCategory.Component (Parent 1) ////
import { Component } from '#angular/core';
import { BasewindowComponent } from '../base/basewindow.component';
#Component({
selector: 'app',
templateUrl: './AccountsCategory.component.html'
})
export class AccountsCategory extends BasewindowComponent {
/////////////////////// User Functions for parent ///////////////////
ufNew() {
alert("I m in Acounts category (parent)")
}
ufSave() {
}
}
//////////// AccountsCategory.component.html /////////////
<basewindow> </basewindow>
my purpose is to reuse base component objects , functions and override from child if requires.
please see test application in plnkr
https://plnkr.co/edit/bVxt4GjNXwIg7pDbR4sE?p=preview

Use this
abstract class Animal {
//OTHER STUFF
abstract ufSave(): void;
//OTHER STUFF
}

Related

Imported angular module doesn't work the first time a route is visited, but it works in the subsequent visits

I have a simple Loader Module hosted in a private npm repository. This module only intercepts http calls and displays a css loader. The code is simple: it has a public api that exports the module and a component. The module has an http interceptor that calls a service which sets a variable isLoading.
The component code is split into three files, as usual (ts, html and scss).
loader.component.ts
import { Component, OnInit, AfterViewInit } from '#angular/core';
import { LoaderService } from '../service/loader.service';
#Component({
selector: 'loader',
templateUrl: './loader.component.html',
styleUrls: ['./loader.component.scss']
})
export class LoaderComponent implements OnInit {
public isLoading: boolean;
constructor(private loaderService: LoaderService) { }
ngOnInit(){
this.loaderService.isLoading.subscribe(status => this.isLoading = status);
}
}
loader.component.html
<div *ngIf="isLoading" class="overlay">
<div class="loader center-block"></div>
<p class="wait">
<strong>Wait... </strong>
</p>
</div>
The loader.component.scss file defines the loader, overlay and wait css classes (not shown for brevity).
The interceptor code is here:
#Injectable()
export class LoaderInterceptor implements HttpInterceptor {
constructor(private loaderService: LoaderService) {}
intercept(
request: HttpRequest<unknown>,
next: HttpHandler
): Observable<HttpEvent<any>> {
this.loaderService.show();
return next.handle(request).pipe(finalize(() => this.loaderService.hide()));
}
}
And finally, the service code:
import { Injectable } from '#angular/core';
import { Subject } from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class LoaderService {
public isLoading: Subject<boolean>;
constructor() {
this.isLoading = new Subject<boolean>();
}
show() {
this.isLoading.next(true);
}
hide() {
this.isLoading.next(false);
}
}
This module is imported at the app.module.ts of an application and declared in the imports array of the decorator.
The application has some routes with lazy load feature modules.
The loader module is used at the app.component.html file, as follows:
<loader></loader>
<router-outlet></router-outlet>
The problem: the loader does not work the first time we visit a route, but it works if we click the previous button at the browser or we click to go back to homepage or any other way I tested visiting a route twice or more. Otherwise, it doesn't work.
I tried to find similar questions, I tried to see the order of css imports, I also tried to analise the loader module, the import order, but no clue about what is happening.

Angular Dynamic Components - Add Class and other attributes

I am using the following code for creating the dynamic components
import {
Component, OnInit, ViewContainerRef, ViewChild, ViewChildren,
ReflectiveInjector, ComponentFactoryResolver, ViewEncapsulation, QueryList, Input, AfterViewInit
} from '#angular/core';
import { Router, ActivatedRoute } from '#angular/router';
import { forEach } from '#angular/router/src/utils/collection';
import { IComponent } from 'app/app.icomponent';
#Component({
encapsulation: ViewEncapsulation.None,
selector: 'dynamic-component',
entryComponents: [HomeComponent, HighlevelSignalComponent],
template: `
<div #dynamicDiv [ngClass]="classFromMenu" >
<ng-template #dynamicComponentContainer></ng-template>
</div>
`,
styleUrls: [
'./dynamic-content.component.css'
],
})
export class DynamicComponent implements IComponent, OnInit, AfterViewInit {
classFromMenu: any;
#ViewChild('dynamicComponentContainer', { read: ViewContainerRef }) dynamicComponentContainer: ViewContainerRef;
constructor(private resolver: ComponentFactoryResolver, private route: Router,
private activatedRoute: ActivatedRoute, ) {
}
.......
buildComponent(passedData) {
// orderAndObjs has the data for creating the component
this.orderAndObjs.forEach(obj => {
var componentFactory = this.resolver.resolveComponentFactory(obj.component);
var compRef = this.dynamicComponentContainer.createComponent(componentFactory);
// compRef is the component that is created.
//Assuming the component that i am trying to create is <dynamic-component>.
//I want to add either a class or any other attribute like this
//<dynamic-component class="flex">
});
}
}
}
The dynamic-component is created perfectly fine and everything is working as expected. But the only issue is I want to add a class for dynamic-component so that it can be
<dynamic-component class="dynamicClass">
Any help is appreciated :(
Hmm.. I usually add it to the selector of component that is supposed to be an entryComponent ...
selector: 'dynamic-component.someclass',
^^^^^^^^^^^
to add attribute use attribute selector:
selector: 'dynamic-component[myattr=value]',
I call it hidden feature of entryComponents
but its declarative approach and can't be changed at runtime(indeed we can change it)
In Angular 5/6, using Renderer2 from #angular/core, you can do something like below:
constructor(private resolver: ComponentFactoryResolver, private route: Router,
private activatedRoute: ActivatedRoute, private renderer2: Renderer2) {
}
buildComponent(passedData) {
this.orderAndObjs.forEach(obj => {
var componentFactory = this.resolver.resolveComponentFactory(obj.component);
var compRef = this.dynamicComponentContainer.createComponent(componentFactory);
this.renderer2.addClass(compRef.location.nativeElement, 'flex');
});
}
High-level DOM operations are performed with Renderer2 provider. Considering that it was injected, it is:
this.renderer2.addClass(compRef.location.nativeElement, 'dynamicClass');
It should be noticed that depending on how dynamic element is attached to DOM, this may be unnecessary complication.
Considering that dynamicComponentContainer is real DOM element and not <ng-template>, the view of dynamic component can be directly mounted to the container, thus eliminating <dynamic-component> wrapper element:
Given the container:
<div class="dynamicClass" #dynamicComponentContainer></div>
It will be:
var compRef = componentFactory.create(
this.injector,
[],
this.dynamicComponentContainer.element.nativeElement
);

Angular2 communication between 2 components

i am using Angular2 rc5 and i try to build a component communication through a service.
For arrays it works like expected but if i change a string its not updating.
My main component looks like:
import {Component} from '#angular/core';
import {ShareServiceService} from "../share-service.service";
import {ChildTwoComponent} from "../child-two/child-two.component";
import {ChildOneComponent} from "../child-one/child-one.component";
#Component({
selector: 'parent',
template: `
<h1>Parent</h1>
<div>
<child-one></child-one>
<child-two></child-two>
</div>
`,
providers: [ShareServiceService],
directives: [ChildOneComponent, ChildTwoComponent]
})
export class ParentComponent {
constructor() {}
}
My first children component:
import {Component} from '#angular/core';
import {ShareServiceService} from "../share-service.service";
#Component({
selector: 'child-one',
template: `
<div style="float:right; width: 45%">
<pre>title: {{title}}</pre>
<pre>title: {{_sharedService.testTitle}}</pre>
<div>
<ul *ngFor="let dataElement of data">
<li>{{dataElement}}</li>
</ul>
</div>
</div>
`
})
export class ChildOneComponent{
data:string[] = [];
title:string;
constructor(public _sharedService:ShareServiceService) {
this.data = this._sharedService.dataArray;
this.title = this._sharedService.testTitle;
}
}
The second children component:
import {Component} from '#angular/core';
import {ShareServiceService} from "../share-service.service";
#Component({
selector: 'child-two',
template: `
<div style="float:left; width: 45%">
<pre>title: {{title}}</pre>
<pre>titleObj: {{titleObj.title}}</pre>
<div>
<ul *ngFor="let dataElement of data">
<li>{{dataElement}}</li>
</ul>
</div>
<input type="text" [(ngModel)]="dataInput"/>
<button (click)="addData()">addData</button>
<button (click)="updateTitle()">updateTitle</button>
</div>
`
})
export class ChildTwoComponent {
dataInput:string = 'Testing data';
data:string[] = [];
title:string;
constructor(public _sharedService:ShareServiceService) {
this.data = this._sharedService.dataArray;
this.title = this._sharedService.testTitle;
}
addData() {
this._sharedService.insertData(this.dataInput);
this.dataInput = '';
}
updateTitle() {
this._sharedService.updateTestTitle(this.dataInput);
this.dataInput = '';
}
}
My service:
import {Injectable} from '#angular/core';
#Injectable()
export class ShareServiceService {
dataArray:string[] = [];
testTitle:string = "should be updated";
insertData(data:string) {
this.dataArray.push(data);
}
updateTestTitle(newTitle:string) {
this.testTitle = {title: newTitle};
}
}
What i try to achieve is, that if i enter something in the input field with binding for "" and press the "updateTitle" that the Title in both components are updated.
But thats doesnt work currently.
if i add my input value to an array, by clicking the "adddata" Button, all works like excepted and my list with data elements shows all elements.
Does someone know why i cant update a string?
Thanks in advance!
If you copy an object or array you copy a reference. Both (source and destination) point to the same object. If one side modifies the object the other side sees the modification.
If you copy a primitive value (string, number, boolean), the the destination gets a copy of the value and source and destination aren't related in any way.
// copies a reference
this.data = this._sharedService.dataArray;
// copies the value
this.title = this._sharedService.testTitle;
What you probably want is an observable that emits events when properties in the shared service are modified.
For more details see https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#bidirectional-service

Angular 2 two-way component binding doesn't call parent ngOnChange

I have created a plunker here:
http://plnkr.co/edit/8bwqkYQ6tqrpGwHT588y?p=preview
that shows the issue.
Basically, I have 2 components. The first component has a 2-way binding of a property to the child component.
My parent component is:
import { Component, Input, Output, EventEmitter } from '#angular/core'
import { ChildComponent } from "./childComponent"
#Component({
selector: 'parentComponent',
template: `
<div>
Reset<br>
<div>Parent SelectedId: {{selectedId}}</div>
<childComponent [(selectedId)]="selectedId"></childComponent>
</div>
`,
directives: [ChildComponent]
})
export class ParentComponent {
#Input() selectedId: number;
ngOnChanges(changes) {
console.log("Parent changes called!");
}
}
and my child component:
import { Component, Input, Output, EventEmitter } from '#angular/core'
#Component({
selector: 'childComponent',
template: `
<div>
<div>Child SelectedId: {{selectedId}}</div>
</div>
`,
directives: []
})
export class ChildComponent {
#Input() selectedId: number;
#Output() selectedIdChange: EventEmitter<number> = new EventEmitter<number>();
constructor() {
setTimeout(() => {
this.selectedId = 100;
this.selectedIdChange.emit(this.selectedId);
}, 2000);
}
ngOnChanges(changes) {
console.log("Child changes called!");
}
}
In the child, I set a timeout to change the value of selectedId programmatically after 2 seconds, then emit the value back to the parent.
This all works great, except for one thing... the ngOnChange of the parent is only being called once.
I would think that the parent would very much like to know if the child has changed the value, or else what is the point of 2 way binding??
What am I missing here?
The ngOnChange of the parent will only be called if App's selectedId changes, since that's what ParentComponent's input property is bound to.
If you want the parent to be notified of changes made in the child, bind to the xChange event (where x is the name of the input property) – i.e., break up the property and event bindings:
<childComponent [selectedId]="selectedId" (selectedIdChange)="changed($event)"></childComponent>
changed(newValue) {
console.log('newValue', newValue);
this.selectedId = newValue;
}
Plunker

Binding is not working in Angular2 template

errorType is not showing when calling with Alert.showAlert("success","someMsg");from another Component but it's working when initializing at the declaration of errorType itself.
component :
import {Component} from 'angular2/core';
#Component({
selector: 'alert-component',
templateUrl: 'app/alert.template.html'
})
export class Alert {
public static errorType:string;
public static messageAlrt:string;
public static showAlert(type:string, message:string): void{
Alert.errorType=type;
}
}
template :
<div id="messageAlert" >
<strong>{{errorType}}:</strong> this is the error message at top of the page
</div>
Really apreciate your help in resolving this problem that errrorType value is not getting bound to erroType
It's because you use static fields. When using {{errorType}}, a non static property of the component is used.
I would refactor your component this way:
import {Component} from 'angular2/core';
#Component({
selector: 'alert-component',
templateUrl: 'app/alert.template.html'
})
export class Alert {
public errorType:string;
public messageAlrt:string;
}
When you want to display your alert, I would add it dynamically:
#Component({
(...)
template: `<div #target></div>`
})
export class SomeComponent {
#ViewChild('target', {read: ViewContainerRef}) target;
showAlert(type:string, message:string) {
this.resolver.resolveComponent(Alert).then(
(factory:ComponentFactory<any>) => {
this.cmpRef = this.target.createComponent(factory);
this.cmpRef.type = type;
}
);
}
See this great Günter's answer:
Angular 2 dynamic tabs with user-click chosen components

Resources