Angular 5 passing object to a component - javascript

So i have created the following class:
export class PresentObject {
public type: string;
public resourceUrl: string;
public text: string;
}
And the following component:
import {Component, Input, OnInit} from '#angular/core';
import {PresentObject} from '../classes/present-object';
#Component({
selector: 'app-video',
templateUrl: './video.component.html',
styleUrls: ['./video.component.css']
})
export class VideoComponent implements OnInit {
#Input()
view: PresentObject;
constructor() {
}
ngOnInit() {
console.log(this.view.text);
}
}
Now I attempt to insert that through HTML:
<section *ngFor="let view of views; let last = last" [ngSwitch]="view.type">
<app-video *ngSwitchCase="'video'" view="{{view}}"></app-video>
<span *ngIf="last">{{repeatComplete()}}</span>
</section>
After debugging I can see if I console.log(this.view) i get: "[object Object]"
Can anyone tell me what I've done wrong?

<section *ngFor="let view of views; let last = last" [ngSwitch]="view.type">
<app-video *ngSwitchCase="'video'" view="view"></app-video>
<span *ngIf="last" (click)="repeatComplete()">LAST</span>
</section>

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);
}

Angular passing data to child component

Hey I am trying to display a simple error message on my login page if the login fails. Following is my login.component.html:
<div class="container shadow login-container">
<div class="row">
<div class="col-sm-12 text-center">
<div class="error-message">
<app-server-error [errorMessage]="error" ></app-server-error> -----> not displaying on screen
</div>
<div class="login-form-container">
<div class="login-input-container">
<input [(ngModel)]="user.email" type="email" placeholder="Enter your email" class="buddha-input"/>
</div>
<div class="login-input-container">
<input [(ngModel)]="user.password" type="password" placeholder="Enter password" class="buddha-input"/>
</div>
<div class="login-input-container">
<button (click)="tryLogin()" class="login-form-button">Login</button>
</div>
</div>
</div>
</div>
</div>
Following is my server-error.component.html:
<p>
{{errorMessage}}
</p>
Following is my server-error.component.ts
import { Component, OnInit, Input } from '#angular/core';
#Component({
selector: 'app-server-error',
templateUrl: './server-error.component.html',
styleUrls: ['./server-error.component.css']
})
export class ServerErrorComponent implements OnInit {
#Input() public errorMessage: string;
constructor() { }
ngOnInit() {
}
}
"Error" is not showing up on the screen and I am not getting errors on console either. Please do let me know how I can fix this? Thank you
#Input() public errorMessage: string; expects error to be a string.
Define error like this in .ts
error = 'error message'
Working Demo
With [errorMessage]="error", error should be a variable.
So you need to define it in your component.
But if you want to display the string "error",
then pass it like this [errorMessage]="'error'" or errorMessage="error"
The other posted answer may solve your problem but I would go with Service which will be responsible for showing an error from everywhere in the Application and also you can have a full control on the error component as it is centralized at a one place:
error.service:
import { Injectable } from '#angular/core';
import { BehaviorSubject } from 'rxjs';
#Injectable()
export class ErrorService {
constructor() { }
private errorMessages = new BehaviorSubject('');
errorMessage = this.errorMessages.asObservable();
showError(message: string) {
this.errorMessages.next(message)
}
}
Error.Component.ts:
import { Component, OnInit, Input } from '#angular/core';
import {ErrorService } from "../error.service";
#Component({
selector: 'app-server-error',
templateUrl: './server-error.component.html',
styleUrls: ['./server-error.component.css']
})
export class ServerErrorComponent implements OnInit {
private errorMessage : any;
constructor(public errorService : ErrorService) { }
ngOnInit() {
this.errorService.errorMessage.subscribe(value => {
this.errorMessage = value;
})
}
}
App.Component.html:
// show it in app.component
<div class="error-message">
<app-server-error></app-server-error>
</div>
Use (in Login Component):
import { Component, OnInit } from "#angular/core";
import {ErrorService } from "../error.service";
#Component({
selector: "app-login",
templateUrl: "./login.component.html",
styleUrls: ["./login.component.css"]
})
export class LoginComponent implements OnInit {
constructor(public errorService: ErrorService) {}
user = {};
ngOnInit() {}
tryLogin(){
this.errorService.showError('An error');
}
}

Toggle active/inactive class angular from different component

I have a parent component HeaderComponent with two children, NavComponent and BurgerComponent! At the momemnt there is a class that toggles the active inactive state of the burger when clicked on it! Below the first image when the burger is inactive, the second with active burger and NavComponent visible.
When clicked on the NavComponent area I have managed that the NavComponent closes.
The issue: The the NavComponent is closed by click on nav area, but I also need the burger to go to the inactive state(image 1).
What I have so far:
NavCompoent HTML with click event
<nav class="nav-menu {{ menuStatus }}" (click)="collapseMenu($event)">
NavComponent TS:
export class NavComponent implements OnInit {
title: string;
closeMenu: boolean;
#Output() sendTitle = new EventEmitter < string > ();
#Output() menuClose = new EventEmitter<any>();
#Input() menuStatus: boolean;
active = false;
constructor() {}
ngOnInit() {}
getText(event) {
this.title = event.target.innerText;
this.sendTitle.emit(this.title)
console.log("title sent", this.title);
}
collapseMenu($event) {
this.menuStatus = false;
this.menuClose.emit(this.menuStatus);
}
}
HeaderComponent HTML (this is the parent component)
<header class="sticky">
<div class="header-container">
<div class="header-left">
<h1>{{pageTitle}}</h1>
</div>
<div class="header-right">
<app-burger (opened)="burgerStatus($event)" [menuCloseBurger]="menuClose"></app-burger>
</div>
</div>
</header>
<app-nav (sendTitle)="getTitle($event)" [menuStatus]="burger" (menuClose)="sendingMenuClose($event)"></app-nav>
Header Component TS:
export class HeaderComponentComponent implements OnInit {
route: string;
pageTitle: string;
burger: string;
menuClose: string;
constructor(location: Location, router: Router) {
router.events.subscribe(val => {
this.pageTitle = location.path();
this.pageTitle = this.pageTitle.substring(1);
});
}
ngOnInit() {
this.pageTitle = this.route;
console.log(this.pageTitle);
}
getTitle($event) {
console.log(this.route);
this.pageTitle = $event;
}
burgerStatus($event) {
this.burger = $event;
console.log($event);
}
sendingMenuClose($event) {
this.menuClose = $event;
console.log("menu close at parent", this.menuClose);
}
}
BurgerComponent TS:
export class BurgerComponent implements OnInit {
active: boolean;
#Output() opened = new EventEmitter<any>();
#Input() menuCloseBurger: string;
constructor() { }
ngOnInit() {
this.active = false;
}
onBurgerClicked() {
this.active = !this.active;
this.opened.emit(this.active);
}
}
BurgerComponent HTML:
<div class="burger-menu" [class.active]="active" (click)="onBurgerClicked()">
<div class="burger-container">
<div class="burger-inner"></div>
</div>
</div>
collapseMenu() send a boolean value false, I need to get this into the BurgerCompnent class somehow so the value of that is false and the burger close. I am so close, I can't figure out the last step!
As per #PitchBlackCat's recommendation I have create a service NavStatusService!
import { Injectable } from '#angular/core';
import { EventEmitter } from '#angular/core';
#Injectable({
providedIn: 'root'
})
export class NavStatusService {
constructor() { }
public readonly isNavCollapsed$ = new EventEmitter<boolean>();
}
I have implemented it in the BurgerComponent:
onBurgerClicked() {
this.active = !this.active;
this.state.isNavCollapsed$.emit(this.active);
}
Now I am stuck as to how the communication between in the two component, Burger and Nav supposed to work!
You need a separate service to manage the shared variables.
You could try a framework like ngrx or create your own service along the lines of the example provided below.
Notice how the application-state.service has become the owner of the data that is shared between multiple components. This way, components that live in seperate parts of your layout can share data, whithout knowing about eachother.
application-state.service
export class ApplicationStateService implements OnInit {
public isNavCollapsed: boolean = false;
}
burger.component
<button class="burger" [class.active]="!state.isNavCollapsed" (click)="onBurgerClicked()">
</button>
import { Component, OnInit } from '#angular/core';
import { ApplicationStateService } from '../application-state.service';
#Component({
selector: 'app-burger',
templateUrl: './burger.component.html',
styleUrls: ['./burger.component.css']
})
export class BurgerComponent implements OnInit {
constructor(public state: ApplicationStateService) { }
ngOnInit() {
}
onBurgerClicked() {
this.state.isNavCollapsed = !this.state.isNavCollapsed;
}
}
nav.component
<ul *ngIf="!state.isNavCollapsed">
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
<li>
<button (click)="state.isNavCollapsed = true">close</button>
</li>
</ul>
import { Component, OnInit } from '#angular/core';
import { ApplicationStateService } from '../application-state.service';
#Component({
selector: 'app-nav',
templateUrl: './nav.component.html',
styleUrls: ['./nav.component.css']
})
export class NavComponent implements OnInit {
constructor(public state: ApplicationStateService) { }
ngOnInit() {
}
}
Check out this example on StackBlitz to see it in action

Angular 2 click event doesn't work

My have a web project and using angular 2 my different pages used click event don't have any problem but new page created then click event give a error in new page.
This Error
TypeError: self.parentView.parentView.context.changedItem is not a
function
at View_SiteConfig3.handleEvent_0 (/AppModule/SiteConfig/component.ngfactory.js:137)
at View_SiteConfig3.eval (core.umd.js:12399)
at HTMLTextAreaElement.eval (platform-browser.umd.js:3223)
at ZoneDelegate.invokeTask (zone.js:265)
at Object.onInvokeTask (core.umd.js:3971)
at ZoneDelegate.invokeTask (zone.js:264)
at Zone.runTask (zone.js:154)
at HTMLTextAreaElement.ZoneTask.invoke (zone.js:335)
site-config.html
<div *ngFor="let item of items1; let i = index;" class="col-sm-4">
<button (click)="changedItem(item)">Test</button>
</div>
site-config.ts
import { Component, OnInit } from '#angular/core'
import { Http } from '#angular/http'
#Component({
selector: 'site-config',
moduleId: module.id,
templateUrl: '/site-config.html'
})
export class SiteConfig implements OnInit {
items1: number[] = [1,2,3]
ngOnInit(): void {
}
public changedItem(item) {
//My Codes This Here
}
constructor(private http: Http) {
}
}
EDIT: Solved problem this method;
My project worked. Problem is ts file not compiled then give a "is not
a function" error
Maybe it's an error from a piece of code you don't provide.
I reproduce your code :
The view:
<pre *ngIf="current">{{current}}</pre>
<div *ngFor="let item of items1; let i = index;" class="col-sm-4">
<button (click)="changedItem(item)">Test</button>
</div>
The class content:
items1: number[] = [1,2,3]
current: number;
ngOnInit() {
}
public changedItem(item) {
this.current = item;
}
constructor() {
}
Here's a working Plunkr : https://plnkr.co/edit/ZGI1FNB8RWN9BnnPnKgJ?p=preview
Can you provide more code ?
Try this:
site-config.html
<div *ngFor="let item of items1; let i = index;" class="col-sm-4">
<button type="button" (click)="changedItem($event, item)">Test</button> <!-- add type="button" -->
</div>
site-config.ts
import { Component, OnInit } from '#angular/core'
import { Http } from '#angular/http'
#Component({
selector: 'site-config',
moduleId: module.id,
templateUrl: '/site-config.html'
})
export class SiteConfig implements OnInit {
items1: number[] = [1,2,3]
ngOnInit(): void {
}
public changedItem(event: any, item: number) {
event.preventDefault();
//Your code...
}
constructor(private http: Http) {
}
}

Access Angular 2 Inputs (properties) inside constructor

I'm creating some components in order to learn Angular2.
I have this basic html:
<h1>test</h1>
<btn [order]="0"></btn>
<btn [order]="1"></btn>
<btn [order]="2"></btn>
And in the ts I have this:
import {Component, Input} from 'angular2/core';
import {DataService} from '../services/DataService';
#Component({
selector: 'btn',
template: '<button>test{{ item }}</button>',
inputs: ['order']
})
export class ButtonComponent {
items: Array<number>;
item: number;
#Input() order;
constructor(dataService: DataService) {
console.log(this.order)
}
}
Doing that I get undefined, what am I doing wrong? how can I read the inputs (or an attribute) in order to send data to the class?
EDIT
import {Component, Input} from 'angular2/core';
import {DataService} from '../services/DataService';
#Component({
selector: 'btn',
template: '<button>test{{ item }}</button>',
inputs: ['order']
})
export class ButtonComponent {
items: Array<number>;
item: number;
#Input() order;
ngOnInit(dataService: DataService) {
this.items = dataService.getItems();
console.log(this.order)
}
constructor() {}
}
You can't access them in the constructor, they are not yet initialized. Use ngOnInit() instead. For more details see https://angular.io/docs/ts/latest/guide/lifecycle-hooks.html
export class ButtonComponent implements OnInit {
items: Array<number>;
item: number;
#Input() order;
constructor(dataService: DataService) { }
ngOnInit() {
console.log(this.order);
}
}

Categories

Resources