Pass index value of button to a popover component - html

I'm a beginner in angular and currently using angular 9 for my project.I have a component called play-game and it has a set of buttons.
play-game.component.html
<div class="container">
<div [formGroup]="seatsFormGroup">
<div formArrayName="seatsArray" *ngFor="let seat of seats;let idx = index" id="seat-{{idx}}" class="col-sm-4 ">
<label [ngbPopover]="popOver" popoverTitle="Pop title" class="table-player-seat-button" (click)="sit(idx)">{{seat.displayName? seat.displayName: "Sit "+ idx}}</label>
<ng-template #popOver>
<app-seat-modal></app-seat-modal>
</ng-template>
</div>
</div>
</div>
And I have a separate component for my popover as follows
seat-modal.component.html
<h4 class="modal-title">Seat{{seat}}</h4>
<button type="button" class="close" data-dismiss="modal" (click)="hide()">×</button>
<form [formGroup]="formRequestSeat" (submit)="join(seat)">
<div>
<button type="submit" class="button-request-seat">Request The Seat</button>
</div>
</form>
seat-modal.component.ts
import { Component, OnInit } from '#angular/core';
import {NgbModal, ModalDismissReasons} from '#ng-bootstrap/ng-bootstrap';
import {FormBuilder, FormGroup, Validators} from '#angular/forms';
import { SocketService} from '../../_services/socket.service';
import {AlertService} from '../../_services/alert.service';
import {ActivatedRoute, Router} from '#angular/router';
#Component({
selector: 'app-seat-modal',
templateUrl: './seat-modal.component.html',
styleUrls: ['./seat-modal.component.less']
})
export class SeatModalComponent implements OnInit {
formRequestSeat: FormGroup;
socket;
seat;
showModal: boolean;
screenName = '';
constructor(private socketService: SocketService,
private modalService: NgbModal,
private formBuilder: FormBuilder,
private alertService: AlertService,
private router: Router,
private activatedRoute: ActivatedRoute) { }
ngOnInit(){
this.formRequestSeat = this.formBuilder.group({
seatRequest: ['', Validators.required]
});
}
hide(){
this.modalService.dismissAll();
}
join(seat){
const self = this;
const tableToken = localStorage.getItem('tableToken');
const userToken = localStorage.getItem('userToken');
self.socket = self.socketService.init(userToken, tableToken);
self.socket.emit('join', {tableToken, seat}, (gameObject) => {
if (gameObject.error === null) {
self.alertService.success(gameObject.message, true);
}
else {
self.alertService.error(gameObject.message, true);
}
self.hide();
});
}
}
Earlier I have used a modal popup instead of popover. I could get the idx of the button to the popup modal but I have no idea how to pass idx to my popover.Please help

<div class="container">
<div [formGroup]="seatsFormGroup">
<div formArrayName="seatsArray" *ngFor="let seat of seats;let idx = index" id="seat-{{idx}}" class="col-sm-4 ">
<label [ngbPopover]="popOver" popoverTitle="Pop title" class="table-player-seat-button" (click)="sit(idx)">{{seat.displayName? seat.displayName: "Sit "+ idx}}</label>
<ng-template #popOver>
<app-seat-modal [btnIdx]="idx"></app-seat-modal>
</ng-template>
</div>
</div>
</div>
in app-seat-modal component
import { Component, OnInit } from '#angular/core';
import {NgbModal, ModalDismissReasons} from '#ng-bootstrap/ng-bootstrap';
import {FormBuilder, FormGroup, Validators} from '#angular/forms';
import { SocketService} from '../../_services/socket.service';
import {AlertService} from '../../_services/alert.service';
import {ActivatedRoute, Router} from '#angular/router';
#Component({
selector: 'app-seat-modal',
templateUrl: './seat-modal.component.html',
styleUrls: ['./seat-modal.component.less']
})
export class SeatModalComponent implements OnInit {
#Input() btnIdx : number;
formRequestSeat: FormGroup;
socket;
seat;
showModal: boolean;
screenName = '';
constructor(private socketService: SocketService,
private modalService: NgbModal,
private formBuilder: FormBuilder,
private alertService: AlertService,
private router: Router,
private activatedRoute: ActivatedRoute) { }
ngOnInit(){
this.formRequestSeat = this.formBuilder.group({
seatRequest: ['', Validators.required]
});
}
hide(){
this.modalService.dismissAll();
}
join(seat){
const self = this;
const tableToken = localStorage.getItem('tableToken');
const userToken = localStorage.getItem('userToken');
self.socket = self.socketService.init(userToken, tableToken);
self.socket.emit('join', {tableToken, seat}, (gameObject) => {
if (gameObject.error === null) {
self.alertService.success(gameObject.message, true);
}
else {
self.alertService.error(gameObject.message, true);
}
self.hide();
});
}
}

Related

Angular autocomplete is not working MySQL API

we tried Autocomplete in angular using codeigniter3 controller as a api. but it not reflected in the angular home page.
Autoserivce.ts
import { HttpClient } from '#angular/common/http';
import { Injectable } from '#angular/core';
#Injectable({
providedIn: 'root',
})
export class AutoService {
private baseURL = 'http://localhost/travelgate/api/item';
constructor(private http: HttpClient) {}
getData() {
return this.http.get(this.baseURL);
}
}
app.component.ts
import { Component, OnInit } from '#angular/core';
import { AutoService } from './auto.service';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent implements OnInit {
title = 'ng-auto-complete';
posts!: any;
name: any;
constructor(private service: AutoService) {}
ngOnInit() {
this.getAllData();
}
getAllData() {
this.service.getData().subscribe((res: any) => {
this.posts = res;
console.log(this.posts);
});
}
nameValue(name: any) {
this.name = name;
console.log(this.name);
}
}
app.Component.html
<div class="container">
<div class="row">
<div class="col-md-12">
<form class="form mt-5">
<label for="exampleDataList" class="form-label">Datalist example</label>
<input class="form-control" list="datalistOptions" id="exampleDataList" placeholder="Type to search..."
(change)="nameValue($any($event.target).value)">
<datalist id="datalistOptions">
<option *ngFor="let post of posts" [value]="post.name">
</datalist>
</form>
</div>
</div>
</div>
item.php
<?php
require APPPATH . 'libraries/REST_Controller.php';
class Item extends REST_Controller {
public function __construct() {
parent::__construct();
$this->load->database();
}
public function index_get($search = 0)
{
if(!empty($name)){
$this->db->select('*');
$this->db->from('rezlive_hotels_city_list');
$this->db->like('name', $name);
$data = $this->db->get()->result_array();
}else{
$query = $this->db->get("rezlive_hotels_city_list");
$resultList=$query->result_array();
$data= json_encode($resultList);
}
$this->response($data, REST_Controller::HTTP_OK);
}
}
screenshot

*ngFor a component but change source of image inside that component Angular

So I want to call a component multiple times with a *ngFor but inside each call I want each img to change their source attributes from a list of sources I have stored in child-component.ts
parent html
<app-thumbnail *ngFor="let video of video_ids;"></app-thumbnail>
child html
<div class="single-thumbnail-container">
<div class="separator"></div>
<img class="thumbnails" [ngClass]="{ selected: isSelected === true }"
[src]="thumbnails[index]" (click)="selectVideo()">
<div class="overlay"></div>
<div class="separator"></div>
</div>
parent TypeScript
import { Component, OnInit } from '#angular/core';
import { Pipe, PipeTransform } from '#angular/core';
import { DomSanitizer } from '#angular/platform-browser';
import { ThumbnailComponent } from './thumbnail/thumbnail.component';
#Component({
selector: 'app-youtube-videos',
templateUrl: './youtube-videos.component.html',
styleUrls: ['./youtube-videos.component.scss']
})
export class YoutubeVideosComponent implements OnInit {
url!: string;
video_ids!: string[];
ngOnInit() {
this.video_ids = ['xXOZiFmjSVE', 'i1QST3prI7Y', 'cgDZN44WpoE', 'tKD6yT9Jv-w', 'X6bXkv7Opg4', 'nVy0JdoLILU', 'vYH67L1x5qk', 'GReYTgrrdro', 'l9J9WcaI7b0', 'ieH1pPktlgg', 'oAAiRBGY-BI', 'SxKEB0MC3NE', 'fm4EP_tWmXs', 'MKHKu1krm1I', 'UgswO0nHsqA', 'wku7zvDDRk0', 'Qk13QMMHksc', 'httfJoffl9E', '0QcKISkrIaQ', 'KkN1son2i_c', 'CXIbfrwMRQI', 'VASpq7FU6Mo', 'SlBSwK_5xn8', '0o2kAz6cpxA', '00ff2UcGLu0', 'XO3UkRift0A', 'bThL2wlzEJc', 'OmnJpAppY9E', 'DCXfaSR8Ka8', '6dl_MEhdJqI', 'QS952qoqYLA', 'wp0IxPy32Ds'];
this.url = this.video_ids[0];
}
}
#Pipe({ name: 'safe' })
export class SafePipe implements PipeTransform {
constructor(private sanitizer: DomSanitizer) { }
transform(url) {
return this.sanitizer.bypassSecurityTrustResourceUrl("https://www.youtube-nocookie.com/embed/" + url);
}
}
child TypeScript
import { Component, OnInit } from '#angular/core';
import { YoutubeVideosComponent } from '../youtube-videos.component';
#Component({
selector: 'app-thumbnail',
templateUrl: './thumbnail.component.html',
styleUrls: ['./thumbnail.component.scss']
})
export class ThumbnailComponent implements OnInit {
thumbnails!: string[];
isSelected!: boolean;
youtubeVideosComponent!: YoutubeVideosComponent;
index!: number;
ngOnInit(){
this.thumbnails = [];
for (let i = 0; i < this.youtubeVideosComponent.video_ids.length; i++){ this.thumbnails.push("https://img.youtube.com/vi/" + this.youtubeVideosComponent.video_ids[i] + "/0.jpg") }
this.isSelected = false;
}
selectVideo(){
if (this.isSelected === false){
this.isSelected = true;
}
else {
this.isSelected = false;
}
}
}
Spent few hours trying to find a solution but didn't, thanks for helping me out!
You could add an #Input to your child component that will be passed by the parent
child.ts
#Component({...})
export class ThumbnailComponent implements OnInit {
#Input() videoId!: string;
getThumbnail(): string {
return `https://img.youtube.com/vi/${this.videoId}/0.jpg`;
}
...
...
}
child.html
<div class="single-thumbnail-container">
<div class="separator"></div>
<img
class="thumbnails"
[ngClass]="{ selected: isSelected === true }"
[src]="getThumbnail()"
(click)="selectVideo()">
<div class="overlay"></div>
<div class="separator"></div>
</div>
parent.html
<app-thumbnail
*ngFor="let video of video_ids"
[videoId]="video"
>
</app-thumbnail>

#viewChild and #ViewChildern gives undefined

I'm working on Angular 9 and want to access an input field after clicking on a button. right now it gives me undefined. I have tried #ViewChild and #viewChildern because I'm using ngIf.
Template.html file
<div class="search-input" #searchDiv *ngIf="serachActive">
<input
#searched
autofocus
type="text"
class="serach-term"
placeholder="Search"
[(ngModel)]="searchTerms"
(ngModelChange)="applySearch()"
/>
<button (click)="toggleSearch(!serachActive)">
<span class="material-icons"> search </span>
</button>
<ul class="search-list">
<li *ngFor="let result of results">
<a [routerLink]="['/', 'video', 'details', result._id]">{{
result.title ? result.title : ''
}}</a>
</li>
</ul>
</div>
Template.ts file
import { Component, OnInit,AfterViewInit,ElementRef,ViewChild,ViewChildren } from '#angular/core';
import { UserService } from '../../../user.service';
import { VideoService } from '../../../services/video.service';
import { Subject } from 'rxjs';
import { distinctUntilChanged, debounceTime } from 'rxjs/operators';
import { Router } from '#angular/router';
#Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.css'],
})
export class HeaderComponent implements OnInit,AfterViewInit{
serachActive: boolean = false;
#ViewChildren('searched') searchElement: ElementRef;
#ViewChildren("searched") input: ElementRef;
user;
subject = new Subject<string>();
results = [];
searchTerms;
loggedIn: Boolean = false;
constructor(
private userService: UserService,
private videoService: VideoService,
private router: Router
) {
this.user = this.userService.getUser();
this.loggedIn = this.userService.isAuthenticated();
}
ngOnInit() {
console.log('on init', this.input); //undefined
this.subject
.pipe(debounceTime(400), distinctUntilChanged())
.subscribe((value) => {
this.router.navigate(['search'], { queryParams: { term: value } });
});
}
ngAfterViewInit() {
console.log('on after', this.input); //undefined
}
toggleSearch(toggledata) {
this.serachActive = toggledata;
this.results = [];
this.searchTerms = '';
console.log(this.input) //undefined
console.log(this.searchElement.nativeElement) //undefined
}
applySearch() {
const searchText = this.searchTerms;
this.subject.next(searchText);
this.searchElement.nativeElement.focus(); //undefined
}
menuButtonClick(button){
if(button === "history"){
this.router.navigate(['history'])
}
}
}
Use ViewChild since you're only searching for 1 element ID.
If adding { static: true } or { static: false } in your ViewChild options doesn't work as what is stipulated on Angular Static Query Migration Documentation
Use ChangeDetectorRef instead:
#Component({...})
export class AppComponent {
#ViewChild('searchInput') input: ElementRef;
isShow: boolean = false;
constructor(private cdr: ChangeDetectorRef) {}
toggle(): void {
this.isShow = !this.isShow;
this.cdr.detectChanges(); // Detects changes which this.isShow is responsible on showing / hiding
// the element you're referencing to in ViewChild
if (this.isShow) // If element is shown, console the referenced element
console.log(this.input);
}
}
Have created a Stackblitz Demo for your reference

Angular service not passing form data after routing

New to Angular and I feel like there's just an obvious mistake I am missing, code-wise.
I'm trying to follow the tutorial here: https://youtu.be/CUAHJxWGia0
I have one component to create/add an employee's ID called CreateEmployee.
On submission, it should route to a component to list all employees (ListEmployees).
It's using employee.service.ts.
When I click submit (before or without routing), it correctly logs the employee input to the console on CreateEmployee.
The problem is that when routing to the second component, ListEmployees, my new entry is not displayed at all, and only my test data is displayed.
I've made sure EmployeeService is included in my app.module as well.
create-employee.ts:
import { Component, OnInit } from '#angular/core'
import { FormControl, FormBuilder, NgForm } from '#angular/forms'
import { EmployeeService } from 'app/services/employee.service'
import { Router } from '#angular/router'
import { Employee } from 'app/shared/employee.model'
#Component({
selector: 'app-create-employee',
template: ` <form class="" [formGroup]="employeeForm" (ngSubmit)="saveEmployee()">
<div class="form-control">
<app-input
#memberID
name="memberID"
label="Member ID"
formControlName="memberID"
placeholder="Member ID"
></app-input>
</div>
<div><button type="submit" class="">Save</button></div>
</form>
{{ employeeForm.value | json }}
`,
styleUrls: ['./create-employee.component.scss'],
})
export class CreateEmployeeComponent implements OnInit {
employeeForm: any
constructor(private fb: FormBuilder, private _employeeService: EmployeeService, private _router: Router) {}
employee: Employee = {
memberID: null,
}
ngOnInit(): void {
this.employeeForm = this.fb.group({
memberID: new FormControl(''),
})
this.employee = this.employeeForm.get('memberID').value
}
saveEmployee() {
this._employeeService.save(this.employee)
console.log(this.employeeForm.get('memberID').value)
// this._router.navigate(['employee-list'])
}
}
list-employee.ts
import { Component, OnInit } from '#angular/core'
import { Employee } from 'app/shared/employee.model'
import { EmployeeService } from 'app/services/employee.service'
#Component({
selector: 'app-list-employees',
template: `<div *ngFor="let employee of employees">
<div class="">
{{ employee.memberID }}
</div>
</div> `,
styleUrls: ['./list-employees.component.scss'],
})
export class ListEmployeesComponent implements OnInit {
employees: Employee[] = []
constructor(private _employeeService: EmployeeService) {}
ngOnInit(): void {
this.employees = this._employeeService.getEmployees()
}
}
employee.service.ts
import { Injectable } from '#angular/core'
import { Employee } from 'app/shared/employee.model'
#Injectable({
providedIn: 'root',
})
export class EmployeeService {
listEmployees: Employee[] = [{ memberID: '1' }, { memberID: '2' }]
constructor() {}
getEmployees(): Employee[] {
return this.listEmployees
}
save(employee: Employee) {
this.listEmployees.push(employee)
}
}

Angular 9 component Interaction

I have two components in my angular project that I need a data in one component to get from the other component.seat-modal is where my data is.following is seat-modal.ts.
import { Component, OnInit } from '#angular/core';
import {NgbModal, ModalDismissReasons} from '#ng-bootstrap/ng-bootstrap';
import {FormBuilder, FormGroup, Validators} from '#angular/forms';
import { SocketService} from '../../_services/socket.service';
#Component({
selector: 'app-seat-modal',
templateUrl: './seat-modal.component.html',
styleUrls: ['./seat-modal.component.less']
})
export class SeatModalComponent implements OnInit {
formRequestSeat: FormGroup;
socket;
public seat;
showModal: boolean;
public screenName: string;
constructor(private socketService: SocketService,
private modalService: NgbModal,
private formBuilder: FormBuilder) { }
ngOnInit(){
this.formRequestSeat = this.formBuilder.group({
seatRequest: ['', Validators.required]
});
}
hide(){
this.modalService.dismissAll();
}
join(seat){
const userToken = localStorage.getItem('userToken');
const tableToken = localStorage.getItem('tableToken');
this.socket = this.socketService.init(userToken);
const displayName = this.formRequestSeat.controls.seatRequest.value;
if (!displayName){
alert('Please enter a display name');
return;
}
this.socket.emit('join', {tableToken, displayName, seat}, (data) => {
// data.forEach((index, value) => {
// // this.seatsFormGroup.controls['seat-' + index].value(value);
// });
console.log(data.screenName);
this.screenName = data.screenName;
});
this.hide();
}
}
Follow is seat-modal.html
<div class="modal" id="{{seat.id}}" [style.display]="showModal ? 'block' : 'none'">
<div class="modal-dialog">
<div class="modal-content">
<!-- Modal Header -->
<div class="modal-header">
<h4 class="modal-title">Seat{{seat.id}}</h4>
<button type="button" class="close" data-dismiss="modal" (click)="hide()">×</button>
</div>
<!-- Modal body -->
<div class="modal-body">
<form [formGroup]="formRequestSeat" (submit)="join(seat.id)">
<div class="form-group col-6">
<label for="name">Your Name</label>
<input formControlName="seatRequest" type="text"/>
</div>
<div>
<button type="submit" class="button-request-seat">Request The Seat</button>
</div>
</form>
</div>
</div>
</div>
</div>
<app-play-game [parentData]="screenName"></app-play-game>
Follow is my other component ts
import {Component, Input, OnInit} from '#angular/core';
import {AlertService} from '../../_services/alert.service';
import {SocketService} from '../../_services/socket.service';
import { FormBuilder, FormGroup, FormArray, FormControl,
ValidatorFn}
from '#angular/forms';
import { of } from 'rxjs';
import {NgbModal} from '#ng-bootstrap/ng-bootstrap';
import {SeatModalComponent} from '../../_components/seat-modal/seat-
modal.component';
#Component({
selector: 'app-play-game',
templateUrl: './play-game.component.html',
styleUrls: ['./play-game.component.less']
})
export class PlayGameComponent implements OnInit {
#Input() public parentData;
seatsFormGroup: FormGroup;
seats = [];
showModal: boolean;
public seatModalRef;
private socket;
constructor(private socketService: SocketService,
private formBuilder: FormBuilder,
private modalService: NgbModal) {
this.seatsFormGroup = this.formBuilder.group({
'seat-0': [''],
'seat-1': [''],
'seat-2': [''],
'seat-3': [''],
'seat-4': [''],
'seat-5': [''],
'seat-6': [''],
'seat-7': [''],
'seat-8': [''],
'seat-9': ['']
});
for (let i = 0; i < 10; i++) {
this.seats.push( 'seat-' + i);
}
}
ngOnInit(){
console.log('name=' + this.parentData);
}
sit(seat){
this.seatModalRef = this.modalService.open(SeatModalComponent);
this.seatModalRef.componentInstance.seat = seat;
this.seatModalRef.componentInstance.showModal = true;
}
}
I have tried a console.log(this.parentData) but it is undefined. Please help with codes I'm a begginer in angular.
your seat component should be change from
export class SeatModalComponent implements OnInit {public screenName: 'Sahan';}
to
export class SeatModalComponent implements OnInit {public screenName: string = 'Sahan';}
Currently you have given it Sahan string as a type not a value. Colon (:) is used to give a type where equals(=) is used to assign a value.
Please fix the SeatModalComponent with below.
public screenName: String = 'Sahan';