Pass boolean to another Angular component - javascript

I have two Angular components
results.table and results.query
I want to hide the table inside the results.table.component when the user clicks on the reset button within the results.query.component
Maybe I am doing this wrong with event emitter, or maybe there is a better way to do this
results.table HTML
<div *ngIf='results?.length>0'>
<table *ngIf="showResults" class='table'>
<tr>
<th>Result Name</th>
<th>Location</th>
</tr>
<tbody>
<ng-template ngFor let-results [ngForOf]='items' let-i="index">
<tr>
<td>
<span>{{result?.description}}</span>
</td>
<td>
<span>{{result?.location}}</span>
</td>
</tr>
</ng-template>
</tbody>
</table>
</div>
results.table TS
showResults: boolean = true;
showResults(event) {
console.log('this is not getting called')
if (event) {
this.showResults = false;
}
}
results.query HTML
<div class="panel-body">
<form (submit)="onSubmitClicked()">
<div class="row">
<div class="form-group col-md-12 col-xs-12">
<div class="col-xs-12 col-sm-3 col-md-3 col-lg-3">
<label class="col-md-12 col-xs-12 control-label no-margin no-padding">Location: </label>
<pg-radio-toggle-select class="col-md-12 col-xs-12 no-margin no-padding" name="locationChangeInput" [(ngModel)]="Location"
(selectedChanged)="onFilteringLocation($event)" [options]='locationOptions'>
</pg-radio-toggle-select>
</div>
<pg-inputfield name="description" class="col-xs-12 col-sm-3 col-md-3 col-lg-3" [(ngModel)]="paramsModel.description"
displaytext="Name:"></pg-inputfield>
</div>
</div>
<div>
<button type="reset" class="btnReset" (click)="reset()">Reset</button>
<button type="submit" name="btnSearch">Search</button>
</div>
</form>
</div>
results.query TS
import {Component, OnInit, EventEmitter, Output} from '#angular/core';
import * as _ from 'lodash';
import { LocationService } from '../location-service.service';
#Component({
selector: 'result-query',
templateUrl: './result-query.component.html',
styleUrls: ['./result-query.component.less'],
})
export class ResultQueryComponent implements OnInit {
#Output() showResults: EventEmitter<boolean> = new EventEmitter<boolean>();
constructor(
private LocationService: LocationService,
) {
this.reset();
}
ngOnInit() {
this.reset();
}
onSubmitClicked() {
console.log('test')
}
reset(): void {
console.log('I am the reset king');
this.showResults = false;
this.showResults.emit(true);
this.onSubmitClicked();
}
}

If two components does have a parent child relationship, you can use #Input() #Output() decorators.
4 Ways to share data between angular components
Component Interaction
Input Output Example
Parent Component
import { Component, OnInit, ViewEncapsulation } from '#angular/core';
import { Stephen } from '../stephen.model';
#Component({
selector: 'app-parent',
template: `
Hello, Mr. (or Ms.): {{ selectedName }}
`,
styleUrls: ['./parent.component.css'],
encapsulation: ViewEncapsulation.None
})
export class ParentComponent implements OnInit {
stephen: Stephen;
selectedName: string;
constructor() {
this.stephen = new Stephen();
this.selectedName = this.stephen.firstName;
}
ngOnInit() {
}
updateName(selectedName: string): void {
console.log('in parent');
this.selectedName = selectedName;
}
}
Child Component
import { Component, OnInit, ViewEncapsulation, Input, Output, EventEmitter } from '#angular/core';
import { Stephen } from '../../stephen.model';
#Component({
selector: 'app-child',
template: `
{{ stephen.firstName }}
{{ stephen.lastName }}
{{ stephen.fullName }}
`,
styleUrls: ['./child.component.css'],
encapsulation: ViewEncapsulation.None
})
export class ChildComponent implements OnInit {
#Input() stephen: Stephen;
#Output() onNameSelected: EventEmitter;
constructor() {
this.onNameSelected = new EventEmitter();
}
ngOnInit() {
}
clicked(name: string): void {
this.onNameSelected.emit(name);
}
}
Important - second solution
But in your case these 2 components don't seem to have a parent child relationship. If you want to share data between two components, you can create a share-able service. This service will contain and EventEmitter to which a component that needs latest change will subscribe in ngOnInit method and the component which will have latest data will call a function from this share-able service to emit that event.
share-able service
import { Injectable, Output, EventEmitter } from '#angular/core';
#Injectable({
providedIn: 'root'
})
export class MessengerService {
#Output() change: EventEmitter<any> = new EventEmitter();
sendData(data: any): any {
this.change.emit(data);
}
}
The component that want to know about this change will subscribe to this event in it the ngOnInit like this.
messengerService.change.subscribe(emitedValue => {
this.value = emitedValue;
});
The component that has the new change will call the sendData method is messenge / share-able service to post new data to the event subscribers whenever it is required.

I dont know if you forgot to write it in your question, but you should have a results.query Tag in your results.Table HTML, and call the output through it. Considering your selector is app-results-query, it would be like this:
results.table HTML
<app-results-query (showResults)="changeShowResults($event)"></app-results-query>
<table *ngIf="showResults">
//table stuff
</table>
results.table TS
showResults: boolean = true;
changeShowResults(event: boolean) {
console.log('this is not getting called')
if (event) {
this.showResults = false;
}
}

Related

Image does not show up with Angular ngx-translate

I am using ngx-translate with Angular. I want to change an image depending on the language used in the application. The thing is that I can´t change the image when I click a language. I have two languages 'en' and 'es'.
This is my 'header.component.html'. This is the component which has the menu of the application.
As you can see there is an 'updateSrc()' function in the click attribute.
<div class="select-box__current" tabindex="1">
<div class="select-box__value" (click)="useLanguage('es');updateSrc(second_url);">
<input class="select-box__input" type="radio" id="0" value="1" />
<p class="select-box__input-text">es</p>
</div>
<div class="select-box__value" (click)="useLanguage('en');updateSrc(first_url);">
<input class="select-box__input" type="radio" id="1" value="2" checked="checked"/>
<p class="select-box__input-text">en</p>
</div>
</div>
Also I have another component 'looker.component.html' where the image have to change.
<div class="map">
<img class="graph" src="{{first_url}}" alt="graph">
</div>
And this is my 'looker.component.ts' where I am not sure how to write the updateSrc() function in order to change the other URL when someone clicks one of the two languages.
import { Component, OnInit, PLATFORM_ID, Inject } from '#angular/core';
import { Meta, Title } from '#angular/platform-browser';
#Component({
selector: 'app-looker',
templateUrl: './looker.component.html',
styleUrls: ['./looker.component.scss']
})
export class LookerComponent implements OnInit {
first_url: string = "https://storage.googleapis.com/amarello-web-assets/img/graph_2.svg";
second_url: string = "https://storage.googleapis.com/amarello-web-assets/img/graph_1.svg";
constructor(
private title: Title,
private meta: Meta,
#Inject(PLATFORM_ID) private platformId: Object
) { }
ngOnInit(): void {
this.first_url;
}
updateSrc(url) {
}
}
You can use property binding on [src] which will take the value of the property first_url then on the change event just update the property as shown below!
html
<div class="map">
<img class="graph" [src]="first_url" alt="graph"> <!-- changed here -->
</div>
ts
import { Component, OnInit, PLATFORM_ID, Inject } from '#angular/core';
import { Meta, Title } from '#angular/platform-browser';
#Component({
selector: 'app-looker',
templateUrl: './looker.component.html',
styleUrls: ['./looker.component.scss']
})
export class LookerComponent implements OnInit {
first_url: string = "https://storage.googleapis.com/amarello-web-assets/img/graph_2.svg";
second_url: string = "https://storage.googleapis.com/amarello-web-assets/img/graph_1.svg";
constructor(
private title: Title,
private meta: Meta,
#Inject(PLATFORM_ID) private platformId: Object
) { }
ngOnInit(): void {
}
updateSrc(url) {
this.first_url = url; // <- changed here
}
}

How to update parent component view when data is fetched from child component?

I have a parent and a child component, the child component is actually a modal where we can enter emails and click on 'Add to List'.
The entered emails are then fetched from parent component using #ViewChild property. The array details are obtained in parent because I can console.log() and see them from parent.
But how do I update a part of view in Parent with this new data is received ?
The code and explanations are as below :
Child component :
"emails" is an array with email ids.
I am fetching this array from child.
import { Component, OnInit, ViewEncapsulation } from '#angular/core';
#Component({
selector: 'app-add-student-popup',
templateUrl: './add-student-popup.component.html',
styleUrls: ['./add-student-popup.component.scss']
})
export class AddStudentPopupComponent implements OnInit {
emails: string[] = [];
constructor() { }
ngOnInit(): void {
}
**** Some other code that adds user entered emails to an array 'emails' ****
----
----
sendData() {
console.log(this.emails);
}
}
Parent
import { AfterViewInit, Component, OnInit, ViewChild } from '#angular/core';
// Add students modal popup
import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal/';
import { AddStudentPopupComponent } from './add-student-popup/add-student-popup.component';
#Component({
selector: 'app-create-course',
templateUrl: './create-course.component.html',
styleUrls: ['./create-course.component.scss']
})
export class CreateCourseComponent implements OnInit, AfterViewInit {
bsModalRef!: BsModalRef;
emails: string[] = [];
isEmpty: boolean = true;
#ViewChild(AddStudentPopupComponent) addStudent!: AddStudentPopupComponent;
constructor(private modalService: BsModalService) { }
ngOnInit(): any {}
ngAfterViewInit(): void {
if (this.addStudent) {
this.emails = this.addStudent.emails;
isEmpty = false;
}
}
openAddStudentModal() {
this.bsModalRef = this.modalService.show(AddStudentPopupComponent, {class: 'modal-lg'});
this.bsModalRef.content.closeBtnName = 'Close';
}
}
I want to use the updated "emails" array in my front end view. The view part using this array should be updated.
View part
When the popup is filled and submitted the emails array is populated and it should update the this view part.
<div class="multipleInput-container" *ngIf="!isEmpty;else noEmails">
<div class="col-lg-12">
<ul *ngFor="let email of emails">
<li class="multipleInput-email">{{ email }}</li>
</ul>
</div>
</div>
<ng-template #noEmails>
<div class="col-lg-3">
<input type="text" class="form-control form-control-sm"
placeholder="No Students Added" aria-label="No Students Added">
</div>
</ng-template>
Thanks in Advance
You should use #Output
In AddStudentPopupComponent
emails: string[] = [];
#Output() sendEmail = new EventEmitter();
sendData() {
this.sendEmail.emit(this.emails);
}
then in create-course.component.html file
<app-add-student-popup (sendEmail)="emails = $event"></app-add-student-popup>

Is there a way to send a Bootstrap Datepicker value from one component to another?

I'm using Bootrap on my Angular Application and it is divided like this
This is my Datepicker.html file
<form class="form-inline">
<div class="form-group">
<div class="input-group">
<input class="form-control" placeholder="yyyy-mm-dd"
name="dp" [(ngModel)]="model" ngbDatepicker #d="ngbDatepicker">
<div class="input-group-append">
<button class="btn btn-outline-secondary calendar" (click)="d.toggle()" type="button"></button>
</div>
</div>
</div>
</form>
This is my Datepicker.ts file
import { Component, OnInit } from '#angular/core';
import {NgbDateStruct, NgbCalendar} from '#ng-bootstrap/ng-bootstrap';
#Component({
selector: 'ngbd-datepicker-basic',
templateUrl: './datepicker.component.html',
styleUrls: ['./datepicker.component.css']
})
export class DatepickerComponent implements OnInit {
model: NgbDateStruct;
date: {year: number, month: number};
constructor(private calendar: NgbCalendar) {
}
selectToday() {
this.model = this.calendar.getToday();
}
ngOnInit(): void {
}
}
And my goal is to get the selected date from my datepicker component and send it of to my dayoverview component
Dayoverview.ts
import { Component, OnInit } from '#angular/core';
import { ɵangular_packages_core_testing_testing_a } from '#angular/core/testing';
import { PATIENTS } from './dummypatientdata';
#Component({
selector: 'app-dayoverview',
templateUrl: './dayoverview.component.html',
styleUrls: ['./dayoverview.component.css']
})
export class DayoverviewComponent implements OnInit {
patients = PATIENTS;
constructor() { }
ngOnInit(): void {
}
}
The Datepicker is an child component of the day overview.
If Datepicker is a child component of Dayoverview component you should use an EventEmitter in the child component and bind to that in the parent component.
An example can be found in the Angular documentation:
https://angular.io/guide/component-interaction#parent-listens-for-child-event

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

How To show a modal dialog in angular, using w3.css as framework?

I have an angular NgFor that is creating a list of elements, I want to show a modal detail dialog about the clicked element, I m using w3.css as css framework, but I m not successfull
I tried to use the NgStyle with some input from parent to child, I strated using angular 4 days ago so I m not yet used to it logic, in the console logs I see that my click is firing but I dont know what is happening after
My code
List Component and Template
import { Component, OnInit, ChangeDetectorRef } from '#angular/core';
import { BreakPointService } from '../../providers/break-point.service';
import { ReactiveTwitterSpringService } from '../../reactive/reactive-twitter-spring.service';
import { ITweet } from '../../reactive/model/itweet';
import { Subscription, Subject } from 'rxjs';
#Component({
selector: 'app-tweet-list',
templateUrl: './tweet-list.component.html',
styleUrls: ['./tweet-list.component.css']
})
export class TweetListComponent implements OnInit {
list_div_class;
search_input_class;
selectedTweet: ITweet;
public search_results$ = new Subject<any>();
search_results: ITweet[] = new Array();
subscribe: Subscription = new Subscription();
constructor(private tweetService: ReactiveTwitterSpringService, private cdr: ChangeDetectorRef) { }
visible = 'none';
search(tag) {
this.search_results = new Array();
this.subscribe.unsubscribe();
this.subscribe = new Subscription();
this.search_results$ = new Subject<any>();
this.subscribe.add(this.tweetService.search(tag).subscribe(tweet => {
this.search_results.push(tweet);
this.search_results = this.search_results.slice();
this.cdr.detectChanges();
this.search_results$.next(this.search_results);
console.log(tweet);
}));
console.log('array contains ' + this.search_results);
}
setSelected(tweet) {
console.log('selecting and showing');
this.selectedTweet = tweet;
this.visible = 'block';
}
ngOnInit() {
BreakPointService.current_css.subscribe(value => {
console.log('value is ' + value);
this.setupCss(JSON.parse(value));
});
}
setupCss(value: any): any {
this.list_div_class = value.list_div_class;
this.search_input_class = value.search_input_class;
}
}
template
<div class="{{list_div_class}}" style="max-height: 100vh;">
<input type="text" class="{{search_input_class}}" (keyup.enter)="search(searchInput.value)" #searchInput>
<ul class="w3-ul w3-hoverable" style="overflow-x:auto;max-height:70vh;">
<li class="w3-bar w3-center" *ngFor="let tweet of search_results " (click)="setSelected(tweet)">
<img src="{{tweet.userImage}}" class="w3-bar-item w3-circle" style="width:100px;">
<div class="w3-bar-item">
<span class="w3-large">{{tweet.id.name}}</span>
<br>
<span>#{{tweet.tag}}</span>
</div>
</li>
</ul>
<app-tweet-detail [detail]="selectedTweet" [visible]="visible"></app-tweet-detail>
</div>
My detail component and template
import { Component, OnInit, Input } from '#angular/core';
import { ITweet } from '../../../../reactive/model/itweet';
#Component({
selector: 'app-tweet-detail',
templateUrl: './tweet-detail.component.html',
styleUrls: ['./tweet-detail.component.css']
})
export class TweetDetailComponent implements OnInit {
#Input() detail: ITweet = new ITweet();
#Input() visible = 'none';
constructor() { }
setInvisible() {
console.log('hidding');
this.visible = 'none';
}
ngOnInit() {
}
}
template
<div id="modal" class="w3-modal" [ngStyle]="{display: visible}">
<div class="w3-modal-content">
<div class="w3-container" *ngIf="detail">
<span (click)='setInvisible()' class="w3-button w3-display-topright">×</span>
<img src='{{detail.userImage}}' style='width: 250px;' />
<span class='w3-large'>{{detail.id.name}} {{detail.country}} {{detail.placeFullName}}</span>
<p>{{detail.id.text}}</p>
</div>
</div>
</div>
What should I do?
NB
In the w3.css tutorial they use the get element by id to change the visibility to none or block.
I guess what you need to do is have a two variables holding the listOfItems and a selectedItem where you will show on the modal. so for example
Component TS file
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit{
listOfItems: any[];
selectedItem: any;
ngOnInit() {
this.listOfItems = [
{
title: 'Title 1',
content: 'this is my first item'
},
{
title: 'Title 2',
content: 'this is my second item'
}
];
}
openModal( item ) {
this.selectedItem = item;
}
closeModal() {
this.selectedItem = undefined;
}
}
so we have openModal which assigns an item on the selectedItem variable for us to display the specific item and let the modal show, closeModal to revoke the value and make our modal hide again. so implementing this on the html looks like this.
Component HTML
<button *ngFor="let item of listOfItems; let i = index" (click)="openModal(item)" class="w3-button">Open item #{{ i }}</button>
<div *ngIf="selectedItem" class="w3-modal" [style.display]="selectedItem ? 'block' : 'none'">
<div class="w3-modal-content">
<div class="w3-container">
<span (click)="closeModal()" class="w3-button w3-display-topright">×</span>
<h1>{{ selectedItem.title }}</h1>
<p>{{ selectedItem.content }}</p>
</div>
</div>
</div>
So we have a button that loops thru the list of items and pass the item on the function so we could select which item to be shown. Then in the modal we try to check if selectedItem is defined, so if yes then the display will be visible and not otherwise.

Categories

Resources