world... again.
I'm stumped by something that should be straightforward, but right now I cant see it. I'm trying to map over a simple array and display values. Each card should have a button that opens a bs modal which should show more information on the particular array object. but instead it returns infomation only on the first object in the array.
I think there's a concept here that I'm not getting and it's a shade embarassing. Thaank's in advance for your help.
import "./styles.css";
export default function App() {
const modalInfo = [
{ name: "james", number: "1" },
{ name: "Jackie", number: "2" },
{ name: "Ariane", number: "3" },
{ name: "Mike", number: "4" }
];
return (
<>
<div className="App">
{modalInfo.map((info) => (
<div className="card">
<h1>{info.name}</h1>
<button
type="button"
class="btn btn-primary"
data-bs-toggle="modal"
data-bs-target="#staticBackdrop"
>
Show more
</button>
<div
class="modal fade"
id="staticBackdrop"
data-bs-backdrop="static"
data-bs-keyboard="false"
tabindex="-1"
aria-labelledby="staticBackdropLabel"
aria-hidden="true"
>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="staticBackdropLabel">
#{info.number}
</h5>
<button
type="button"
class="btn-close"
data-bs-dismiss="modal"
aria-label="Close"
></button>
</div>
<div class="modal-body">{info.name}</div>
<div class="modal-footer">
<button
type="button"
class="btn btn-secondary"
data-bs-dismiss="modal"
>
Close
</button>
<button type="button" class="btn btn-primary">
Understood
</button>
</div>
</div>
</div>
</div>
</div>
))}
</div>
</>
);
}
This is the current error in console , I copied the code from sandbox and plugged it into another project with bootstrap:
Uncaught TypeError: 'querySelector' called on an object that does not
implement interface Element. findOne selector-engine.js:24
_showElement modal.js:217 show modal.js:143 y index.js:251 show backdrop.js:54 y index.js:251 r index.js:273 selector-engine.js:24:43
You must be getting some unique key error in your console.
Give a key to you card that acts a a unique id for your card.
<....
{modalInfo.map((info, index) => (
<div className="card" key={info.index}>
...>
You can give index as well as a unique id but that not correct way just for testing you can. But from what I see is the number property is incrementing by 1 as well so that's why I have kept index as the key.
id attributes must be unique in a document. You are re-using staticBackdrop in each map iteration so they're being duplicated.
When Bootstrap tries to grab the modal target by #staticBackdrop, it only gets the first one because that's what happens with repeated IDs.
Using the info.id properties from your sandbox link, try incorporating that into the id and data-bs-target attributes
{modalInfo.map((info) => (
<div className="card" key={info.id}> {/* keys are important, don't use index */}
<h1>{info.name}</h1>
<button
type="button"
className="btn btn-primary"
data-bs-toggle="modal"
data-bs-target={`#staticBackdrop_${info.id}`}
>
Show more
</button>
<div
className="modal fade"
id={`staticBackdrop_${info.id}`}
data-bs-backdrop="static"
data-bs-keyboard="false"
tabIndex="-1"
aria-labelledby={`staticBackdropLabel_${info.id}`}
aria-hidden="true"
>
{/* the rest of your markup goes here */}
</div>
</div>
))}
You also have a bunch of class attributes that should be className and a repeated id="staticBackdropLabel" that should get a similar treatment to staticBackdrop.
Related
I am using bootstrap5 to React. I successfully installed the bootstrap5 in React. Now I have to show the modal on my page so I added a button and modal code on my page.
Below is the code I am using for the modal. Now I click on the button then nothing is working. I am not getting my modal.
What is the issue here?
import React from "react";
function addEmployee(){
return(
<div className="addEmployee">
<button type="button" className="btn btn-primary" data-bs-toggle="modal" data-bs-target="#staticBackdrop">Add Employee</button>
<div className="modal fade" id="staticBackdrop" data-bs-backdrop="static" data-bs-keyboard="false" tabIndex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true">
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-header">
<h5 className="modal-title" id="staticBackdropLabel">Modal title</h5>
<button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div className="modal-body">
...
</div>
<div className="modal-footer">
<button type="button" className="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="button" className="btn btn-primary">Understood</button>
</div>
</div>
</div>
</div>
</div>
)
}
export default addEmployee;
Bootstrap 5 no longer depends on jQuery so you don't need a 3rd party library library like react-bootstrap to use Bootstrap in React. For example you can use the data-bs- attributes in the markup, or create a functional component for the Bootstrap modal with methods to show/hide the modal...
function ModalExample() {
const modalRef = useRef()
const showModal = () => {
const modalEle = modalRef.current
const bsModal = new bootstrap.Modal(modalEle, {
backdrop: 'static',
keyboard: false
})
bsModal.show()
}
const hideModal = () => {
const modalEle = modalRef.current
const bsModal= bootstrap.Modal.getInstance(modalEle)
bsModal.hide()
}
return(
<div className="addEmployee">
<button type="button" className="btn btn-primary" onClick={showModal}>Add Employee</button>
<div className="modal fade" ref={modalRef} tabIndex="-1" >
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-header">
<h5 className="modal-title" id="staticBackdropLabel">Modal title</h5>
<button type="button" className="btn-close" onClick={hideModal} aria-label="Close"></button>
</div>
<div className="modal-body">
...
</div>
<div className="modal-footer">
<button type="button" className="btn btn-secondary" onClick={hideModal}>Close</button>
<button type="button" className="btn btn-primary">Understood</button>
</div>
</div>
</div>
</div>
</div>
)
}
Demo of both methods
I would suggest you'd use react-bootstrap its a lot easier and the javascript has been done for you
React-Bootstrap replaces the Bootstrap JavaScript
Each component has been built from scratch as a React component, without unneeded dependencies like jQuery.
To get started just install the package npm install react-bootstrap bootstrap
look at this example
import { Modal, Button } from "react-bootstrap";
function Example() {
const [show, setShow] = useState(false);
const handleClose = () => setShow(false);
const handleShow = () => setShow(true);
return (
<>
<Button variant="primary" onClick={handleShow}>
Launch demo modal
</Button>
<Modal show={show} onHide={handleClose}>
<Modal.Header closeButton>
<Modal.Title>Modal heading</Modal.Title>
</Modal.Header>
<Modal.Body>Woohoo, you're reading this text in a modal!</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={handleClose}>
Close
</Button>
<Button variant="primary" onClick={handleClose}>
Save Changes
</Button>
</Modal.Footer>
</Modal>
</>
);
}
render(<Example />);
Gaurav Singhal's blog # PluralSight
You must use controlled components that use the internal state to set
the values and change the behavior of a component. Libraries like
jQuery do direct DOM manipulation, whereas React components use
Virtual DOM to modify the actual DOM on the browser. Using jQuery to
change your component's behavior is possible. Still, it will lead to
unexpected results and make it difficult to debug. React Bootstrap
implements each component in pure React, so you don't have to worry
about Bootstrap's dependency on jQuery
to check out their (react-bootstrap) documentation page ,here is the link you can follow/go to react-bootstrap
I use Angular 9 to develop a web application. So I need to use Bootstrap Modals
like as
<div class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">{{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">
<p>{{MODAL_BODY}}</p>
</div>
<div class="modal-footer">
<button type="button" (click)="function_1()" class="btn btn-primary">SUBMIT</button>
</div>
</div>
</div>
</div>
I called a function when I clicked the Submit button. Well, I just want to change the function that submit function called in different cases.
So the thing that I just want to do in ts file:
MODAL_BODY = "BODY STRING";
MODAL_TITLE: FUNCTION ;
modal.show();
function1(){
console.log("function 1 works"}
}
function2(){
console.log("function 2 works")
}
I want to use function2() instead of function1() sometimes.
Then I want to change function that submit button called in different situations just like as:
<button type="button" (click)="function_1()" class="btn btn-primary">SUBMIT</button>
//some times i need to use this button below. so I need to change it from ts file
<button type="button" (click)="function_2()" class="btn btn-primary">SUBMIT</button>
Is there anyway to do that? from ts file or dynamically?
Thanks in advance.
If we want to change dynamically the button itself in the template the *ngIf structural directive can be used. (As chrnx writes in the question comment.)
To have an example for this take a look at the example below.
In Angular template code:
<p>
Used button
<br />
<button *ngIf="displayedButton === 1" (click)="onButtonOneClick()">
ButtonOne
</button>
<button *ngIf="displayedButton === 2" (click)="onButtonTwoClick()">
ButtonTwo
</button>
</p>
<p>
Change button state
<br />
<button (click)="onChangeStateClick()">Change</button>
</p>
In component code:
import { Component } from "#angular/core";
#Component({
selector: "my-app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
displayedButton = 1;
onButtonOneClick() {
console.log("Button 1 click");
}
onButtonTwoClick() {
console.log("Button 2 click");
}
onChangeStateClick() {
this.displayedButton = this.displayedButton === 1 ? 2 : 1;
}
}
Stackblitz example:
https://stackblitz.com/edit/angular-ivy-irmbkk?file=src/app/app.component.ts
this is regarding Vue.js question
i'm trying to open bootstrap model form inside the Vue template
i use two vue template components,
this sub component call inside this competence and pass data from this to sub component
this component use for show particular (load one by one products) model data
so i need to show one by one products data on the model form (when product 1 show name 'Abc') like this
but i cant do this.. all implementation are done and working fine
but cant show the particular data on the model form
show it only first loop value (i have 3 products all load in the table,but when click edit button first product show correctly,but click 2nd product show first product data)
but when i call console.log function and view when open the model show particular data in the console, but not showing its on the model form
why it that
i put my code segment in the below
example-component
<tbody >
<tr div v-for="invoices in invoice">
<th class="invoice_name ">{{invoices.p_name}}</th>
<td class="unit">
<sub-com :pID=invoices.p_id :invoice=invoices :invoiceID=invoice_id></sub-com>
</td>
</tr>
</tbody>
sub-com
<template>
<div>
<div class="form-group">
Refund
</div>
<div class="col-md-6">
<div class="modal fade" id="refundModel" tabindex="-1" role="dialog" aria-labelledby="addNewLabel"
aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" 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>
</div>
<form>
<div class="modal-body">
<div class="form-group">
<input v-model="form.name" type="text" name="name" placeholder="Name" class="form-control">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger" data-dismiss="modal">Close</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</template>
this is sub.vue script segment
<script>
export default{
data(){
return{
form: {
name:''
}
}
},
props: {
pID: String,
invoiceID:String,
invoice:{},
}
methods: {
refundMethod(invoices){
this.form.name = invoices.p_name;
console.log(invoices.p_name);
$('#refundModel').modal('show');
}
}
There are a couple of issues that might clear things up.
First you need to add a key to your template v-for loop:
<tr v-for="invoices in invoice" :key="invoices.p_id">
Second you are using jquery to trigger the modal which could work but you will have to generate unique ids for each div:
<div :id="'refundModel_'+pID">
A more Vue way to do this is to use the bootstrap data-show attribute and link it to a Boolean modal property in your data:
<div :data-show="modal" :id="'refundModel_'+pID">
export default {
data(){
return{
modal : false,
form: {
name:''
}
}
},
props: {
pID: String,
invoiceID: String,
invoice: Object,
}
methods: {
refundMethod(invoices){
this.form.name = invoices.p_name;
console.log(invoices.p_name);
this.toggleModal()
}
toggleModal () {
this.modal = !this.modal
}
}
}
I have this button in react:
<button type="button" className="btn btn-primary" onClick={()=>openPopUp(object)}>
Manage Permissions
</button>
and when I click the buton I want to open this popUp:
PopUp.js:
const PopUp = (props) => {
return (
<div className="modal fade" tabIndex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">{props.object.name}</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
{props.object.permissions.map((permission) => {
return (
<li key={permission.code}>
{permission.name}
{props.showDeleteButton(permission.id, props.object.name)}
<p> </p>
</li>
)
})}
<form onSubmit={e => props.addPermission(e, props.object)}>
<label>
Insert a permission:
<input type="text" value={props.object.value} onChange={props.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
</div>
</div>
</div>
</div>
)
}
To do that, I did this, but the pop up wont open:
let openPopUp=(object)=>{
return <PopUp object={object} cont={cont} onChange={handleChange} addPermission={addPermission} showDeleteButton={showDeleteButton}/>
}
There is any error thrown, the popUp just doesn´t open.
It is because openPopUp is a onclick handler, it will not return anything to render. To achieve your goal, simply use a state variable with initial value as false, and update that value in openPopUp method. Use that bool for conditional rendering of PopUp component.
Like this:
constructor() {
super();
this.state = {
openPopUp: false,
object: null
}
}
openPopUp(object) {
this.setState({
openPopUp: true,
object: object
})
}
render() {
return (
<div>
....
{this.state.openPopUp &&
<PopUp object={this.state.object} cont={cont} onChange={handleChange} addPermission={addPermission} showDeleteButton={showDeleteButton} />}
....
</div>
)
}
I'm having difficulty on passing the index from button to button so here is my code. Tthe first one is the render loop that shows all my rows and its button the button at the delete part is calling the index from the row.
renderItem(d, i) {
return <tr key={i} >
<td> {d.Employee_ID} </td>
<td>{d.Employee_Name}</td>
<td>{d.Address }</td>
<td><center><button className ="btn btn-info" onClick={this.handleOnclick.bind(this, d.Employee_ID, d.Employee_Name, d.Address , d.Department)} data-toggle="modal" data-target="#UpdateEmployee">Edit</button></center></td>
// this part is calling button is calling the {i} or what we call the index
<td><center><button className ='btn btn-danger' onClick={this.handleOnclick.bind(this, d.Employee_ID , d.Employee_Name,i)} data-toggle="modal" data-target="#DeleteEmployee"> Delete</button></center></td>
</tr>
}
this is where it proceed to my modal
{/*Delete*/}
<div className="modal fade" id="DeleteEmployee" role="dialog">
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-header">
<button type="button" className="close" data-dismiss="modal">×</button>
<h4 className="modal-title">Delete Employee</h4>
</div>
<div className="container">
<div className="modal-body">
Are you sure you want to delete {this.state.Employee_Name}?
</div>
</div>
<div className="modal-footer">
// I tried calling the index here but the modal can't see my index
<input type="submit" className ="btn btn-danger" data-dismiss="modal" onClick={this.deleteEmployee.bind(this, this.state.Employee_ID ,this.state.i)}/>
<button type="button" className="btn btn-default" data-dismiss="modal" >Close</button>
</div>
</div>
</div>
</div>
but the onclick on my modal can't see the index, because it always delete the first row
deleteEmployee(id, index) {
jQuery.support.cors = true;
fetch('http://localhost:5118/api/employeedetails/DeleteEmployeeDetail/'+ id, {
method: 'GET'
}).then(function(response) {
// history.go(0);
var jsonReturnedValue = [...this.state.jsonReturnedValue];
this.setState({jsonReturnedValue})
}).catch(function(err) {
// Error :(
});
this.state.jsonReturnedValue.splice(index, 1)
this.setState({})
}
PS: The delete works my problem was only the ajax
You are passing the emplyee ID into the bind function as a parameter, which doesn't make sense at all, what you need to do is pass the employee ID to the deleteEmployee function, like this:
onClick={() => this.deleteEmployee(d.Employee_ID , d.Employee_Name,i).bind(this)}
Also just as an extra information start using ES6's awsesome arrow function and you don't have to bind the this everytime, for instance in your case just change the above click handler to:
onClick={() => this.deleteEmployee(d.Employee_ID , d.Employee_Name,i)}
and your deleteEmployee function should look like this:
deleteEmployee = (id, index) => {
jQuery.support.cors = true;
fetch('http://localhost:5118/api/employeedetails/DeleteEmployeeDetail/'+ id, {
method: 'GET'
}).then(function(response) {
// history.go(0);
var jsonReturnedValue = [...this.state.jsonReturnedValue];
this.setState({jsonReturnedValue})
}).catch(function(err) {
// Error :(
});
this.state.jsonReturnedValue.splice(index, 1)
this.setState({})
}
for the button you should change it
<td><center><button className ='btn btn-danger' onClick={this.handleOnclick2.bind (this,d.Employee_ID,d.Employee_Name,i)} data-toggle="modal" data-target="#DeleteEmployee"> Delete</button></center></td>
and add the bind in your constructor
constructor() {
super();
this.state = { jsonReturnedValue: []}
this.handleOnclick2= this.handleOnclick2.bind(this)
}