Hi I wanted to print a specific div that has a canvas consisting of a chart. I had written a script to print the specific div in my HTML body tag but it returns everything except the graph.
This is what I want:
This is what I get:
How can I achieve the results shown in image 1? Thanks in advance.
This is my code for the script:
<script>
//Print specific div
function printFunc() {
var tagname = $('#div-report').prop("tagName").toLowerCase();
var attributes = "";
var attrs = document.getElementById("div-report").attributes;
$.each(attrs, function(i, elem) {
attributes += " " + elem.name + " ='" + elem.value + "' ";
})
var divToPrint = $('#div-report').html();
var head = "<html><head>" + $("head").html() + "</head>";
var allcontent = head + "<body onload='window.print()' >" + "<" + tagname + attributes + ">" + divToPrint + "</" + tagname + ">" + "</body></html>";
var newWin = window.open('', 'Print-Window');
newWin.document.open();
newWin.document.write(allcontent);
newWin.document.close();
};
</script>
This is my code for the front-end HTML(in case you need it):
<body class="d-flex flex-column">
<div class="container p-2 pb-0 mt-5 pt-3" id="admin-dashboard">
<h2 class="pt-3 pb-5 display-6">Report Summary</h2>
<div class="row g-2 mb-5 justify-content-md-end">
<div class="col-auto">
<button type="button" onclick="printFunc()" class="btn btn-outline-primary" style="--bs-btn-padding-y: .5rem; --bs-btn-padding-x: 1rem; --bs-btn-font-size: .75rem;">Print</button>
</div>
</div>
</div>
<div class="container pb-0" id="div-report">
<div ALIGN=CENTER>
<b>
<h6>Report Summary Generated on DD/MM/YYYY
</b>
</div>
<br />
<div ALIGN=CENTER>
<p>
Demo
</p>
</div>
<a class=" nav nav-item text-decoration-none text-muted" href="cstaff-report-generation.php">
<i class="bi bi-arrow-left-square me-2"></i>Go back</a>
<div class="row row-cols-2 row-cols-md-3 g-3 py-3">
<div class="col">
<div class="card border-info">
<div class="card-body">
<h6 class="card-title">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" class="bi bi-cash" viewBox="0 0 16 16">
<path d="M8 10a2 2 0 1 0 0-4 2 2 0 0 0 0 4z" />
<path d="M0 4a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v8a1 1 0 0 1-1 1H1a1 1 0 0 1-1-1V4zm3 0a2 2 0 0 1-2 2v4a2 2 0 0 1 2 2h10a2 2 0 0 1 2-2V6a2 2 0 0 1-2-2H3z" />
</svg>
Total Sales Revenue
</h6>
<p class="card-text my-2">
Demo
</p>
</div>
</div>
</div>
<div class="col">
<div class="card border-info">
<div class="card-body">
<h6 class="card-title">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" class="bi bi-receipt" viewBox="0 0 16 16">
<path d="M1.92.506a.5.5 0 0 1 .434.14L3 1.293l.646-.647a.5.5 0 0 1 .708 0L5 1.293l.646-.647a.5.5 0 0 1 .708 0L7 1.293l.646-.647a.5.5 0 0 1 .708 0L9 1.293l.646-.647a.5.5 0 0 1 .708 0l.646.647.646-.647a.5.5 0 0 1 .708 0l.646.647.646-.647a.5.5 0 0 1 .801.13l.5 1A.5.5 0 0 1 15 2v12a.5.5 0 0 1-.053.224l-.5 1a.5.5 0 0 1-.8.13L13 14.707l-.646.647a.5.5 0 0 1-.708 0L11 14.707l-.646.647a.5.5 0 0 1-.708 0L9 14.707l-.646.647a.5.5 0 0 1-.708 0L7 14.707l-.646.647a.5.5 0 0 1-.708 0L5 14.707l-.646.647a.5.5 0 0 1-.708 0L3 14.707l-.646.647a.5.5 0 0 1-.801-.13l-.5-1A.5.5 0 0 1 1 14V2a.5.5 0 0 1 .053-.224l.5-1a.5.5 0 0 1 .367-.27zm.217 1.338L2 2.118v11.764l.137.274.51-.51a.5.5 0 0 1 .707 0l.646.647.646-.646a.5.5 0 0 1 .708 0l.646.646.646-.646a.5.5 0 0 1 .708 0l.646.646.646-.646a.5.5 0 0 1 .708 0l.646.646.646-.646a.5.5 0 0 1 .708 0l.646.646.646-.646a.5.5 0 0 1 .708 0l.509.509.137-.274V2.118l-.137-.274-.51.51a.5.5 0 0 1-.707 0L12 1.707l-.646.647a.5.5 0 0 1-.708 0L10 1.707l-.646.647a.5.5 0 0 1-.708 0L8 1.707l-.646.647a.5.5 0 0 1-.708 0L6 1.707l-.646.647a.5.5 0 0 1-.708 0L4 1.707l-.646.647a.5.5 0 0 1-.708 0l-.509-.51z" />
<path d="M3 4.5a.5.5 0 0 1 .5-.5h6a.5.5 0 1 1 0 1h-6a.5.5 0 0 1-.5-.5zm0 2a.5.5 0 0 1 .5-.5h6a.5.5 0 1 1 0 1h-6a.5.5 0 0 1-.5-.5zm0 2a.5.5 0 0 1 .5-.5h6a.5.5 0 1 1 0 1h-6a.5.5 0 0 1-.5-.5zm0 2a.5.5 0 0 1 .5-.5h6a.5.5 0 0 1 0 1h-6a.5.5 0 0 1-.5-.5zm8-6a.5.5 0 0 1 .5-.5h1a.5.5 0 0 1 0 1h-1a.5.5 0 0 1-.5-.5zm0 2a.5.5 0 0 1 .5-.5h1a.5.5 0 0 1 0 1h-1a.5.5 0 0 1-.5-.5zm0 2a.5.5 0 0 1 .5-.5h1a.5.5 0 0 1 0 1h-1a.5.5 0 0 1-.5-.5zm0 2a.5.5 0 0 1 .5-.5h1a.5.5 0 0 1 0 1h-1a.5.5 0 0 1-.5-.5z" />
</svg>
Total Number of Order Placed
</h6>
<p class="card-text my-2">
Demo
</p>
</div>
</div>
</div>
<div class="col">
<div class="card border-info">
<div class="card-body">
<h6 class="card-title">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" class="bi bi-person-check" viewBox="0 0 16 16">
<path d="M6 8a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm2-3a2 2 0 1 1-4 0 2 2 0 0 1 4 0zm4 8c0 1-1 1-1 1H1s-1 0-1-1 1-4 6-4 6 3 6 4zm-1-.004c-.001-.246-.154-.986-.832-1.664C9.516 10.68 8.289 10 6 10c-2.29 0-3.516.68-4.168 1.332-.678.678-.83 1.418-.832 1.664h10z" />
<path fill-rule="evenodd" d="M15.854 5.146a.5.5 0 0 1 0 .708l-3 3a.5.5 0 0 1-.708 0l-1.5-1.5a.5.5 0 0 1 .708-.708L12.5 7.793l2.646-2.647a.5.5 0 0 1 .708 0z" />
</svg>
Total Number of Customer Visited
</h6>
<p class="card-text my-2">
Demo
</p>
</div>
</div>
</div>
<div class="col">
<div class="card border-info">
<div class="card-body">
<h6 class="card-title">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" class="bi bi-diagram-2" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M6 3.5A1.5 1.5 0 0 1 7.5 2h1A1.5 1.5 0 0 1 10 3.5v1A1.5 1.5 0 0 1 8.5 6v1H11a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-1 0V8h-5v.5a.5.5 0 0 1-1 0v-1A.5.5 0 0 1 5 7h2.5V6A1.5 1.5 0 0 1 6 4.5v-1zM8.5 5a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1zM3 11.5A1.5 1.5 0 0 1 4.5 10h1A1.5 1.5 0 0 1 7 11.5v1A1.5 1.5 0 0 1 5.5 14h-1A1.5 1.5 0 0 1 3 12.5v-1zm1.5-.5a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5h-1zm4.5.5a1.5 1.5 0 0 1 1.5-1.5h1a1.5 1.5 0 0 1 1.5 1.5v1a1.5 1.5 0 0 1-1.5 1.5h-1A1.5 1.5 0 0 1 9 12.5v-1zm1.5-.5a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5h-1z" />
</svg>
Best-Selling Menu Item
</h6>
<p class="card-text my-2">
Demo
</p>
</div>
</div>
</div>
<div class="col">
<div class="card border-info">
<div class="card-body">
<h6 class="card-title">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" class="bi bi-hourglass-split" viewBox="0 0 16 16">
<path d="M2.5 15a.5.5 0 1 1 0-1h1v-1a4.5 4.5 0 0 1 2.557-4.06c.29-.139.443-.377.443-.59v-.7c0-.213-.154-.451-.443-.59A4.5 4.5 0 0 1 3.5 3V2h-1a.5.5 0 0 1 0-1h11a.5.5 0 0 1 0 1h-1v1a4.5 4.5 0 0 1-2.557 4.06c-.29.139-.443.377-.443.59v.7c0 .213.154.451.443.59A4.5 4.5 0 0 1 12.5 13v1h1a.5.5 0 0 1 0 1h-11zm2-13v1c0 .537.12 1.045.337 1.5h6.326c.216-.455.337-.963.337-1.5V2h-7zm3 6.35c0 .701-.478 1.236-1.011 1.492A3.5 3.5 0 0 0 4.5 13s.866-1.299 3-1.48V8.35zm1 0v3.17c2.134.181 3 1.48 3 1.48a3.5 3.5 0 0 0-1.989-3.158C8.978 9.586 8.5 9.052 8.5 8.351z" />
</svg>
Peak Hour
</h6>
<p class="card-text my-2">
Demo
</p>
</div>
</div>
</div>
</div>
<br />
<h4 class="border-top fw-light pt-3 mt-2">Menu Performance</h4>
<div class="container p-2 pb-0 mt-2 mb-5 pt-3" style="text-align: center;">
<canvas id="mpChart"></canvas>
</div>
</div>
I'm trying to fetch data from webapi to display in react js tables, everything seems to work fine only text is not being displayed in these table the look empty[!
What might be the problem here, because I can't figure it out for days.
Image of Table
this is the error Im getting in console
This is my Department.js file
import React,{Component} from 'react';
import { Table } from 'react-bootstrap';
import { ModalBody, ModalTitle } from 'react-bootstrap';
import { variables } from './variables';
export class Department extends Component{
constructor(props){
super(props);
this.state={
departments:[],
modalTitle:"",
DepartmentName:"",
DepartmentId:0,
DepartmentIdFilter:"",
DepartmentNameFilter:"",
departmentsWithoutFilter:[]
}
}
FilterFn(){
var DepartmentIdFilter=this.state.DepartmentIdFilter;
var DepartmentNameFilter = this.state.DepartmentNameFilter;
var filteredData=this.state.departmentsWithoutFilter.filter(
function(el){
return el.DepartmentId.toString().toLowerCase().includes(
DepartmentIdFilter.toString().trim().toLowerCase()
)&&
el.DepartmentName.toString().toLowerCase().includes(
DepartmentNameFilter.toString().trim().toLowerCase()
)
}
);
this.setState({departments:filteredData});
}
sortResult(prop,asc){
var sortedData=this.state.departmentsWithoutFilter.sort(function(a,b){
if(asc){
return (a[prop]>b[prop])?1:((a[prop]<b[prop])?-1:0);
}
else{
return (b[prop]>a[prop])?1:((b[prop]<a[prop])?-1:0);
}
});
this.setState({departments:sortedData});
}
changeDepartmentIdFilter = (e)=>{
this.state.DepartmentIdFilter=e.target.value;
this.FilterFn();
}
changeDepartmentNameFilter = (e)=>{
this.state.DepartmentNameFilter=e.target.value;
this.FilterFn();
}
refreshList(){
fetch(variables.API_URL+'departments')
.then(response=>response.json())
.then(data=>{
this.setState({departments:data,departmentsWithoutFilter:data});
});
}
componentDidMount(){
this.refreshList();
}
changeDepartmentName =(e)=>{
this.setState({DepartmentName:e.target.value});
}
addClick(){
this.setState({
modalTitle:"Add Department",
DepartmentId:0,
DepartmentName:""
});
}
editClick(dep){
this.setState({
modalTitle:"Edit Department",
DepartmentId:dep.DepartmentId,
DepartmentName:dep.DepartmentName
});
}
createClick(){
fetch(variables.API_URL+'departments',{
method:'POST',
headers:{
'Accept':'application/json',
'Content-Type':'application/json'
},
body:JSON.stringify({
DepartmentName:this.state.DepartmentName
})
})
.then(res=>res.json())
.then((result)=>{
alert(result);
this.refreshList();
},(error)=>{
alert('Failed');
})
}
updateClick(){
fetch(variables.API_URL+'departments',{
method:'PUT',
headers:{
'Accept':'application/json',
'Content-Type':'application/json'
},
body:JSON.stringify({
DepartmentId:this.state.DepartmentId,
DepartmentName:this.state.DepartmentName
})
})
.then(res=>res.json())
.then((result)=>{
alert(result);
this.refreshList();
},(error)=>{
alert('Failed');
})
}
deleteClick(id){
if(window.confirm('Are you sure?')){
fetch(variables.API_URL+'departments/'+ id,{
mode:'no-cors',
method:'DELETE',
headers:{
'Accept':'application/json',
'Content-Type':'application/json'
}
})
.then(res=>res.json())
.then((result)=>{
alert(result);
this.refreshList();
},(error)=>{
alert('Failed');
})
}
}
render(){
const {
departments,
modalTitle,
DepartmentId,
DepartmentName
}=this.state;
return(
<div>
<button type="button"
className="btn btn-primary m-2 float-end"
data-bs-toggle="modal"
data-bs-target="#exampleModal"
onClick={()=>this.addClick()}>
Add Department
</button>
<table className="table table-striped">
<thead>
<tr key={Department.id}>
<th>
<div className="d-flex flex-row">
<input className="form-control m-2"
onChange={this.changeDepartmentIdFilter}
placeholder="Filter"/>
<button type="button" className="btn btn-light"
onClick={()=>this.sortResult('DepartmentId',true)}>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" className="bi bi-arrow-down-square-fill" viewBox="0 0 16 16">
<path d="M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2zm6.5 4.5v5.793l2.146-2.147a.5.5 0 0 1 .708.708l-3 3a.5.5 0 0 1-.708 0l-3-3a.5.5 0 1 1 .708-.708L7.5 10.293V4.5a.5.5 0 0 1 1 0z"/>
</svg>
</button>
<button type="button" className="btn btn-light"
onClick={()=>this.sortResult('DepartmentId',false)}>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" className="bi bi-arrow-up-square-fill" viewBox="0 0 16 16">
<path d="M2 16a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H2zm6.5-4.5V5.707l2.146 2.147a.5.5 0 0 0 .708-.708l-3-3a.5.5 0 0 0-.708 0l-3 3a.5.5 0 1 0 .708.708L7.5 5.707V11.5a.5.5 0 0 0 1 0z"/>
</svg>
</button>
</div>
DepartmentId
</th>
<th>
<div className="d-flex flex-row">
<input className="form-control m-2"
onChange={this.changeDepartmentNameFilter}
placeholder="Filter"/>
<button type="button" className="btn btn-light"
onClick={()=>this.sortResult('DepartmentName',true)}>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" className="bi bi-arrow-down-square-fill" viewBox="0 0 16 16">
<path d="M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2zm6.5 4.5v5.793l2.146-2.147a.5.5 0 0 1 .708.708l-3 3a.5.5 0 0 1-.708 0l-3-3a.5.5 0 1 1 .708-.708L7.5 10.293V4.5a.5.5 0 0 1 1 0z"/>
</svg>
</button>
<button type="button" className="btn btn-light"
onClick={()=>this.sortResult('DepartmentName',false)}>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" className="bi bi-arrow-up-square-fill" viewBox="0 0 16 16">
<path d="M2 16a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H2zm6.5-4.5V5.707l2.146 2.147a.5.5 0 0 0 .708-.708l-3-3a.5.5 0 0 0-.708 0l-3 3a.5.5 0 1 0 .708.708L7.5 5.707V11.5a.5.5 0 0 0 1 0z"/>
</svg>
</button>
</div>
DepartmentName
</th>
<th>
Options
</th>
</tr>
</thead>
<tbody>
{departments.map(dep=>
<tr key={dep.DepartmentId}>
<td>{dep.DepartmentId}</td>
<td>{dep.DepartmentName}</td>
<td>
<button type="button"
className="btn btn-light mr-1"
data-bs-toggle="modal"
data-bs-target="#exampleModal"
onClick={()=>this.editClick(dep)}>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" className="bi bi-pencil-square" viewBox="0 0 16 16">
<path d="M15.502 1.94a.5.5 0 0 1 0 .706L14.459 3.69l-2-2L13.502.646a.5.5 0 0 1 .707 0l1.293 1.293zm-1.75 2.456-2-2L4.939 9.21a.5.5 0 0 0-.121.196l-.805 2.414a.25.25 0 0 0 .316.316l2.414-.805a.5.5 0 0 0 .196-.12l6.813-6.814z"/>
<path fillRule="evenodd" d="M1 13.5A1.5 1.5 0 0 0 2.5 15h11a1.5 1.5 0 0 0 1.5-1.5v-6a.5.5 0 0 0-1 0v6a.5.5 0 0 1-.5.5h-11a.5.5 0 0 1-.5-.5v-11a.5.5 0 0 1 .5-.5H9a.5.5 0 0 0 0-1H2.5A1.5 1.5 0 0 0 1 2.5v11z"/>
</svg>
</button>
<button type="button"
className="btn btn-light mr-1"
onClick={()=>this.deleteClick(dep.DepartmentId)}>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" className="bi bi-trash-fill" viewBox="0 0 16 16">
<path d="M2.5 1a1 1 0 0 0-1 1v1a1 1 0 0 0 1 1H3v9a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V4h.5a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1H10a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1H2.5zm3 4a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 .5-.5zM8 5a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7A.5.5 0 0 1 8 5zm3 .5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 1 0z"/>
</svg>
</button>
</td>
</tr>
)}
</tbody>
</table>
<div className="modal fade" id="exampleModal" tabIndex="-1" aria-hidden="true">
<div className="modal-dialog modal-lg modal-dialog-centered">
<div className="modal-content">
<div className="modal-header">
<h5 className="modal-title">{modalTitle}</h5>
<button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close"
></button>
</div>
<div className="modal-body">
<div className="input-group mb-3">
<span className="input-group-text">DepartmentName</span>
<input type="text" className="form-control"
value={DepartmentName}
onChange={this.changeDepartmentName}/>
</div>
{DepartmentId===0?
<button type="button"
className="btn btn-primary float-start"
onClick={()=>this.createClick()}
>Create</button>
:null}
{DepartmentId!==0?
<button type="button"
className="btn btn-primary float-start"
onClick={()=>this.updateClick()}
>Update</button>
:null}
</div>
</div>
</div>
</div>
</div>
)
}
}```
This is my Program.cs
using Microsoft.EntityFrameworkCore;
using WebApp.Data;
var myAllowSpecificOrigins = "_myAllowSpecificOrigins";
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddDbContext<DataContext>(options =>
{
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"));
});
//Enable CORS
builder.Services.AddCors(options =>
{
options.AddPolicy(name: myAllowSpecificOrigins,
builder =>
{
builder.WithOrigins("http://localhost:3000")
.AllowAnyMethod()
.AllowAnyHeader();
});
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseCors(myAllowSpecificOrigins);
app.UseAuthorization();
app.MapControllers();
app.Run();
What might be the problem here, because I can't figure it out for days.
Does anyone had the same issue?
It looks like I have done something wrong in react js file
I am creating a shopping cart page and the quantity part, of all inputs only one of the inputs works and it's value changes
where am i doing wrong??
$('.minus').attr('id', 'minus');
$('.plus').attr('id', 'plus');
const minus = document.getElementById('minus')
const plus = document.getElementById('plus')
plus.addEventListener("click", () => {
var count = document.querySelector('[title="Qty"]').value;
count++;
document.querySelector('[title="Qty"]').value = count;
});
minus.addEventListener("click", () => {
var count = document.querySelector('[title="Qty"]').value;
if(count >1){
count--;
document.querySelector('[title="Qty"]').value = count;
}
});
<div class="padding-td">
<button class="btn border text-danger minus"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-dash" viewBox="0 0 16 16">
<path d="M4 8a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7A.5.5 0 0 1 4 8z"/>
</svg>
</button>
<input type="number" title="Qty" value="<?php echo $cart_item["quantity"]?>" min="1" class="form-control w-25 d-inline-block input">
<button class="btn border text-danger plus"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-plus" viewBox="0 0 16 16">
<path d="M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4z"/>
</svg>
</button>
</div>
I have a table that displays the content from a model whenever someone accesses the URL /project_page.
On that page, the user can add files and I would like the table to be updated in real-time without having to constantly refresh.
For that purpose, I have tried to implement an Ajax function that updates the table content every few seconds. Since it is something that was suggested a few years ago here
I think the function is implemented and I receive the data properly in the Ajax success function but I don't know how to 'inject it' to the table.
I would also like to know if there is a more optimal or pythonic way to achieve this result.
urls.py
path('project_page_ajax/', views.project_page_ajax, name='project_page_ajax'),
views.py
#login_required
def project_page(request):
context = {}
context['nbar'] = 'projects'
if request.method == 'POST':
print(request.FILES)
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
file_hist = form.save(commit=False)
file_hist.user = request.user
# file is saved
file_hist.save()
file_hist_results = FileHistory.objects.all().filter(user=request.user)
context['file_hist_results'] = file_hist_results
print(type(context['file_hist_results']))
return render(request, 'project_page.html', context)
print (form.errors)
else:
form = UploadFileForm()
file_hist_results = FileHistory.objects.all().filter(user=request.user)
context['file_hist_results'] = file_hist_results
context['form'] = form
return render(request, 'project_page.html', context)
#login_required
def project_page_ajax(request):
response = dict()
if request.method == 'GET':
file_hist_results = FileHistory.objects.all().filter(user=request.user).values()
#response.update({'file_hist_results': file_hist_results})
return JsonResponse({"file_hist_results": list(file_hist_results)})
return HttpResponse('')
project_page.html (JS PART)
var intervalID = setInterval(updateTable, 10000);
function updateTable()
{
$.ajax({
method: "GET",
url: "/project_page_ajax/",
success: function(data, textStatus, request) {
console.log(data);
}
});
}
project_page.html(HTML PART)
<table id="ittFileUploadTable" class="display nowrap" width="100%">
<thead>
<tr class="ittLineItemsTh">
<th style="text-align:center;">File Name</th>
<th style="text-align:center;">Submitted</th>
<th style="text-align:center;">Updated</th>
<th style="text-align:center;">User</th>
<th style="text-align:center;">Action</th>
</tr>
</thead>
<tbody>
{% for histfiles in file_hist_results %}
<tr>
<td>{{ histfiles.filename }}</td>
<td>{{ histfiles.uploaded }}</td>
<td>{{ histfiles.updated }}</td>
<td>{{ histfiles.user }}</td>
<td>
<button id="delete-itt-file" type="button" class="btn btn-secondary">
<svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" fill="currentColor" class="bi bi-trash-fill" viewBox="0 0 16 16">
<path d="M2.5 1a1 1 0 0 0-1 1v1a1 1 0 0 0 1 1H3v9a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V4h.5a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1H10a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1H2.5zm3 4a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 .5-.5zM8 5a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7A.5.5 0 0 1 8 5zm3 .5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 1 0z"></path>
</svg>
</button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
this question is more related to javascript.but here is my idea how you can solve this with partial_html.This is just an idea how you can do it but maybe a javascript guy will come with a beautifull answer ))).
views.py
from django.shortcuts import redirect
#login_required
def project_page(request):
context = {}
context['nbar'] = 'projects'
if request.method == 'POST':
print(request.FILES)
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
file_hist = form.save(commit=False)
file_hist.user = request.user
# file is saved
file_hist.save()
return redirect('project_page')
print (form.errors)
else:
form = UploadFileForm()
file_hist_results = FileHistory.objects.all().filter(user=request.user)
context['file_hist_results'] = file_hist_results
context['form'] = form
return render(request, 'project_page.html', context)
#login_required
def project_page_ajax(request):
response = dict()
if request.method == 'GET':
file_hist_results = FileHistory.objects.all().filter(user=request.user).values()
return render(request, 'partial_page.html', {'file_hist_results':file_hist_results})
project_page.html
<table id="ittFileUploadTable" class="display nowrap" width="100%">
<thead>
<tr class="ittLineItemsTh">
<th style="text-align:center;">File Name</th>
<th style="text-align:center;">Submitted</th>
<th style="text-align:center;">Updated</th>
<th style="text-align:center;">User</th>
<th style="text-align:center;">Action</th>
</tr>
</thead>
<tbody>
{% for histfiles in file_hist_results %}
<tr>
<td>{{ histfiles.filename }}</td>
<td>{{ histfiles.uploaded }}</td>
<td>{{ histfiles.updated }}</td>
<td>{{ histfiles.user }}</td>
<td>
<button id="delete-itt-file" type="button" class="btn btn-secondary">
<svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" fill="currentColor" class="bi bi-trash-fill" viewBox="0 0 16 16">
<path d="M2.5 1a1 1 0 0 0-1 1v1a1 1 0 0 0 1 1H3v9a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V4h.5a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1H10a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1H2.5zm3 4a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 .5-.5zM8 5a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7A.5.5 0 0 1 8 5zm3 .5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 1 0z"></path>
</svg>
</button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
partial_page.html(just a simple html do not put any body or head tag just this create that file with only this)
<table id="ittFileUploadTable" class="display nowrap" width="100%">
<thead>
<tr class="ittLineItemsTh">
<th style="text-align:center;">File Name</th>
<th style="text-align:center;">Submitted</th>
<th style="text-align:center;">Updated</th>
<th style="text-align:center;">User</th>
<th style="text-align:center;">Action</th>
</tr>
</thead>
<tbody>
{% for histfiles in file_hist_results %}
<tr>
<td>{{ histfiles.filename }}</td>
<td>{{ histfiles.uploaded }}</td>
<td>{{ histfiles.updated }}</td>
<td>{{ histfiles.user }}</td>
<td>
<button id="delete-itt-file" type="button" class="btn btn-secondary">
<svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" fill="currentColor" class="bi bi-trash-fill" viewBox="0 0 16 16">
<path d="M2.5 1a1 1 0 0 0-1 1v1a1 1 0 0 0 1 1H3v9a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V4h.5a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1H10a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1H2.5zm3 4a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 .5-.5zM8 5a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7A.5.5 0 0 1 8 5zm3 .5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 1 0z"></path>
</svg>
</button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
js
var intervalID = setInterval(updateTable, 10000);
function updateTable()
{
$.ajax({
method: "GET",
url: "/project_page_ajax/",
success: function(response) {
$("#ittFileUploadTable").hide(); // first hide the current table
$("#ittFileUploadTable").append(response); // and append the data
}
});
}
The solution largely depends on what the JSON response is.
HTML
If your response is the actual HTML chunk to be displayed, looking somewhat like this:
<tr><!-- Some tds --></tr>
<tr><!-- Some tds --></tr>
<tr><!-- Some tds --></tr>
<!-- ... -->
<tr><!-- Some tds --></tr>
Then you can do it like this:
document.querySelector("#ittFileUploadTable tbody").innerHTML = yourTemplate;
JSON
If your data is JSON, then it would be great to create a template function, like this one:
function fileUploadRecordTemplate(record) {
return `
<td>record.filename</td>
<td>record.uploaded</td>
<td>record.updated</td>
<td>record.user</td>
<td>
<button id="delete-itt-file" type="button" class="btn btn-secondary">
<svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" fill="currentColor" class="bi bi-trash-fill" viewBox="0 0 16 16">
<path d="M2.5 1a1 1 0 0 0-1 1v1a1 1 0 0 0 1 1H3v9a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V4h.5a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1H10a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1H2.5zm3 4a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 .5-.5zM8 5a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7A.5.5 0 0 1 8 5zm3 .5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 1 0z"></path>
</svg>
</button>
</td>
`;
}
And hydrate your tbody like this:
let output = [];
for (let record of data) output.push(fileUploadRecordTemplate(record));
document.querySelector("#ittFileUploadTable tbody").innerHTML = yourTemplate;
Fiddle
let index = 1;
//t1
function updateT1() {
//We generate some HTML, but if you get an HTML from server-side, then you can
//skip this part
let template = "";
let rows = parseInt(document.getElementById("t1rows").value);
for (let i = 0; i < rows; i++) {
template += `
<tr>
<td>${index++}</td>
<td>${index++}</td>
<td>${index++}</td>
<td>${index++}</td>
</tr>
`;
}
//This is the actual operation which refreshes the HTML
document.querySelector("#t1 > tbody").innerHTML = template;
}
//t2
function fileUploadRecordTemplate(record) {
return `
<tr>
<td>${record.filename}</td>
<td>${record.uploaded}</td>
<td>${record.updated}</td>
<td>${record.user}</td>
<td>
<button id="delete-itt-file" type="button" class="btn btn-secondary">
<svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" fill="currentColor" class="bi bi-trash-fill" viewBox="0 0 16 16">
<path d="M2.5 1a1 1 0 0 0-1 1v1a1 1 0 0 0 1 1H3v9a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V4h.5a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1H10a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1H2.5zm3 4a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 .5-.5zM8 5a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7A.5.5 0 0 1 8 5zm3 .5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 1 0z"></path>
</svg>
</button>
</td>
</tr>
`;
}
function updateT2() {
let rows = parseInt(document.getElementById("t2rows").value);
let data = [];
for (let i = 0; i < rows; i++) {
data.push({
filename: index++,
uploaded: index++,
updated: index++,
user: index++
});
}
let output = [];
for (let record of data) output.push(fileUploadRecordTemplate(record));
document.querySelector("#t2 tbody").innerHTML = output.join("");
}
<table id="t1">
<thead>
<th>First</th>
<th>Second</th>
<th>Third</th>
<th>Fourth</th>
</thead>
<tbody>
</tbody>
</table>
Number of rows: <input type="number" value="4" id="t1rows"><input type="button" value="OK" onclick="updateT1()">
<table id="t2">
<thead>
<th>First</th>
<th>Second</th>
<th>Third</th>
<th>Fourth</th>
<th>Fifth</th>
</thead>
<tbody>
</tbody>
</table>
Number of rows: <input type="number" value="4" id="t2rows"><input type="button" value="OK" onclick="updateT2()">
I found a solution!
As #mark_b sugested, I used the datatables Ajax instead of jQuery AJAX
Now it works, here is my code:
$('#ittFileUploadTable').DataTable( {
responsive: true,
autowidth: false,
destroy: true,
deferRender: true,
ajax: {
url: '/project_page_ajax/',
type: 'GET',
data: {},
dataSrc: ""
},
columns: [
{"data": "fields.filename"},
{"data": "fields.uploaded"},
{"data": "fields.updated"},
{"data": "fields.user"},
{"data": "pk"},
],
columnDefs: [
{ className: 'text-center', targets: [1] },
{
targets: [0],
class: 'text-center',
orderable: false,
render: function (data, type, row) {
var buttons = ''+data+'';
return buttons;
}
},
{
targets: [-1],
class: 'text-center',
orderable: false,
render: function (data, type, row) {
var buttons = '<form method="post" action="delete_file/'+data+'/"><button type="submit" class="btn btn-danger"><svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" fill="white" class="bi bi-trash-fill" viewBox="0 0 16 16"><path d="M2.5 1a1 1 0 0 0-1 1v1a1 1 0 0 0 1 1H3v9a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V4h.5a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1H10a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1H2.5zm3 4a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 .5-.5zM8 5a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7A.5.5 0 0 1 8 5zm3 .5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 1 0z"/></svg></button></form>';
return buttons;
}
},
],
order: [
[0, 'asc']
],
"pagingType": "numbers",
dom: 'rt'
});
I'm trying to fetch data from mysql and pass the data to ejs file. I want to display the passed data as a html datatable. but it seems to not work.
I'm using sequelize and node js and ejs.
Here is how i implemented findAll() method
router.get('/list', function (req,res, next) {
player.findAll()
.then( players => {
console.log(data);
var data = res.json(players);
res.render("list", {data:data})
});
});
And here is where i want the data to be displayed.
<table>
<thead>
<tr>
<th scope="col"></th>
<th scope="col">Name</th>
<th scope="col">Last follow up date</th>
<th scope="col"></th>
<th scope="col"></th>
<th scope="col"></th>
</tr>
</thead>
<tbody id="Table-data">
<%if (typeof data != 'undefined'){ %>
<% data.forEach(function(row){ %>
<tr>
<td> 1 </td>
<td> <%= row.name %> </td>
<td> 15 </td>
<td>
<a href="./chart">
<span class="title">
<svg
width="1em"
height="1em"
viewBox="0 0 16 16"
class="bi bi-bar-chart-line"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill-rule="evenodd"
d="M11 2a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1v12h.5a.5.5 0 0 1 0 1H.5a.5.5 0 0 1 0-1H1v-3a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1v3h1V7a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1v7h1V2zm1 12h2V2h-2v12zm-3 0V7H7v7h2zm-5 0v-3H2v3h2z"
/>
</svg>
view
</span>
</a>
</td>
<td>
<a href="./edit">
<span class="title">
<svg
width="1em"
height="1em"
viewBox="0 0 16 16"
class="bi bi-pencil-square"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M15.502 1.94a.5.5 0 0 1 0 .706L14.459 3.69l-2-2L13.502.646a.5.5 0 0 1 .707 0l1.293 1.293zm-1.75 2.456l-2-2L4.939 9.21a.5.5 0 0 0-.121.196l-.805 2.414a.25.25 0 0 0 .316.316l2.414-.805a.5.5 0 0 0 .196-.12l6.813-6.814z"
/>
<path
fill-rule="evenodd"
d="M1 13.5A1.5 1.5 0 0 0 2.5 15h11a1.5 1.5 0 0 0 1.5-1.5v-6a.5.5 0 0 0-1 0v6a.5.5 0 0 1-.5.5h-11a.5.5 0 0 1-.5-.5v-11a.5.5 0 0 1 .5-.5H9a.5.5 0 0 0 0-1H2.5A1.5 1.5 0 0 0 1 2.5v11z"
/>
</svg>
edit
</span>
</a>
</td>
<td>
<a href="./addEnv">
<span class="title">
<svg
width="1em"
height="1em"
viewBox="0 0 16 16"
class="bi bi-plus-square"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill-rule="evenodd"
d="M14 1H2a1 1 0 0 0-1 1v12a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1zM2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2z"
/>
<path
fill-rule="evenodd"
d="M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4z"
/>
</svg>
add enviroment
</span>
</a>
</td>
</tr>
<% })} else{ %>
<tr>
<td colspan="6">No Record Found</td>
</tr>
<% } %>
</tbody>
</table>
The output always like this
output
Thank you for helping in advance
Try passing players directly to the template
router.get('/list', function (req,res, next) {
player.findAll()
.then(players => {
res.render("list", {data: players})
});