Angular2 call function from another component - javascript

I have two components: NgbdAlertCloseable and AlertCtrl. Also I have AppComponent as parent component. What I want is to click a button in AlertCtrl component and create the alert on NgdbAlertCloseable component.
addSuccess() function adds an alert to the view and it worked well while I call it inside of its component. However, I tried to use an EventEmitter to call this function from another component (as suggested here: https://stackoverflow.com/a/37587862/5291422) but it gives this error:
ORIGINAL EXCEPTION: TypeError: self._NgbdAlertCloseable_2_4.addSuccess is not a function
Here are my files:
ngbd-alert-closeable.component.ts
import { Input, Component } from '#angular/core';
#Component({
selector: 'ngbd-alert-closeable',
templateUrl: './app/alert-closeable.html'
})
export class NgbdAlertCloseable {
#Input()
public alerts: Array<IAlert> = [];
private backup: Array<IAlert>;
private index: number;
constructor() {
this.index = 1;
}
public closeAlert(alert: IAlert) {
const index: number = this.alerts.indexOf(alert);
this.alerts.splice(index, 1);
}
public static addSuccess(alert: IAlert) {
this.alerts.push({
id: this.index,
type: 'success',
message: 'This is an success alert',
});
this.index += 1;
}
public addInfo(alert: IAlert) {
this.alerts.push({
id: this.index,
type: 'info',
message: 'This is an info alert',
});
this.index += 1;
}
}
interface IAlert {
id: number;
type: string;
message: string;
}
alert-ctrl.component.ts
import { EventEmitter, Output, Component } from '#angular/core';
import { NgbdAlertCloseable } from './ngbd-alert-closeable.component';
#Component({
selector: 'alert-ctrl',
template: '<button class="btn btn-success" (click)="addSuccessMsg()">Add</button>'
})
export class AlertCtrl {
#Output() msgEvent = new EventEmitter();
public addSuccessMsg(){
this.msgEvent.emit(null);
}
}
app.component.ts
import { Component } from '#angular/core';
#Component({
selector: 'my-app',
template: '<div class="col-sm-4"><alert-ctrl (msgEvent)="ngbdalertcloseable.addSuccess()"></alert-ctrl><ngbd-alert-closeable #ngbdalertcloseable></ngbd-alert-closeable>'
})
export class AppComponent { }
Am I using it wrong? How can I fix that?

Check that the addSuccess function is static and is using non static properties.
Should be:
public addSuccess(alert: IAlert) {
this.alerts.push({
id: this.index,
type: 'success',
message: 'This is an success alert',
});
this.index += 1;
}
And in your view you must pass the IAlert value in this example we'll send that value when we call msgEvent.emit(IAlert).
import { Component } from '#angular/core';
#Component({
selector: 'my-app',
template: '<div class="col-sm-4"><alert-ctrl (msgEvent)="ngbdalertcloseable.addSuccess($event)"></alert-ctrl><ngbd-alert-closeable #ngbdalertcloseable></ngbd-alert-closeable>'
})
export class AppComponent { }
Then you must send that IAlert, I'll change your AlertCtrl just for demo purpose.
import { EventEmitter, Output, Component } from '#angular/core';
import { NgbdAlertCloseable } from './ngbd-alert-closeable.component';
#Component({
selector: 'alert-ctrl',
template: '<button class="btn btn-success" (click)="addSuccessMsg()">Add</button>'
})
export class AlertCtrl {
currentAlert:IAlert = {id: 0, type: 'success', message: 'This is an success alert'};
#Output() msgEvent = new EventEmitter<IAlert>();
public addSuccessMsg(){
this.msgEvent.emit(this.currentAlert);
}
}
Good luck and happy coding!

Related

Angular does not rerender on Input() change

Whatever i do angular does not detect change on talks array. I have a handleSubmit function to send the toolbar. Toolbar use it to send the changes to parent from input field.
My app.component.ts file
import { Component, Type, OnChanges, SimpleChanges } from '#angular/core';
import { getResponse } from '../api/API';
declare module '../api/API' {
export interface NlpAPI {
getResponse(data: any): Promise<any>;
}
}
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent implements OnChanges {
talks: string[];
title: string;
ngOnChanges(changes: SimpleChanges): void {
console.log(changes);
}
constructor() {
this.talks = [];
this.title = 'Talks';
}
ngOnInit() {
this.talks.push('Welcome to ProjectX! How can I help you?');
this.talks.push('I am a chatbot. I can help you with your queries.');
}
handleSubmit(data: any): void {
this.talks.push(data.talk);
}
messageResponse() {
// #ts-ignore: Object is possibly 'null'.
const x = document.getElementById('txt').value;
// #ts-ignore: Object is possibly 'null'.
document.getElementById('output').innerHTML =
'Your message is ' + '"' + x + '"';
}
}
My app.component.html
<!-- Toolbar -->
<app-custom-toolbar [handleSubmit]="handleSubmit"></app-custom-toolbar>
<!-- Highlight Card -->
<app-text-area [talksFromUser]="talks" [title]="title"></app-text-area>
<!-- Bottombar -->
<router-outlet></router-outlet>
My text-area.component.ts file
import { Component, Input, OnChanges, SimpleChanges } from '#angular/core';
#Component({
selector: 'app-text-area',
templateUrl: './text-area.component.html',
styleUrls: ['./text-area.component.css'],
})
export class TextAreaComponent implements OnChanges {
#Input() talksFromUser: string[] = [];
#Input() title: string = '';
constructor() {}
ngOnChanges(changes: SimpleChanges): void {
console.log(changes);
}
}
My text-area.component.html
<div class="main-text-area">
<div *ngFor="let item of talksFromUser">{{ item }}</div>
</div>
custom-toolbar.component.ts file
import { Component, Input, OnInit } from '#angular/core';
import { NgForm } from '#angular/forms';
#Component({
selector: 'app-custom-toolbar',
templateUrl: './custom-toolbar.component.html',
styleUrls: ['./custom-toolbar.component.css'],
})
export class CustomToolbarComponent implements OnInit {
talks: string[] = [];
#Input() handleSubmit!: (args: any) => void;
constructor() {}
ngOnInit(): void {}
onSubmit(f: NgForm) {
this.handleSubmit(f.value);
f.resetForm();
}
}
I tried also
this.talks = [...this.talks, data.talk]
Thank you all.
There are two issues in your code:
First one, you are calling handleSubmit("string") (so data is a string), but you are pushing data.talk, which is undefined (so talks will be [undefined, undefined, ...]). To fix it, use data:
handleSubmit(data: any): void {
this.talks.push(data); // use "data" instead of "data.talk"
}
Second one, you are using a AppComponent method into CustomToolbarComponent class. You need to keep the this scope of AppComponent. Also, you should use arrow functions:
handleSubmit = (data: any): void => {
this.talks.push(data);
}

ERROR TypeError: Cannot read property 'first_name' of undefined

i get this error When i try to render the list to the view from a backend service,
am able to get the response data and log it to the console but it wont render on the view.
enter code here
import { Component, OnInit, Input } from '#angular/core';
import { StudentsService } from '../services/students.service';
import { Student } from '../interfaces/Student';
#Component({
selector: 'app-student',
templateUrl: './student.component.html',
styleUrls: ['./student.component.css'],
})
export class StudentComponent implements OnInit {
#Input() student: Student;
students: Student[];
constructor(private studentService: StudentsService) {}
ngOnInit() {
this.studentService.getStudents().subscribe((students) => {
(data) => {
this.students = data.json();
Array.of(this.students);
};
console.log(students);
});
}
}
export interface Student {
id: number;
first_name: string;
last_name: string;
date_of_birth: Date;
}
<div class="container mt-5">
<ul *ngFor="let student of students">
<li>{{student.first_name}}</li>
</ul>
</div>
(data) => {
this.students = data.json();
Array.of(this.students);
};
it shouldn't be a function. change it to something like this:
import { Component, OnInit, Input } from '#angular/core';
import { StudentsService } from '../services/students.service';
import { Student } from '../interfaces/Student';
#Component({
selector: 'app-student',
templateUrl: './student.component.html',
styleUrls: ['./student.component.css'],
})
export class StudentComponent implements OnInit {
#Input() student: Student;
students: Student[];
constructor(private studentService: StudentsService) {}
ngOnInit() {
this.studentService.getStudents().subscribe((students) => {
this.students = students; // students is response from server. if it is not Student[] you should map it to correct type.
});
}
}

How to show heading based on value in angular?

I am trying to change the title based on item._id .i stored item in component.
this is my html
<h1 mat-dialog-title>{{item._id ? "Update" : "Add"}} animal</h1>
below is my dialog-overview-example.ts
import {Component, Inject} from '#angular/core';
import {MatDialog, MatDialogRef, MAT_DIALOG_DATA} from '#angular/material';
/**
* #title Dialog Overview
*/
#Component({
selector: 'dialog-overview-example',
templateUrl: 'dialog-overview-example.html',
styleUrls: ['dialog-overview-example.css'],
})
export class DialogOverviewExample {
animal: string;
name: string;
item:string;
constructor(public dialog: MatDialog) {}
openDialog(): void {
item =[{"_id": "2","animal":"lion","weiht":"100"}];
let dialogRef = this.dialog.open(DialogOverviewExampleDialog, {
width: '250px',
data: { name: this.name, animal: this.animal,item: this.item }
});
dialogRef.afterClosed().subscribe(result => {
console.log('The dialog was closed');
this.animal = result;
});
}
}
#Component({
selector: 'dialog-overview-example-dialog',
templateUrl: 'dialog-overview-example-dialog.html',
})
export class DialogOverviewExampleDialog {
constructor(
public dialogRef: MatDialogRef<DialogOverviewExampleDialog>,
#Inject(MAT_DIALOG_DATA) public data: any) { }
onNoClick(): void {
this.dialogRef.close();
}
}
Demo
if _id is there in item heading should show update animal otherwise it should show Add animal in our case id already there in item so it should show update animal ..help me out
I could see that you have defined the item inside the component as an array. So you have to use the following code in HTML
<h1 mat-dialog-title>{{item[0]._id ? "Update" : "Add"}} animal</h1>

How to push data and detect changes in angular 2 + version?

In previous angular version we had $scope.apply to detect changes , So i below code i have data from detailService that is printed now i am pushing data to object its throwing error object property is undefined , what is correct approach in new angular version to push data to array and bind it to the dom ?
app.component.ts
import { Component, OnInit,Pipe, PipeTransform, EventEmitter, Output } from '#angular/core';
import { DetailService } from '../detail.service';
import { StreamService } from '../stream.service';
import { MatTableDataSource } from '#angular/material';
import {GtConfig} from '#angular-generic-table/core';
import { GenericTableComponent} from '#angular-generic-table/core';
import * as io from 'socket.io-client';
export interface Element {
ticketNum: number;
ticketOpened: number;
eventType: string;
riskIndex: string;
riskValue: number;
severity: string;
lastModifiedDate: number;
assetID: string;
}
#Component({
selector: 'app-detail',
templateUrl: './detail.component.html',
styleUrls: ['./detail.component.css'],
})
export class DetailComponent{
messageArray: any[];
message1:Object = {};
public secondConfigObject: GtConfig<any>;
constructor(private detailService: DetailService) {
this.secondConfigObject = {
settings: this.getBaseSettings(),
fields: this.getBaseFields(),
data: []
};
};
ngOnInit() {
this.detailService.currentMessage1.subscribe(message1 => {
console.log('eventINDetailComp',message1);
this.secondConfigObject.data.push(message1);
});
}
}
app.component.html
<div class="table-responsive">
<generic-table [gtClasses]="'table-hover'" #myCustomTable [gtSettings]="secondConfigObject.settings" [gtFields]="secondConfigObject.fields" [gtData]="secondConfigObject.data"></generic-table>
</div>
You should move the code from the constructor to the start of the ngOnInit() function so the data gets set once the page has been created, not during.
As for data binding, variables on the screen/html will automatically update when they are changed in the code behind

Closing angular material dialog box

Learning angular2 material. I have the modal finally opening. But issue is when I click out side of modal it closes (not desired result right now) but thats not the current issue. When I click cancel the modal is not closing and throwing error. If I keep the this.dialogRef.close() commented out the app builds but when clicking the close button the modal does not close. If i uncomment that line the application does not build.
Any suggetions or what am I missing for this to work properly?
Thanks
Troy
Here is my componet(s) code:
import { Component, OnInit, Inject } from '#angular/core';
import { IGame } from './game/game';
import { Game } from './models/game.model';
import { GameService } from './services/game-service';
import { FormControl } from '#angular/forms';
import { Observable } from 'rxjs/Observable';
import { MdSnackBar } from '#angular/material';
import { MdDialog, MdDialogRef, MD_DIALOG_DATA} from '#angular/material';
import 'rxjs/add/operator/startWith';
import 'rxjs/add/operator/map';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
title = 'app';
games: any[] = [ ];
selectedRow: Object;
setClickedRow: Function;
myControl: FormControl = new FormControl();
animal: string;
name: string;
girl: string;
options = [
'Football',
'Basketball',
'Baseball',
'Lacrosse',
'Volleyball'
];
filteredOptions: Observable<string[]>;
constructor(private _gameService: GameService,public snackBar: MdSnackBar,
public dialog: MdDialog) {
this.filteredOptions = this.myControl.valueChanges
.startWith(null)
.map(val => val ? this.filter(val) : this.options.slice());
}
filter(val: string): string[] {
return this.options.filter(option =>
option.toLowerCase().indexOf(val.toLowerCase()) === 0);
}
onSelect(game: Game): void {
this.selectedGame = game;
}
openSnackBar(message) {
this.snackBar.open(message,null, {
duration: 2000,
});
}
openDialog(): void {
let dialogRef = this.dialog.open(DialogDataExampleDialog, {
width: '250px',
data: {
animal: this.animal,
girl:this.girl
}
});
dialogRef.afterClosed().subscribe(result => {
this.animal = result;
this.girl = result;
console.log('The dialog was closed: ' + result.animal + ' ' +
result.girl);
});
}
ngOnInit() {
return this._gameService.getGames()
.subscribe(
(gameData) => this.games = gameData,
(error) => this.openSnackBar("Something broke!"),
()=> this.openSnackBar("Data loaded successfully")
);
}
}
#Component({
selector: 'dialog-data-example-dialog',
template: `
<div md-dialog-content>
<p>What's your favorite animal?</p>
<md-form-field>
<input mdInput tabindex="1" [(ngModel)]="data.animal">
</md-form-field>
<p>Whos's your favorite white girl</p>
<md-form-field>
<input mdInput tabindex="2" [(ngModel)]="data.girl">
</md-form-field>
</div>
<div md-dialog-actions>
<button md-button [md-dialog-close]="data" tabindex="2">Ok</button>
<button md-button (click)="onNoClick()" tabindex="-1">No Thanks</button>
</div>
`,
})
export class DialogDataExampleDialog {
constructor(dialogRef: MdDialogRef<DialogDataExampleDialog>,
#Inject(MD_DIALOG_DATA) public data: any) {}
onNoClick(): void {
/*this.dialogRef.close();*/
}
}

Categories

Resources