*ngFor in angular 5 bootstrap modal not working - javascript

Need some expert help to show api-answer data in a bootstrap modal.(the other thread about this in SO did not answer this question)
I have a .ts file that looks like below.
NgbdModal1Content and NgbdModalStacked are the ones I'm having trouble with. Ignore NgbdModal2Content & NgbdModal3Content and their components.
Also, I added a sleep part to make sure the api answer had come back and populated
getResultatFromApi3: string [] = [];
getResultatFromApi4: Observable<Station> [];
Before the modal is rendered. The getResultatFromApiX are console logged before modal is rendered.
import { Component, Injectable } from '#angular/core';
import { NgbActiveModal, NgbModal } from '#ng-bootstrap/ng-bootstrap';
import { GetApiService } from './get-api.service';
import { Observable } from 'rxjs/Observable';
import { Station } from './station';
import { Station2 } from './station2';
#Component({
selector: 'app-modal-stacked',
templateUrl: './modal-stacked2.html',
})
// tslint:disable-next-line:component-class-suffix
export class NgbdModal1Content {
constructor(private modalService: NgbModal, public activeModal: NgbActiveModal) {}
open() {
this.modalService.open(NgbdModal2Content, {
size: 'lg'
});
}
open2() {
this.modalService.open(NgbdModal3Content, {
size: 'lg'
});
}
}
#Component({
template: `
<div class="modal-header">
<h4 class="modal-title">Teststation 1</h4>
<button type="button" class="close" aria-label="Close" (click)="activeModal.dismiss('Cross click')">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<p>Kör test här!</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-dark" (click)="activeModal.close('Close click')">Close</button>
</div>
`
})
// tslint:disable-next-line:component-class-suffix
export class NgbdModal2Content {
constructor(public activeModal: NgbActiveModal) {}
}
#Component({
template: `
<div class="modal-header">
<h4 class="modal-title">Teststation 2</h4>
<button type="button" class="close" aria-label="Close" (click)="activeModal.dismiss('Cross click')">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<p>Kör test här!</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-dark" (click)="activeModal.close('Close click')">Close</button>
</div>
`
})
// tslint:disable-next-line:component-class-suffix
export class NgbdModal3Content {
constructor(public activeModal: NgbActiveModal) {}
}
#Component({
// tslint:disable-next-line:component-selector
selector: 'ngbd-modal-stacked',
templateUrl: './modal-stacked.html'
})
// tslint:disable-next-line:component-class-suffix
export class NgbdModalStacked {
constructor(private modalService: NgbModal, private _getApiService: GetApiService) {}
getResultatFromApi3: string [] = [];
getResultatFromApi4: Observable<Station> [];
getApiData: string [];
// Triggered when opening Modal (that contains two buttons for two other modals
open() {
this._getApiService.method3Call().subscribe(function(data) {
console.log('Test från Y-Tube-videon', data);
this.getResultatFromApi4 = data;
this.getResultatFromApi3 = data;
console.log(this.getResultatFromApi4);
console.log(this.getResultatFromApi3);
});
this.delay(5000).then(any => {
this.modalService.open(NgbdModal1Content);
console.log('du klickade på Teststationer');
});
}
async delay(ms: number) {
await new Promise(resolve => setTimeout(() => resolve(), ms)).then(() => console.log('fired'));
}
}
My api call comes back with information when I trigger Open() in NgbdModalStacked part and answer looks like this, from console log:
I moved the NgbdModal1Content hmtl part to a separate html file to make it easier. That html file looks like this:
<div class="modal-header">
<h4 class="modal-title">Teststationer</h4>
<button type="button" class="close" aria-label="Close" (click)="activeModal.dismiss('Cross click')">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<p><button class="btn btn-lg btn-outline-primary" (click)="open()">Teststation 1 {{getResultatFromApi4}}</button></p>
<p><button class="btn btn-lg btn-outline-primary" (click)="open2()">Teststation 2</button></p>
<p>hej2<p>
<ul *ngFor="let data of getResultatFromApi3">
<li>Reported: {{data.Name}} <span>Mer info</span></li>
</ul>
<table>
<tr *ngFor="let data of getResultatFromApi3">
<td>{{data.Name}}</td>
</tr>
</table>
<ul>
<li *ngFor="let data of getResultatFromApi4">
{{data.Name}}
</li>
</ul>
<ul>
<li *ngFor="let data of getResultatFromApi4">
{{data.Name}}
</li>
</ul>
<p>hejigen2<p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-dark" (click)="activeModal.close('Close click')">Close</button>
</div>
But it doesn't output the data (see pic below) and I can't understand what I'm doing wrong? Tried data.Name and data.name, have both string and object array but api answer is not displayed but the other things in p are displayed.
HOW DO I MAKE THE DATA.NAME SHOW?
Thank you

public getResultatFromApi10 = [];
this._getApiService.method3Call().subscribe(
data => data.forEach(item => {this.getResultatFromApi10.push(item); })
);
This code made it work for me. The other subscribe would output info in the console.log but not carry any data from .ts to the html-part wheras the push(item) seem to have done the trick.
Hope this can help somebody else who might run into the same problem.

Related

Create Custom Social Share Buttons in angular

I will appreciate any ideas and support for this issue
I have an angular project and I try to create icons share buttons for social media.
I have a component named landing.component. in the HTML file I implemented a Modal popup to allow showing a new windows where I have the icons. Please, follow screenshots below
Below, is the new windows
the HTML code is here
<div class="card-wrapper" fxLayout="row wrap" fxLayoutAlign="start start">
<div
class="card active-card"
fxFlex="25"
*ngFor="let category of categories"
(click)="categoryClick(category)"
>
<picture>
<img [src]="category.imageLocation" />
</picture>
<div class="card-overlay" fxLayout="row wrap" fxLayoutAlign="center end">
<span class="card-title" fxFlex="100">{{ category.title }}</span>
<div class="card-buttons" fxFlex="100" fxLayout="row">
<ul class="list-inline text-center member-icons ">
<li class="list-inline-item">
<button mat-icon-button disableRipple class="btn btn-primary" routerLink="/mtl" (click)="open(content)"><i class="fa-solid fa-share"></i></button>
</li>
<span fxFlex></span>
</ul>
<!-- <button mat-icon-button disableRipple>
<heart-icon></heart-icon>
</button> -->
<!-- <span fxFlex></span> -->
<!-- <button mat-icon-button disableRipple> -->
<!-- <download-icon></download-icon> -->
<!-- </button> -->
<!-- <button mat-icon-button disableRipple>
<share-icon></share-icon>
</button> -->
</div>
</div>
</div>
</div>
<section
class="cragcity-container p-t-5"
fxLayout="row"
fxLayoutAlign="space-between start"
>
<div style="margin: auto">
<img class="socmed-icon m-r-15" src="./assets/icons/facebook.webp" />
<img class="socmed-icon m-r-15" src="./assets/icons/skype.webp" />
<img class="socmed-icon" src="./assets/icons/instagram.webp" />
</div>
</section>
<ng-template #content let-modal>
<div class="modal-header">
<h4 class="modal-title" id="modal-basic-title">Share Social Media</h4>
<button type="button" class="btn-close" aria-label="Close" (click)="modal.dismiss('Cross click')"></button>
</div>
<div class="modal-body">
<form>
<div class="mb-3">
<label for="Social Media"></label>
<div class="share-btn-container">
<a #facebook href="#" class="facebook-btn">
<i class="fab fa-facebook"></i>
</a>
<a href="#" class="twitter-btn">
<i class="fab fa-twitter"></i>
</a>
<a href="#" class="pinterest-btn">
<i class="fab fa-pinterest"></i>
</a>
<a href="#" class="linkedin-btn">
<i class="fab fa-linkedin"></i>
</a>
<a href="#" class="whatsapp-btn">
<i class="fab fa-whatsapp"></i>
</a>
</div>
<!-- <div class="input-group">
<input
name="dp"
ngbDatepicker
#dp="ngbDatepicker"
/>
<button class="btn btn-outline-secondary bi bi-calendar3" (click)="dp.toggle()" type="button"></button>
</div> -->
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-dark" (click)="modal.close('Save click')">Close</button>
</div>
</ng-template>
<app-cragcity-footer></app-cragcity-footer>
In the facebook option, I created a variable #facebook that will allow me to use viewchildren in the ts file to do an elementref and find the element in the DOM.
In the viewchildren option, I created a variable link1.
then, in the ngAfterViewInit I created two variables url and title. the url variable will take the link of my page to be share and the title is just message.
Finally, I used this command:
this.link1.nativeElement.setAttribute("href",`https://www.facebook.com/sharer.php?u=${this.url}`)
(this is what I believe is the same in js document.location.href) but used in ts
The code is not working, basically when I click the facebook icon only close the windows and that's it and the web shows me this error here bbelwo:
the landing. component.ts code is here below:
import { Component, OnInit, Input, ViewChild, ElementRef, AfterViewInit, ViewChildren } from '#angular/core';
import { Router, ActivatedRoute } from '#angular/router';
import { DataService } from 'src/app/core/services/data.service';
import { category } from '../models/category';
import { ModalDismissReasons, NgbActiveModal, NgbModal } from '#ng-bootstrap/ng-bootstrap';
#Component({
selector: 'app-landing',
templateUrl: './landing.component.html',
styleUrls: ['./landing.component.scss']
})
export class LandingComponent implements OnInit, AfterViewInit {
public categories = new Array<category>();
#Input() name;
url:string;
title:string;
closeResult: string | undefined;
constructor(private _dataService: DataService, private router: Router, private modalService: NgbModal, private route: ActivatedRoute) {
}
ngOnInit(): void {
this.retrieveCategories();
}
#ViewChildren("facebook")link1: ElementRef;
ngAfterViewInit() {
this.url = this.router.url;
/* this.link1.nativeElement = this.url; */
this.title = encodeURI("Facebook");
this.link1.nativeElement.setAttribute("href",`https://www.facebook.com/sharer.php?u=${this.url}`)
/* console.log(this.link1);
console.log(this.url);
*/
/* this.link1.nativeElement.setAttribute('xlink:href') */
}
retrieveCategories() {
const actionUrl = 'v1/category';
const params = {};
this._dataService.get<any>(actionUrl, params)
.subscribe(data => {
if (data !== null) {
if (!data.isError) { this.categories = data.result; }
}
});
}
categoryClick(data: category) {
if (data.subCategory.length > 0)
this.router.navigate(['mtl', data.id]);
}
open(content) {
this.modalService.open(content, { ariaLabelledBy: 'modal-basic-title' }).result.then(
(result) => {
this.closeResult = `Closed with: ${result}`;
},
(reason) => {
this.closeResult = `Dismissed ${this.getDismissReason(reason)}`;
},
);
}
private getDismissReason(reason: any): string {
if (reason === ModalDismissReasons.ESC) {
return 'by pressing ESC';
} else if (reason === ModalDismissReasons.BACKDROP_CLICK) {
return 'by clicking on a backdrop';
} else {
return `with: ${reason}`;
}
}
}
I really appreciate any help
Regards
First it is a different between #ViewChild and #ViewChildren. The first will search one element, the second multiple elements. So in your case use #ViewChild("facebook") link1: any;
But a besser approach is to let Angular do this thing and don't use setAttribute to the native element. So you can bind anything to the href attribute like this:
HTML
<a #facebook [href]="facebookLink" class="facebook-btn">
<i class="fab fa-facebook"></i>
</a>
Code
facebookLink: string = "https://facebook.com";
You can generate the links with a ngFor loop, too for more flexibility.
CODE
linkObjects = [{iconClassI: "fab fa-facebook", iconClassA: "facebook-btn", link: "http://facebook.com"}, {... all other links}]
HTML
<div class="share-btn-container">
<a *ngFor="let item of linkObjects" [href]="item.link" [class]="item.iconClassA">
<i [class]="item.iconClassI"></i>
</a>
</div>

core.js:6210 ERROR TypeError: this.service.addDepartment is not a function

I'm getting this error when I try to press the 'Add' button on a web application I'm building.
core.js:6210 ERROR TypeError: this.service.addDepartment is not a function
at AddEditDepComponent.addDepartment (add-edit-dep.component.ts:25)
at AddEditDepComponent_button_5_Template_button_click_0_listener (add-edit-dep.component.html:10)
at executeListenerWithErrorHandling (core.js:15265)
at wrapListenerIn_markDirtyAndPreventDefault (core.js:15303)
at HTMLButtonElement.<anonymous> (platform-browser.js:582)
at ZoneDelegate.invokeTask (zone-evergreen.js:406)
at Object.onInvokeTask (core.js:28540)
at ZoneDelegate.invokeTask (zone-evergreen.js:405)
at Zone.runTask (zone-evergreen.js:178)
at ZoneTask.invokeTask [as invoke] (zone-evergreen.js:487)
I don't quite know what the problem is. The function addDepartment looks fine to me, but the error is definitely there.
add-edit-dep.component.ts
import { Component, OnInit, Input } from '#angular/core';
import { SharedService } from 'src/app/shared.service';
#Component({
selector: 'app-add-edit-dep',
templateUrl: './add-edit-dep.component.html',
styleUrls: ['./add-edit-dep.component.css']
})
export class AddEditDepComponent implements OnInit {
constructor(private service : SharedService) { }
#Input() dep: any;
DepartmentId!:string;
DepartmentName!:string;
ngOnInit(): void {
this.DepartmentId = this.dep.DepartmentId;
this.DepartmentName = this.dep.DepartmentName;
}
addDepartment() {
var val = {DepartmentId:this.DepartmentId,
DepartmentName:this.DepartmentName};
this.service.addDepartment(val).subscribe((res: { toString: () => any; })=>{
alert(res.toString());
});
}
updateDepartment() {
var val = {DepartmentId:this.DepartmentId,
DepartmentName:this.DepartmentName};
this.service.updateDepartment(val).subscribe((res: { toString: () => any; })=>{
alert(res.toString());
});
}
}
I would like to think it has something to do with 'res' because I was getting an error (res is an implicit any type) and used QuickFix in VS Code to fix it. But the updateDepartment function is basically identical and it is working properly, so I don't know what the problem is.
I've included all the files I worked on today. I'd appreciate any help.
show-dep.component.html
<!-- Button trigger modal -->
<button type="button" class="btn btn-primary float-right m-2"
data-bs-toggle="modal" data-bs-target="#exampleModal"
(click)="addClick()"
data-backdrop="static" data-keyboard="false">
Add Department
</button>
<!-- Modal -->
<div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered modal-xl" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">{{ModalTitle}}</h5>
<button type="button" class="btn-close"
data-bs-dismiss="modal" aria-label="Close"
(click)="closeClick()" >
</button>
</div>
<div class="modal-body">
<app-add-edit-dep
[dep]="dep" *ngIf="ActivateAddEditDepComp">
</app-add-edit-dep>
</div>
</div>
</div>
</div>
<table class = "table table-striped">
<thead>
<tr>
<th>Department ID</th>
<th>Department Name</th>
<th>Options</th>
</tr>
</thead>
<tbody>
<tr *ngFor = "let dataItem of DepartmentList">
<td>{{dataItem.DepartmentId}}</td>
<td>{{dataItem.DepartmentName}}</td>
<td>
<button type="button" class = "btn btn-light mr-1"
data-bs-toggle="modal" data-bs-target="#exampleModal"
(click)="editClick(dataItem)"
data-backdrop="static" data-keyboard="false">
Edit
</button>
<button type="button" class = "btn btn-light mr-1">
Delete
</button>
</td>
</tr>
</tbody>
</table>
add.edit-dep.component.html
<div class = "form-froup row">
<label class = "col-sm-2 col-form-label"> Department Name </label>
<div class = "col-sm-10">
<input type = "text" class = "form-control" [(ngModel)] = "DepartmentName"
placeholder = "Enter department name">
</div>
</div>
<button (click) = "addDepartment()" *ngIf = "dep.DepartmentId == 0" class = "btn btn-primary">
Add
</button>
<button (click) = "updateDepartment()" *ngIf = "dep.DepartmentId != 0" class = "btn btn-primary">
Update
</button>
shared.service.ts
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { Observable } from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class SharedService {
[x: string]: any;
readonly APIUrl = "http://localhost:59281/api";
readonly PhotoUrl = "http://localhost:59281/Photos";
constructor(private http:HttpClient) { }
getDepList():Observable<any[]> {
return this.http.get<any>(this.APIUrl + '/Department');
}
getDepartment(val:any) {
return this.http.post(this.APIUrl + '/Department', val);
}
updateDepartment(val:any) {
return this.http.put(this.APIUrl + '/Department', val);
}
deleteDepartment(val:any) {
return this.http.delete(this.APIUrl + '/Department/' + val);
}
getEmpList():Observable<any[]> {
return this.http.get<any>(this.APIUrl + '/Employee');
}
getEmployee(val:any) {
return this.http.post(this.APIUrl + '/Employee', val);
}
updateEmployee(val:any) {
return this.http.put(this.APIUrl + '/Employee', val);
}
deleteEmployee(val:any) {
return this.http.delete(this.APIUrl + '/Employee/' + val);
}
UploadPhoto(val:any) {
return this.http.post(this.APIUrl + 'Employee/SaveFile', val);
}
getAllDepartmentNames():Observable<any[]> {
return this.http.get<any[]>(this.APIUrl + '/Employee/GetAllDepartmentNames');
}
}
There is no addDepartment(val:any) function in your SharedService class, this is one of those cases where error messages point to exactly the right place.
You're calling this.service.addDepartment(val) in the addDepartment() method of the AddEditDepComponent

How to open modal for multiple components from same parent component

I am using angular 9.
I have a home page which has four buttons. I want to open separate modal on each button's click at a time.
I did research a lot, here is my trial and effort.
Thanks in advance :)
parent component
#Component({
selector: 'app-link-budget-view',
templateUrl: './home.component.html',
styleUrls: ['./home.component.scss']
})
export class HomeComponent implements OnInit {
#ViewChild('childOne') callChild_OneFn: ChildOneComponent;
#ViewChild('childTwo') callChild_TwoFn: ChildTwoComponent;
...
ngOnInit(): void {
}
openModalOne() {
this.callChild_OneFn.OpenModalFunction();
}
openModalOne() {
this.callChild_TwoFn.OpenModalFunction();
...
}
}
Home Html
<button class="btn btn-primary mb-2 mr-2" (click)="openModalOne()">Modal 1</button>
<button class="btn btn-primary mb-2 mr-2" (click)="openModalTwo()">Modal 2</button>
...
<app-child-one #childOne></app-child-one>
<app-child-two #childTwo></app-child-two>
...
childOne Component
#Component({
selector: 'app-link-budget-view',
templateUrl: './child-one.component.html',
styleUrls: ['./chile-one.component.scss']
})
export class ChildOneComponent implements OnInit {
constructor( private modalService: NgbModal) { }
ngOnInit(): void {
}
OpenModalFunction() {
console.log("component One function running...")
this.modalService.open('#ModalOneId', { size: 'xl' });
}
...
}
similarly there is a function in component two
OpenModalFunction() {
console.log("component Two function running...")
this.modalService.open('#ModalTwoId', { size: 'xl' });
}
Component One Html
<ng-template #ModalOneId let-modal>
<div class="modal-header">
<h4 class="modal-title">This is modal one</h4>
<button type="button" class="close" aria-label="Close" (click)="modal.dismiss('Cross click')">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="card">
<div class=" card-body">
<div id="table" class="table-editable">
...
...
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" (click)="modal.close('Close click')">Close</button>
</div>
</ng-template>
similarly ng-templete is used in component two html
you didn't mention if what you wrote is working or not, or what errors you are getting. it looks like it should work to me. Although if you just want to open a modal, you can handle it completely in your html:
<button (click)="childOne.OpenModalFunction()">Modal 1</button>
<button (click)="childTwo.OpenModalFunction()">Modal 2</button>
<app-child-one #childOne></app-child-one>
<app-child-two #childTwo></app-child-two>
that should be the only thing you need in the parent. no code needed in the parent .ts file. if this is not working, there's something wrong with the code in your child class.
Finally I fixed it here is the code to help others
Parent ts
export class ParentComponent implements OnInit {
constructor(private modalService: CustomModalServiceService) { }
ngOnInit(): void {
}
openModal(modalName: string) {
this.modalService.openModalFunction(modalName);
}
}
Parent html
<button class="btn btn-primary mb-2 mr-2" (click)="openModal('childOne')">Modal_1</button>
<button class="btn btn-primary mb-2 mr-2" (click)="openModal('childTwo')">Modal_2</button>
child one or two ts code accordingly for one or two
export class ChildOneComponent implements OnInit {
constructor(private modalRef: NgbActiveModal) { }
ngOnInit(): void {
}
hideModalFunction() {
this.modalRef.close();
}
}
child one or two html for modal
<div class="modal-header">
<h4 class="modal-title">This is modal one</h4>
<button type="button" class="close" aria-label="Close" (click)="hideModalFunction()">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="card">
<div class=" card-body">
<div id="table" class="table-editable">
...
...
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" (click)="hideModalFunction()">Close</button>
</div>
and you need a custom modal service
Custom modal service
export class CustomModalService {
...
private modalRef: NgbModalRef;
constructor( private modalService: NgbModal) { }
ngOnInit(): void {
}
openModalFunction(modalName: string) {
switch(modalName) {
case 'one':
console.log("component One function running...");
// do any execution before opening child component
this.modalRef = this.modalService.open(ChildOneComponent, { size: 'xl' });
this.modalRef.componentInstance.testData = 'test';
break;
case 'two':
console.log("component Two function running...");
// do any execution before opening child component
this.modalRef = this.modalService.open(ChildTwoComponent, { size: 'xl' });
break;
case default:
// do nothing
}
}
}
You are repeating too much code here. You could make it more re-usable and less repetitive. Try to extract most of the business logic to a service. Leave the component as dumb(no business logic) as possible for better re-usability.
Parent component
#Component({
selector: 'app-link-budget-view',
templateUrl: './home.component.html',
styleUrls: ['./home.component.scss']
})
export class HomeComponent implements OnInit {
...
constructor(private myModalService: MyModalService)
ngOnInit(): void {
}
openModal(modelName: string) {
this.myModalService.openModalFunction(modalName);
}
}
Home Html
<button class="btn btn-primary mb-2 mr-2" (click)="openModal('one')">Modal 1</button>
<button class="btn btn-primary mb-2 mr-2" (click)="openModal('two')">Modal 2</button>
...
MyModal Service
#Injectable({
providedIn: 'root'
})
export class MyModalService {
...
private modalRef: NgbModalRef;
constructor( private modalService: NgbModal) { }
ngOnInit(): void {
}
openModalFunction(modalName: string) {
switch(modalName) {
case 'one':
console.log("component One function running...");
// do any execution before opening child component
this.modalRef = this.modalService.open(ChildOneComponent, { size: 'xl' });
this.modalRef.componentInstance.testData = 'test';
break;
case 'two':
console.log("component Two function running...");
// do any execution before opening child component
this.modalRef = this.modalService.open(ChildTwoComponent, { size: 'xl' });
case default:
// do nothing
}
}
hideModalFunction() {
//do something before closing the modal
this.modalRef.close();
}
}
Now no OpenModalFunction() required inside the child components as you have extracted the modal opening logic into the MyModalService. This will also adhere to the Single Functionality principle means every component has only single functionality to be fulfilled. Furthermore, you have now full control via MyModalService to handle popups. If you want to execute a common code before/after opening/closing the windows like notifying another service, you could do that.
Now this could be further optimized as all software codes do. Like extracting common code from Child Components to a single interface/abstract class. But it totally depends upon your requirements.

Inputting data into a modal from a parent component Angular 5

I am trying to create a cancel function that cancels a specific viewing based on its id. I have a viewings model that I retrieve from firebase as an observable, I then input it into a child div. The problem being that when I click cancel, it always cancels the first viewing on the page, not the specific one that I click.
The strange thing is, that I created a new component on the same level as my modal component, Input the data in the exact same way, and that works perfectly. It only seems to be with the modal that It does not work.
<div class="col-md-3 buttons" [hidden]='!hidden' [#sliderDiv]="out">
<button class="button button-primary button-sm button-green text-center" (click)="updateViewingStatus()">Update Time</button>
<button data-toggle="modal" data-target="#cancelModal" class="button button-primary button-sm button-previous text-center">Cancel Viewing</button>
</div >
<viewings-cancel-modal [viewings]="viewings"></viewings-cancel-modal>
<testing-cancel [viewings]="viewings"></testing-cancel>
</div>
this is where I input viewings property into the child components. Both identical.
this is my test logic (using just a button) that works perfectly:
export class TestingCancelComponent implements OnInit {
#Input() viewings: TenantViewingModel;
private viewingsId;
constructor(private _viewings: ViewingsService) { }
ngOnInit() {
this.viewingsId = this.viewings.viewings_id;
console.log(this.viewings.viewings_id)
}
updateViewingStatus() {
this._viewings.updateViewingStatus(this.viewingsId);
}
}
And this is my modal logic (that doesnt work) :
export class PropertyViewingsCancelModalComponent implements OnInit {
#Input() viewings: TenantViewingModel;
private viewingsId;
constructor(private _viewings: ViewingsService) { }
ngOnInit() {
this.viewingsId = this.viewings.viewings_id;
// console.log(this.viewings.viewings_id)
}
updateViewingStatus() {
this._viewings.updateViewingStatus(this.viewingsId);
}
}
Which again are identical. The html for the working button is as follows:
<button (click)="updateViewingStatus()"></button>
and the non-working modal:
<div class="modal" id="cancelModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalCenterTitle" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="text-center modal_title"> Are you sure you want to </div>
<h1 class="text-center" id="exampleModalLongTitle">Cancel Viewing? {{viewingsId}}</h1>
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
</button>
</div>
<div class="modal-body">
<div class="container">
<img src="/assets/img/site/cancel.svg" alt="" style="height: auto; width: 100%; padding: 25px">
<div class="row">
<div class="col-md-6">
<button data-dismiss="modal" class="button button-primary button-xs button-previous text-center" (click)="updateViewingStatus()">confirm</button>
</div>
<div class="col-md-6 text-right">
<button data-dismiss="modal" (click)="logViewings()" class="button button-primary button-xs button-blue text-center">back</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
So just as a re-cap:
The button test works perfectly, removing the specific viewing that I want to remove or cancel. But with the modal, it only removes the first viewing on the page, even though the logic is identical, and I pass the data through to each child component in the exact same way.
Here some working example let's try this,
Html File,
<!--Pass your id as argument to your method.-->
<button (click)="onCancel(id)" class="button button-primary button-sm button-previous text-center">Cancel Viewing</button>
<!--This button has been hiden element is used to call your method -->
<button type="button" class="hideElement" data-toggle="modal" data-target="#cancelModal" #cancelModal></button>
<viewings-cancel-modal [viewings]="viewings"></viewings-cancel-modal>
Typescript File,
import { ElementRef, ViewChild } from '#angular/core';
#ViewChild('cancelModal') private cancelModal: ElementRef;
public onCancel(id:number) {
//set some global variable has been id value
localstorage.setItem("Id",id); //here set value as local storage.
this.viewings.viewings_id=id;
this.cancelModal.nativeElement.click(); //then here iam doing call that modal
}
Modal typescript File,
export class PropertyViewingsCancelModalComponent implements OnInit {
#Input() viewings: TenantViewingModel;
private viewingsId;
constructor(private _viewings: ViewingsService) { }
ngOnInit() {
//this.viewingsId = this.viewings.viewings_id;
this.viewingsId = localstorage.getItem("Id"); //here iam getting id value in localstorage
console.log("View Id",this.viewingsId) //here you getting your id you can proceed your process in modal button click time.
}
updateViewingStatus() {
this._viewings.updateViewingStatus(this.viewingsId);
}
}
It is a simple logic you have to implement your convenient. I hope it's helpful to solve your problem.
Thanks,
Muthukumar

How to add vue js functions to jquery dynamically

I am using a reusable bootstrap modal i.e same modal for edit, delete operations.
When edit or update buttons are clicked same modal will pop up and I need to append appropriate functions to the modal footer buttons according which operation it is.
My footer buttons are like,
<div class="modal-footer">
<button class="btn actionBtn" data-dismiss="modal">
<span id="footer_action_button" class='glyphicon'> </span>
</button>
<button class="btn btn-warning" data-dismiss="modal">
<span class='glyphicon glyphicon-remove'></span> Close
</button>
</div>
When edit button is clicked,
$(document).on('click', '.edit-modal', function() {
$('#footer_action_button').text(" Update");
$('#footer_action_button').addClass('glyphicon-check');
$('#footer_action_button').removeClass('glyphicon-trash');
$('.actionBtn').addClass('btn-success');
.....
......
$('#myModal').modal('show');
$('.actionBtn').click(updateOperation);
});
similarly for delete action too..
here $('.actionBtn').click(updateOperation); would work well normallly.
but here updateOperation is a vueJs function,
methods: {
updateOperation: function () {
.....
.....
},
}
I am unable to call this update operation.
When statically adding #click="updateOperation()", it works fine.
<button class="btn actionBtn" data-dismiss="modal"
#click="updateOperation()">
<span id="footer_action_button" class='glyphicon'> </span>
</button>
I'm not sure to quite understand your question, but here is how I've done it:
I have a Modal component:
Modal.vue:
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" #click="close()">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title">
{{ title }}
</h4>
</div>
<div class="modal-body">
<slot></slot>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" #click="close()">Fermer</button>
<button type="button" class="btn btn-primary" #click="save()" :disabled="loading"><i class="fa fa-spin fa-spinner" v-if="loading"></i>Confirmer</button>
</div>
</div>
And:
export default {
props: ['title','save','close','loading']
}
As you can see, I take a save and close method in argument of the Modal component.
Then, when I call the component from another one, I send the methods as parameters:
Parent.vue:
<modal v-show="showModal" title="Ajouter une adresse" :save="saveAddress" :close="hideModal" :loading="savingNewAddress">
My Modal content here
</modal>
export default {
data () {
return {
this.showModal = false;
}
},
methods: {
saveAddress () {
console.log('fired from my parent component');
},
hideModal () {
this.showModal = false;
},
displayModal () {
this.showModal = true;
}
},
components: {
Modal
}
}
I hope this helps!

Categories

Resources