Angular ngFor trackBy not working. Not Updating DOM - javascript

Hi y'all my dom is not being updated with trackBy for some reason. I have another component where trackBy is working great but for some reason I can't get it to work on my new component. I have to refresh the page everytime something is added to groceryList and I don't know why?
HTML:
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
<div class="accordion" id="accordionExample">
<div class="card" *ngFor="let grocery of groceryList;trackBy:trackByIdGroceryCode;index as index;">
<div class="card-header" id="grocery1{{index}}">
<h5 class="mb-0">
<button class="btn btn-link" type="button" data-toggle="collapse" attr.data-target="#grocery2{{index}}" aria-expanded="false" aria-controls="grocery2{{index}}">
{{grocery.recipeName}}
</button>
</h5>
</div>
<div id="grocery2{{index}}" class="collapse" aria-labelledby="grocery1{{index}}" data-parent="#accordionExample">
<div class="card-body">
<ul class="list-group" id="filterList">
<li class="list-group-item">
<span class="glyphicon glyphicon-chevron-down"></span>
<ul id="subgroup" class="list-group">
<li class="list-group-item" *ngFor="let ingredient of grocery.ingredients">{{ingredient}}</li>
</ul>
</li>
</ul>
</div>
</div>
</div>
</div>
<mat-icon svgIcon="shopping_cart"></mat-icon>
Component Code:
import { Component, OnInit, NgModule } from '#angular/core';
import {GetRecipesService} from '../getrecipes.service'
import { MatIconRegistry } from "#angular/material/icon";
import { DomSanitizer } from "#angular/platform-browser";
#Component({
selector: 'app-grocery-sidebar',
templateUrl: './grocery-sidebar.component.html',
styleUrls: ['./grocery-sidebar.component.css']
})
export class GrocerySidebarComponent implements OnInit {
constructor(getRecipesService: GetRecipesService,private matIconRegistry: MatIconRegistry,private domSanitizer: DomSanitizer) {
getRecipesService.getGroceryList().subscribe(promise=>{
this.groceryList = promise;
this.groceryList = this.groceryList.data;
});
this.recipeService=getRecipesService;
this.matIconRegistry.addSvgIcon("shopping_cart",this.domSanitizer.bypassSecurityTrustResourceUrl("../assets/shopping-cart-solid.svg"));
}
addToGroceryList(recipeName,recipeIngredients){
this.recipeService.addToGroceryList(recipeName,recipeIngredients).subscribe(promise=>{
console.log("addToGroeryList Promise: "+promise);
this.refreshGroceryList();
});
}
refreshGroceryList(){
this.recipeService.getGroceryList().subscribe(promise=>{
console.log("refreshed groceryList: "+promise.data)
this.groceryList = promise.data;
console.log(this.groceryList);
})
}
deleteGroceryRecipeById(recipeId){
this.recipeService.deleteGroceryRecipeById(recipeId).subscribe(promise=>{
this.refreshGroceryList();
});
}
public trackByIdGroceryCode(index: number, grocery: any): string {
console.log("tracking");
return grocery._id;
}
ngOnInit(): void {
}
recipeService;
groceryList;
showFiller=false;
}
And if your wondering, the console.log("tracking") inside of trackByIdGroceryCode() is being called when adding to my groceryList array. So I'm not sure why my dom isnt being updated unless I refresh the page
Here's my console output if you're curious
tracking grocery-sidebar.component.ts:44:12
addToGroeryList Promise: [object Object] grocery-sidebar.component.ts:23:14
tracking grocery-sidebar.component.ts:44:12
refreshed groceryList: [object Object],...,[object Object] grocery-sidebar.component.ts:31:14
Array(23) [ {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, … ] grocery-sidebar.component.ts:33:14
tracking
{{ groceryList | json }}
<div class="accordion" id="accordionExample">
<div class="card" *ngFor="let grocery of groceryList; index as index;">
<div class="card-header" [id]="'grocery1'+index">
<h5 class="mb-0">
<button class="btn btn-link" type="button" data-toggle="collapse" [attr.data-target]="'#grocery2'+index" aria-expanded="false" [aria-controls]="'grocery2'+index">
{{grocery.recipeName}}
</button>
</h5>
</div>
<div [id]="'grocery2' + index" class="collapse" [aria-labelledby]="'grocery1'+index" data-parent="#accordionExample">
<div class="card-body">
<ul class="list-group" id="filterList">
<li class="list-group-item">
<span class="glyphicon glyphicon-chevron-down"></span>
<ul id="subgroup" class="list-group">
<li class="list-group-item" *ngFor="let ingredient of grocery.ingredients">{{ingredient}}</li>
</ul>
</li>
</ul>
</div>
</div>
</div>
</div>
<mat-icon svgIcon="shopping_cart"></mat-icon>
Recipe Component that invokes groceryComponent:
import {Component} from '#angular/core';
import {GetRecipesService} from './getrecipes.service'
import { TagInputModule } from 'ngx-chips';
import {GrocerySidebarComponent} from "./grocery-sidebar/grocery-sidebar.component";
TagInputModule.withDefaults({
tagInput: {
placeholder: 'Add a ag',
// add here other default values for tag-input
},
dropdown: {
displayBy: 'my-display-value',
// add here other default values for tag-input-dropdown
}
});
#Component({
selector: 'recipes', //<recipes>
styleUrls: ['./recipes.component.css'],
template: `
<script src="angular.min.js"></script>
<script src="ng-tags-input.min.js"></script>
<div class="recipeContainer container-fluid">
<!-- Modal -->
<div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Modal title</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<form>
<div class="form-group">
<label for="recipeNameInput1">Recipe Name</label>
<input [(ngModel)] ="formRecipeName" name="formRecipeName" class="form-control" id="exampleInputEmail1" aria-describedby="emailHelp">
<tag-input [(ngModel)]="formIngredients" id="ingredientTags" [modelAsStrings]="true" name="formIngredients" [secondaryPlaceholder]="'Enter Ingredient'"> </tag-input>
</div>
<button type="submit" class="btn btn-primary" (click)="addRecipe()" data-dismiss="modal">Submit</button>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<!-- Are you Sure Modal -->
<div class="modal fade" id="deleteModal" tabindex="-1" role="dialog" aria-labelledby="deleteModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="deleteModalLabel">Are you sure?</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<button type="submit" class="btn btn-primary" (click)="deleteRecipeInBuffer()" data-dismiss="modal">Delete</button>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<div class="album py-5 bg-light">
<nav class="navbar navbar-expand-sm navbar-dark bg-dark">
<a class="navbar-brand" href="#"></a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarCollapse">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<button class="btn btn-outline-success my-2 my-sm-0" type="submit" data-toggle="modal" data-target="#exampleModal">Add Recipe</button>
</li>
<li class="nav-item">
</li>
</ul>
<form class="form-inline mt-2 mt-md-0">
<input class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search">
<button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
</form>
</div>
</nav>
<div class="row">
<div class="col-md-4" *ngFor = "let recipe of recipeList;trackBy:trackByIdCode">
<div class="card mb-4 box-shadow">
<sup>
<button type="button" data-toggle="modal" data-target="#deleteModal" class="close" aria-label="Close" (click)="prepareToDelete(recipe._id)">
<span aria-hidden="true">×</span>
</button>
</sup>
<h5 class="card-title">{{recipe.recipeName}} </h5>
<div class="card-body" >
<p class="card-text">{{recipe.recipeIngredients}}</p>
<div class="d-flex justify-content-between align-items-center">
<div class="btn-group">
<button type="button" class="btn btn-sm btn-outline-secondary" (click)="addToGroceryList(recipe.recipeName,recipe.recipeIngredients)">Add To Grocery List</button>
</div>
<small class="text-muted">9 mins</small>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
TODO: Edit Recipe. Ingreidents with quantity. Ingredients with style (Chopped. Diced. Sautee..etc). Search or Filter (by name or ingredient).
TODO: Add to grocery List. Undo Button
`,
})
export class RecipesComponent{
constructor(getRecipesService: GetRecipesService,groceryList:GrocerySidebarComponent){
getRecipesService.getRecipes().subscribe(promise=>{
this.recipeList = promise;
this.recipeList = this.recipeList.data;
console.log(this.recipeList);
});
this.recipeService=getRecipesService;
this.groceryList = groceryList;
}
addToGroceryList(recipe,ingredients){
this.groceryList.addToGroceryList(recipe,ingredients);
}
//when user presses x on card, the id is stored here. Then are you sure window appears
//if yes on are you sure then delete whats in buffer
//else clear what's in buffer
prepareToDelete(recipeId){
this.deleteBuffer = recipeId;
}
//if yes after are you sure, delete whats in buffer
deleteRecipeInBuffer(){
this.deleteRecipe(this.deleteBuffer);
}
addRecipe(){
this.recipeService.addRecipe(this.formRecipeName,this.formIngredients).subscribe(promise=>{
console.log("promise"+promise);
this.refreshRecipeList();
this.formIngredients = undefined;
this.formRecipeName = undefined;
});
}
deleteRecipe(recipeId){
this.recipeService.deleteRecipe(recipeId).subscribe(promise=>{
console.log(promise);
this.refreshRecipeList();
})
}
refreshRecipeList(){
this.recipeService.getRecipes().subscribe(promise=>{
console.log("refreshed");
this.recipeList = promise.data;
});
}
public trackByIdCode(index: number, recipe: any): string {
return recipe._id;
}
deleteBuffer;//buffer is used to store recipeId => are you sure window comes up. if yes then delete whats in deleteBuffer
formRecipeName;//form value in modal
formIngredients; //form value in modal
recipeService;//http access service
recipeList;//list of all recipes recieved from recipeService
groceryList;
}
UPADTE: I Learned that things update fine when deleting objects but when I call my function to add to my grocery component from my recipe component things don't update. I think my issue is that things arn't being called in the order that I think they are. I still don't know how to fix this but I really appreciate everyone that is trying to help
//

Looks like this could be an angular lifecycle issue; maybe the template is not getting updated after the subscriptions that are called when you run refreshGroceryList(). Try doing a manual change detection after you update the data, like so:
constructor(private cdr: ChangeDetectorRef, ...) {}
refreshGroceryList(){
this.recipeService.getGroceryList().subscribe(promise=>{
console.log("refreshed groceryList: "+promise.data)
this.groceryList = promise.data;
this.cdr.detectChanges();
console.log(this.groceryList);
})
}

The problem is you are trying to bind to aria and data attributes. If you change all the aria- attributes to attr.aria- and data- attributes to attr.data- it will work.
Here is a working StackBlitz https://stackblitz.com/edit/angular-ivy-kp6aev?file=src%2Fapp%2Fapp.component.html

Related

How do I close a bootstrap (5.2) Modal from Javascript?

For a school project's sake, I created a modal using bootstrap in html, inside of it there is a prompt that I must check from javascript, how do I close the Modal from javascript, so that in case the prompt is valid I can just save the changes and if it isn't I throw an exception?
small note (Please without jQuery, I've seen a similar thread that had as a reply using this library, it's forbidden for the assignment)
this is my html code :
<div class="modal fade" id="bidModal" tabindex="-1" aria-labelledby="bidModal" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="bidModalLabel">Bid amount</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<p class="text" id="prompted">How much do you want to bet?</p>
<div class="input-group mb-2">
<input id="bAmount" type="text" class="form-control text" aria-label="Amount of bet">
<span class="input-group-text">€</span>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger" data-bs-dismiss="modal">Cancel bid</button>
<button type="button" onClick="bid()" class="btn btn-success">Save bid</button>
</div>
</div>
</div>
</div>
this is my javascript code :
function bid(){
let valueOfBid = document.getElementById("bAmount").value;
if(isNaN(valueOfBid)){
//Cancel the prompt
}
players[realPlayer].bet=valueOfBid;
changeButtonState(false);
theTimer();
}
Please try like this. I suggest that you change isNaN(valueOfBid) to valueOfBid == "" before you add my code on your codebase.
function bid(){
let valueOfBid = document.getElementById("bAmount").value;
if(valueOfBid == ""){
alert(1)
//Cancel the prompt
var myModalEl = document.getElementById('bidModal');
var modal = bootstrap.Modal.getInstance(myModalEl)
modal.hide();
}
// players[realPlayer].bet=valueOfBid;
// changeButtonState(false);
}
you can add this to the element that should close the modal...
data-bs-dismiss="modal"
the following modal generates a list of links based off of a search term and user matches.
when they click one of the router links it will close the modal because of the line
<router-link :to="{ name: 'user', params: {user: user }}"
data-bs-dismiss="modal"
>{{ user }}
</router-link
>
the above code is generated INSIDE the modal -> here is the entire thing
<div class="full-page">
<div
class="modal fade"
id="findUser"
data-bs-backdrop="static"
data-bs-keyboard="false"
tabindex="-1"
aria-labelledby="staticBackdropLabel"
aria-hidden="true"
>
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="staticBackdropLabel">Find User</h5>
<button
type="button"
class="btn-close"
data-bs-dismiss="modal"
aria-label="Close"
></button>
</div>
<div class="modal-body">
<label for="recipient-name" class="col-form-label"
>Steem Username:</label
>
<input
type="text"
v-model="userField"
class="form-control"
id="recipient-name"
/>
</div>
<div v-if="userField"></div>
<ul v-for="(user, index) in userMatches" :key="index">
<li>
<router-link
:to="{ name: 'user', params: { user: user } }"
data-bs-dismiss="modal"
>{{ user }}</router-link
>
</li>
</ul>
<div class="modal-footer">
<button
type="button"
class="btn btn-secondary"
data-bs-dismiss="modal"
>
Close
</button>
</div>
</div>
</div>
</div>
</div>

Bootstrap modal not displayed over another modal

I have a modal thats being created when "Click me here" button is clicked, Further the modal needs to show a toast modal conveying some Thank you message.
The thank you modal closes the existing modal when save is clicked. The expected was, when save is clicked the save modal should not be unloaded, the thank you modal should be kept loaded over the top of save modal.
When save is clicked I get the error message
Cannot read properties of undefined (reading 'backdrop')
<!doctype html>
<html lang="en">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.2.2/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-Zenh87qX5JnK2Jl0vWa8Ck2rdkQ2Bzep5IDxbcnCeuOxjzrPF/et3URy9Bv1WTRi" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.2.2/dist/js/bootstrap.bundle.min.js"
integrity="sha384-OERcA2EqjJCMA+/3y+gxIOqMEjwtxJY7qPCqsdltbNJuaOe923+mo//f6V8Qbsw3"
crossorigin="anonymous"></script>
</head>
<body>
<button id="clickme">Click me here</button>
<ul class="list-group task-point">
</ul>
<script>
function showToast(m,title="Error") {
$("#modal")
.html(`<div class="modal fade" id="messagemodal" tabindex="-1" role="dialog" aria-labelledby="messagemodal" aria-hidden="true">
<div class="modal-dialog modal-sm modal-dialog-centered" role="document">
<div class="modal-content">
<div class="p-2 modal-header">
<h5 class="ms-2 modal-title">${title}</h5>
<button type="button" class="me-1 btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="text-start modal-body">
${m}<br/><br/>
</div>
</div>
</div>
</div>`);
var modal = new bootstrap.Modal(document.getElementById('messagemodal'), {
keyboard: false
});
modal.show();
}
$("#clickme").click(function (event) {
var code = $(".dropdown-menu").length+1
$(".task-point").append(`
<li class="list-group-item">
<img src="https://img.icons8.com/color/48/000000/networking-manager.png" class="float-start" />
<div class="btn-group float-end">
<button type="button" class="btn dropdown-toggle" data-bs-toggle="dropdown" data-bs-display="static" aria-expanded="false"> Action </button>
<ul class="dropdown-menu dropdown-menu-lg-end">
<li><a data-bs-toggle="modal" href="#exampleModalToggle-${code}" role="button" class="dropdown-item" href="#">Edit ${code}</a></li>
<li><a class="dropdown-item" href="#">Delete ${code}</a></li>
<li><a class="dropdown-item" href="#">Run ${code}</a></li>
</ul>
</div>
<div class="ms-5">This is ${code} item<br/>
<small class="text-secondary">This is a ${code} item description</small>
<div>
<div class="modal fade" id="exampleModalToggle-${code}" aria-hidden="true" aria-labelledby="exampleModalToggleLabel" tabindex="-1">
<div class="modal-dialog modal-fullscreen">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="exampleModalToggleLabel">Create a file</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body"> What is Lorem Ipsum? </div>
<div class="modal-footer">
<button class="btn btn-primary" data-bs-target="#exampleModalToggle2" data-bs-toggle="modal" onclick="showToast('Thanks for saving');">Save</button>
</div>
</div>
</div>
</div>
</li>
`);
$(`#exampleModalToggle-${$(".dropdown-menu").length}`).modal("show")
})
</script>
</body>
Please try below code and replace it with your code:
<!doctype html>
<html lang="en">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.2.2/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-Zenh87qX5JnK2Jl0vWa8Ck2rdkQ2Bzep5IDxbcnCeuOxjzrPF/et3URy9Bv1WTRi" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.2.2/dist/js/bootstrap.bundle.min.js"
integrity="sha384-OERcA2EqjJCMA+/3y+gxIOqMEjwtxJY7qPCqsdltbNJuaOe923+mo//f6V8Qbsw3"
crossorigin="anonymous"></script>
</head>
<body>
<style>
.modal-backdrop.fade.show + .modal-backdrop.show {
z-index: 9999;
}
div#messagemodal {
z-index: 99999;
}
</style>
<button id="clickme">Click me here</button>
<ul class="list-group task-point">
</ul>
<div id="modal">
</div>
<script>
function showToast(m,title="Error") {
$("#modal")
.html(`<div class="modal fade" id="messagemodal" tabindex="-1" role="dialog" aria-labelledby="messagemodal" aria-hidden="true">
<div class="modal-dialog modal-sm modal-dialog-centered" role="document">
<div class="modal-content">
<div class="p-2 modal-header">
<h5 class="ms-2 modal-title">${title}</h5>
<button type="button" class="me-1 btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="text-start modal-body">
${m}<br/><br/>
</div>
</div>
</div>
</div>`);
$("#messagemodal").modal('show');
$(document).on("click", ".me-1", function() { $("#messagemodal").modal('hide'); $("#modal").empty();});
}
$("#clickme").click(function (event) {
var code = $(".dropdown-menu").length+1
$(".task-point").append(`
<li class="list-group-item">
<img src="https://img.icons8.com/color/48/000000/networking-manager.png" class="float-start" />
<div class="btn-group float-end">
<button type="button" class="btn dropdown-toggle" data-bs-toggle="dropdown" data-bs-display="static" aria-expanded="false"> Action </button>
<ul class="dropdown-menu dropdown-menu-lg-end">
<li><a data-bs-toggle="modal" href="#exampleModalToggle-${code}" role="button" class="dropdown-item" href="#">Edit ${code}</a></li>
<li><a class="dropdown-item" href="#">Delete ${code}</a></li>
<li><a class="dropdown-item" href="#">Run ${code}</a></li>
</ul>
</div>
<div class="ms-5">This is ${code} item<br/>
<small class="text-secondary">This is a ${code} item description</small>
<div>
<div class="modal fade" id="exampleModalToggle-${code}" aria-hidden="true" aria-labelledby="exampleModalToggleLabel" tabindex="-1" da>
<div class="modal-dialog modal-fullscreen">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="exampleModalToggleLabel">Create a file</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body"> What is Lorem Ipsum? </div>
<div class="modal-footer">
<button class="btn btn-primary" onclick="showToast('Thanks for saving');">Save</button>
</div>
</div>
</div>
</div>
</li>
`);
$(`#exampleModalToggle-${$(".dropdown-menu").length}`).modal("show");
})
</script>
</body>
For Thank you popup faded backdrop, put below css in the style sheet
.modal-backdrop.fade.show + .modal-backdrop.show {
z-index: 9999;
}
div#messagemodal {
z-index: 99999;
}
If above css is not working for you then please use parent class name along with the css.

Open a modal from a button in another component Vue JS

I have 2 components. One called TestSearchTool and another one called TestModal. I'd like to show my Modal when I click a button in the TestSearchTool component. These 2 components are siblings in the hierarchy so I didn't really find a way to pass the value between them ( there is vuex but I'd like to find a way without it )
I'm using Bootstrap 5 and Vue 3 to do this since Bootstrap Vue doesn't work on Vue 3.
Here is my TestModal component :
<template>
<div>
<div class="modal fade" ref="exampleModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Modal title</h5>
<button type="button" class="btn-close" #click="modal.hide()" aria-label="Close"></button>
</div>
<div class="modal-body">
...
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" #click="modal.hide()">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { Modal } from 'bootstrap'
export default {
name: "App",
data: () => ({
modal: null
}),
mounted() {
this.modal = new Modal(this.$refs.exampleModal)
}
};
</script>
Here is my TestSearchTool component :
<template>
<div>
<div class="container ml-5 mt-3 border-1 rounded pl-5 pt-5 pr-5">
<div class="row mb-4">
<div class="col-md-6 mb-4" >
<label for="test" class="label-form">Titre</label>
<input autocomplete="off" placeholder="Rechercher par le titre du test" v-model="testName" type="text" id="test" class="form-control">
</div>
<div class="col-md-6 mb-4">
<label for="candidat" class="label-form">Candidat</label>
<select v-model="CandidateName" class="form-select" id="candidat">
<option value="" selected>Tous les candidats</option>
</select>
</div>
</div>
<div class="row">
<div class="col-12 mb-3">
<div class="col-12 mb-4">
<div class="col-sm-6 col-12 d-inline-block">
<!-- Modal is shown on this button's click !-->
<button type="button" #click="this.$emit('clickDone')" class=" btn btn-primary col-12 col-sm-11 mb-sm-0 mb-sm-0 mb-4 float-sm-left"><i class="fa-solid fa-file-circle-plus"></i> Ajouter Un Test</button>
</div>
<div class="col-sm-6 col-12 d-inline-block">
<button #click="deleteTests" type="button" class=" btn btn-primary col-sm-12 col-12" v-if="false"><i class="fa-solid fa-file-circle-minus"></i> Supprimer Le(s) Test(s)</button>
</div>
</div>
<button id="searchTest" #click="searchBy" class="col-12 btn btn-primary" ><i class="fas fa-search"></i> Rechercher</button>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
components:{
},
data(){
return {
testName:'',
CandidateName:'',
show:false,
}
},
methods:{
},
}
</script>
<style scoped>
</style>
And here is the parent component (called Tests) :
<template>
<div>
<test-search-tool></test-search-tool>
<test-modal></test-modal>
</div>
</template>
<script>
import TestSearchTool from "../components/TestSearchTool.vue"
import TestModal from "../components/TestModal.vue"
export default {
components : {
DashboardNavbar,
TestSearchTool,
TestModal,
},
mounted(){
document.body.style.backgroundImage='url("")';
document.body.style.background="white";
}
}
</script>
<style>
</style>
As I know the goal of writing codes in components in simple words is to have special duties specific to that component. So when we define a "modal" component, we expect that it shows modal content for us. So in my opinion it is not correct to say modal component (here called TestModal.vue) and TestSearchTool.vue are siblings. You could use TestModal.vue every where in your app structure that you need a modal content to be shown. In other words the TestModal.vue component does not have any special content or logic to be the direct child of Tests.vue (the parent component).
With the above description I used TestModal.vue as child of TestSearchTool.vue and by using props and watch and emit capabilities of Vue, here is the codes of all 3 components:
TestSearchTool.vue:
<template>
<div>
<div class="container ml-5 mt-3 border-1 rounded pl-5 pt-5 pr-5">
<div class="row mb-4">
<div class="col-md-6 mb-4" >
<label for="test" class="label-form">Titre</label>
<input autocomplete="off" placeholder="Rechercher par le titre du test" v-model="testName" type="text" id="test" class="form-control">
</div>
<div class="col-md-6 mb-4">
<label for="candidat" class="label-form">Candidat</label>
<select v-model="CandidateName" class="form-select" id="candidat">
<option value="" selected>Tous les candidats</option>
</select>
</div>
</div>
<div class="row">
<div class="col-12 mb-3">
<div class="col-12 mb-4">
<div class="col-sm-6 col-12 d-inline-block">
<!-- Modal is shown on this button's click !-->
<button type="button" #click="this.$emit('clickDone')" class=" btn btn-primary col-12 col-sm-11 mb-sm-0 mb-sm-0 mb-4 float-sm-left"><i class="fa-solid fa-file-circle-plus"></i> Ajouter Un Test</button>
</div>
<div class="col-sm-6 col-12 d-inline-block">
<button #click="deleteTests" type="button" class=" btn btn-primary col-sm-12 col-12" v-if="false"><i class="fa-solid fa-file-circle-minus"></i> Supprimer Le(s) Test(s)</button>
</div>
</div>
<!-- *********************** -->
<!-- this button is responsible for showing modal. you can use such a button in other parts of your app if you define "data" correctly -->
<button id="searchTest" #click="dataModal = true" class="col-12 btn btn-primary" ><i class="fas fa-search"></i> Rechercher</button>
</div>
<test-modal #closeModal="dataModal = false" :showModal="dataModal"></test-modal>
<!-- *********************** -->
</div>
</div>
</div>
</template>
<script>
import TestModal from "../components/TestModal.vue"
export default {
name: "TestSearchTool",
components:{
TestModal
},
data(){
return {
testName:'',
CandidateName:'',
show:false,
/* this data is used for showing modal */
dataModal: false
}
}
}
</script>
<style scoped>
</style>
TestModal.vue:
<template>
<div>
<div id="myModal" class="modal fade" ref="exampleModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Modal title</h5>
<button type="button" class="btn-close" #click="hideModal" aria-label="Close"></button>
</div>
<div class="modal-body">
...
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" #click="hideModal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { Modal } from 'bootstrap'
export default {
name: "TestModal",
data: () => ({
modalInstance: null
}),
props: {
showModal: {
type: Boolean,
default: false
}
},
watch: {
showModal(newValue, oldValue) {
console.log(newValue);
if (newValue === true) {
this.modalActive();
}
}
},
methods: {
modalActive: function () {
this.modalInstance = new Modal(document.getElementById('myModal'), {
target: "#my-modal",
backdrop: "static"
});
this.modalInstance.show()
},
hideModal: function () {
console.log("closed");
this.modalInstance.hide();
this.$emit('closeModal');
}
}
};
</script>
<style scoped>
</style>
Tests.vue:
<template>
<div>
<test-search-tool></test-search-tool>
</div>
</template>
<script>
import TestSearchTool from "../components/TestSearchTool.vue"
export default {
name: "Tests",
components : {
TestSearchTool
}
}
</script>
<style scoped>
</style>

Razor form foreach returning the same id

I have a button that pops modal with text area. When I click the Submit button in the modal I want to pass the data to the post method (Description and OrderId). The problem is that the orderid is always the same as the first order. For example I click on order with id that is supposed to be 4, but the id that it returns is 1(as the first order), therefore I'm passing the wrong Id to the controller.
Note - The order.Id works perfectly fine outside the modal, the problem is when im passing it to the modal.
#foreach (var order in Model .Where(x => Context.Request.Query["searchOption"] == "2" ? x.Status == "Completed" : x.Status == "Active")) {
<div class="card" style="width: 18rem; margin-left:1em; margin-bottom: 1em; margin-top: 1em">
<div class="card-body">
<h5 class="card-title">#order.ServiceName</h5>
</div>
<ul class="list-group list-group-flush">
<li class="list-group-item">#order.Address</li>
<li class="list-group-item">#order.StartDate</li>
<li class="list-group-item">#order.DueDate</li>
<li class="list-group-item">#order.HoursBooked</li>
<li class="list-group-item">#order.WorkersCount</li>
<li class="list-group-item">#order.Status</li>
<li class="list-group-item">#order.Price<text>$</text></li>
#if (order.Status == "Completed") {
<!-- Button trigger modal -->
<form method="post" asp-controller="Orders" asp-action="AddComplaint">
<!-- Modal Trigger -->
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exampleModal">
Add Complaint
</button>
<!-- Modal -->
<div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Modal title</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
***<input name="OrderId" value="#order.Id" />
<textarea name="Description" style="height:100%; width:100%"></textarea>***
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</div>
</div>
</div>
</form>
}
You can change like this(add i before foreach and add i++ in foreach,change the data-target of button,and change the id of modal):
#{ var i = 0;}
#foreach (var order in Model .Where(x => Context.Request.Query["searchOption"] == "2" ? x.Status == "Completed" : x.Status == "Active")) {
i++;
<div class="card" style="width: 18rem; margin-left:1em; margin-bottom: 1em; margin-top: 1em">
<div class="card-body">
<h5 class="card-title">#order.ServiceName</h5>
</div>
<ul class="list-group list-group-flush">
<li class="list-group-item">#order.Address</li>
<li class="list-group-item">#order.StartDate</li>
<li class="list-group-item">#order.DueDate</li>
<li class="list-group-item">#order.HoursBooked</li>
<li class="list-group-item">#order.WorkersCount</li>
<li class="list-group-item">#order.Status</li>
<li class="list-group-item">#order.Price<text>$</text></li>
#if (order.Status == "Completed") {
<!-- Button trigger modal -->
<form method="post" asp-controller="Orders" asp-action="AddComplaint">
<!-- Modal Trigger -->
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exampleModal#(i)">
Add Complaint
</button>
<!-- Modal -->
<div class="modal fade" id="exampleModal#(i)" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Modal title</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
***<input name="OrderId" value="#order.Id" />
<textarea name="Description" style="height:100%; width:100%"></textarea>***
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</div>
</div>
</div>
</form>
}

Onload Popup Using HTML,CSS and Jquery

<script>
// you can use just jquery for this
$(document).ready(function(){
$('#overlay-back').fadeIn(500,function(){
$('#popup').show();
});
$(".close-image").on('click', function() {
$('#popup').hide();
$('#overlay-back').fadeOut(500);
});
});
The above is the javascript i have used. I need to get the popup on page loading.
<!-- Modal -->
<div class="modal" id="edittemplate" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="text-danger fa fa-times"></i></button>
<h3 class="modal-title" id="myModalLabel" style="text-align:center;">
<strong>Design</strong> - Get Started First Step
</h3>
<h4> Play with Design Tools To Make Your Site Look Exactly Your Way!!! </h4>
</div>
<div class="modal-body">
<div class="row">
<div class="col-md-4">
<strong>Interactive Tutorial</strong>
<div class="sidebar-nav">
<div class="navbar navbar-default" role="navigation">
<div class="navbar-collapse collapse sidebar-navbar-collapse" style="padding-left: 0px; padding-right: 0px;">
<ul class="nav navbar-nav">
<li class="active">Design</li>
<li>Basic Information</li>
<li>Features</li>
<li>Sample Menu</li>
<li>Review And Finish</li>
</ul>
</div><!--/.nav-collapse -->
</div>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="filter">Template Name</label>
<select class="form-control">
<option value="0" selected>All Snippets</option>
<option value="1">Lively</option>
<option value="2">Whimsical</option>
<option value="3">Modern</option>
<option value="4">Elegant</option>
</select>
</div>
<div class="form-group">
<label for="filter">Colour Scheme</label>
<select class="form-control">
<option value="0" selected>All Snippets</option>
<option value="1">Black/Red</option>
<option value="2">Blue/Yellow</option>
<option value="3">Brown/Orange</option>
<option value="4">Green/Black</option>
</select>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<!-- <div class="text-right pull-right col-md-3">
</div> -->
<div class="text-right pull-right col-md-3">
<button type="submit" class="btn btn-success"> Next </button>
</div>
</div>
</div>
</div>
</div>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="index.html" font="Arial">DinersDomain</a>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right"><br>
<li><span class="btn btn-default btn-lg">Edit This Template</span></li>
</ul>
</div><!--/.nav-collapse -->
</div>
Can someone help me how to get the popup instead of clicking on Edit This Template Button. On page refresh popup should come.
With this code you show the modal whenever you want.
$("#edittemplate").modal("show");
For what I can see, you are using bootstrap, if I'm right, you can use bootstrap js to make the modal.
Here's the documentation:
http://getbootstrap.com/javascript/#modals
And here an example:
--------- This is the modal with id = ' myModal ' ------------
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title" id="myModalLabel">Modal title</h4>
</div>
<div class="modal-body">
...
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
And in your .js file (you must have jquery and bootstrap.js libraries imported before)
$("#myModal").modal('show');
Good luck
I've tested this and it works.
If you have a problem I think that:
1) Maybe you have not imported bootstrap-JS / jquery library.
2) Or you didn't imported jquery before bootstrap js library before yourScript
It must be like:
<script src="js/jquery.js"></script>
<script src="js/bootstrap.min.js"></script>
<script src="js/script.js"></script>
In that order.

Categories