I have a CRUD reminder app, and when users right click on a reminder, a context menu pops up. Options include edit, delete, etc. Each reminder has an id, and the context menu button updates based on the reminders id, and passes it to a bootstrap modal form:
JS:
//part of the context menu script
//this function is called when the user right clicks inside of any element with class task
function toggleMenuOn(e) {
if ( menuState !== 1 ) {
menuState = 1;
menu.classList.add( contextMenuActive );
}
let reminder_id = e.target.id
$.ajax({
url: '/ajax/get_reminder/',
data: {
'reminder_id': reminder_id
},
dataType: 'json',
success: function (data) {
let context_btn1 = document.getElementById("context_menu_btn1");
let reminder_pk = data.serialized_reminder.toString();
let reminder_url = "{% url 'update-reminder' 0 %}".replace(/0/, reminder_pk)
context_btn1.className = "update-reminder context-menu__link btn btn-light";
context_btn1.setAttribute('data-id', reminder_url);
change_var(reminder_url)
}
});
}
let context_btn_id = "/update_reminder/0/";
function change_var(new_name) {
context_btn_id = new_name;
}
$(document).ready(function() {
$("#context_menu_btn1").click(function () {
$(this).modalForm({formURL: context_btn_id});
});
});
HTML:
<nav id="context-menu" class="context-menu">
<ul class="context-menu__items">
<li class="context-menu__item">
<button type="button" class="context-menu__link btn btn-light" id="context_menu_btn1" data-id=""><i class="fa fa-edit"></i> Edit</button>
</li>
<li class="context-menu__item">
<button type="button" class="context-menu__link btn btn-light" id="context_menu_btn2" data-id=""><i class="fa fa-times"></i> Delete</button>
</li>
<li class="context-menu__item">
<button type="button"class="context-menu__link btn btn-light" id="context_menu_btn3" data-id=""><i class="fa fa-eye"></i> Share</button>
</li>
</ul>
</nav>
Reminder HTML:
<div>
<h3 class="ml-4">Long-Term Assignments:</h3>
<div class="events-content-section ml-4 mr-3">
{% get_reminder_id user.username as id_reminders %}
{% for reminder_id, long_term_reminder in id_reminders.items %}
<div class="task mb-2" style="display: flex;">
<button type="button" class="view-reminder btn btn-light" data-id="{% url 'view-reminder' long_term_reminder.pk %}" id="{{ reminder_id }}" style="width: 100%;">
<h4 style="float: left;">{{ long_term_reminder.title }}</h4>
</button>
</div>
{% endfor %}
</div>
</div>
As you can see, I have one navigation menu and have buttons that change data-id every time it is shown. The code works the first time, but when I go to edit another reminder it just brings up the modal form for the first reminder. For example, if I were to update a reminder named Test1, and then try to edit Test2, it would bring up the edit form form for Test1.
I think it has something to do with the code not creating a new modalForm every time context_btn_id is updated. As a reference, the code below works, but an individual button is created for each reminder.
$(".view-reminder").each(function () {
$(this).modalForm({formURL: $(this).data('id')});
});
How would I solve this issue? Any help would be appreciated!
You can add a data-id attribute for each reminder in reminders list or table and on navigation click you can get the selected reminder id.
Related
today I've been trying to resolve this problem, but I can't figure it out how to "fix".
I'm creating a website using Flask, and when I'm clicking a button placed in a post form, I'd like to keep an action doing; to be more accurate, when I click the button, an action should be performed, but I'd like this action to be performed more times if I keep pressing the button. This is the structure of my layout and code.
Here is the python code
from flask import (
Blueprint, render_template, request
)
from webapp.Utilities.utilities import SerialHandler
from webapp.blueprints.decorators import login_required
bp = Blueprint('main', __name__)
serial_scheduler = SerialHandler()
#bp.route('/', methods=('GET', 'POST'))
#login_required
def index():
if request.method == 'POST':
button = request.form['press_to_run']
foo()
return render_template('index.html', title="Index")
And here the HTML structure
{% extends "layout.html" %}
{% block stylesheet %}
<link rel="stylesheet" href="{{ url_for('static', filename='index.css') }}">
{% endblock %}
{% block content %}
<div class="container new_container">
<div class="card" style="width: 18rem;">
<div class="card-header">
Featured
</div>
<ul class="list-group list-group-flush">
<li class="list-group-item">An item</li>
<li class="list-group-item">A second item</li>
<li class="list-group-item">A third item</li>
</ul>
</div>
</div>
<div class="container">
<img src="{{ url_for('video.video') }}" alt="">
</div>
<form class="" method="post">
<div class="btn-group" style="width:100%">
<button style="width:33.3%">Apple</button>
<button style="width:33.3%">Samsung</button>
<button style="width:33.3%">Sony</button>
</div>
</form>
<div class="container new_container">
<div class="col-md-12 text-center">
<button onclick="switch_theme()" class="btn btn-light shadow-none" id="switch_button" style="width: 15%;">Dark Mode</button>
</div>
</div>
<script>
function switch_theme() {
const theme = document.getElementById('switch_theme').className;
if(theme === "dark-theme") {
document.getElementById('switch_theme').className = "light-theme";
document.getElementById('switch_button').className = "btn btn-dark shadow-none";
document.getElementById('switch_button').innerHTML = "Light Mode";
} else {
document.getElementById('switch_theme').className = "dark-theme";
document.getElementById('switch_button').className = "btn btn-light shadow-none";
document.getElementById('switch_button').innerHTML = "Dark Mode";
}
}
</script>
{% endblock %}
To conclude I say that I don't necessarily need a solution with python, but I would also be fine with a solution that include maybe a javascript function that runs the python function of my SerialHandler object.
Thanks in advance for the answers.
The code you provided doesn't help much. From what I understood you want to call your flask API endpoint (that will call the python function) repeatedly if someone keeps pressing a button inside a form element. This can be done in the front end with JavaScript itself. Something like -
<form method="POST">
<button id="formbutton">Click me!</button>
</form>
<script>
// grab the button
formBtn = document.querySelector('#formbutton')
let isMouseDown = false
// don't send the form automatically
formBtn.addEventListener('click', function(e) {
e.preventDefault()
})
// keep track of isMouseDown
formBtn.addEventListener('mousedown', function(e) {
isMouseDown = true
})
formBtn.addEventListener('mouseup', function(e) {
isMouseDown = false
})
// how many times to call the backend
setInterval(function() {
if(isMouseDown) {
// can also use axios & pass custom data
fetch('http://your.server/end/point', {
method: 'POST'
}).then(res => console.log(resres))
}
}, 200)
</script>
This may not be the best way to do it but will get the job done. If there are multiple buttons just add them in an array & add event listeners on them in a loop.
I want to change current value from Dropdown...but getting problem with fetching value from dropdown. on show page current status are showing and dropdown option are there for update status.after click on button i want to show new status.
<script>
// Update record
$(document).ready(function(){
$('#nextStatusBtn').click(function(e){
e.preventDefault();
var status_id = $(this).attr("data-id");
console.log('status_id');
$.ajax({
url: "{{route('admin.leads.updateStatus',$leads->id)}}",
type: 'post',
data: {
_token: "{{csrf_token()}}",
status_id: status_id
}
});
});
});
</script>
public function updateStatus(Request $request, Lead_status $lead_status)
{
$status_id = $request->status_id;
$lead_id = $request->lead_id;
var_dump($status_id);
die;
$lead_status = new Lead_status;
$lead_status->user_id = Auth::user()->id;
$lead_status->lead_id = $lead_id;
$lead_status->status_id = $status_id;
if($lead_status->save()){
return json_encode(['code'=>0,'message'=>'Lead Status Changed Successfully!','data'=>$lead_status]);
} else {
return json_encode(['code'=>100,'message'=>'Error updating lead status','data'=>'']);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<div class="btn-group mr-3" role="group">
<div class="dropdown d-inline">
<button class="btn btn-{{$leads->status[0]->colour}} dropdown-toggle" type="button" id="dropdownMenuButton4" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
{{$leads->status[0]->status}}
</button>
<div class="dropdown-menu" x-placement="bottom-start">
#foreach($statuses as $s)
<a class="dropdown-item bg-{{$s->colour}}" data-id="{{$s->id}}">{{$s->status}}</a>
#endforeach
</div>
</div>
<button class="btn btn-{{$leads->status[0]->colour}} d-inline" id="nextStatusBtn" type="button">btn</i></button>
</div>
I have a div called project and it is rendered with EJS
There several projects in the data for EJS, they are rendered by forEach loop - so several similar div appear.
The project div has id for identification in Jquery.
Further it has a project.name and project.id as a data-*
The problem which I encountered:
If I don't reload the page as intended - first try works well and Element inner text get updated correctly.
But on second try to change another project name both are changed to value of previous, so to say for both projects. In few words - new change overrides all previous. How is it possible?
Link to see how it looks in GIF
Imgur
Strange behaviour of chaining requests Imgur
<%userData.forEach(function(project){%>
<div class="project" id='project <%=project.id%>'>
<div class="projectHeader">
<div class="projectTitle">
<h5 id="projectTitle <%=project.id%>" class="projectName">
<%=project.name%>
</h5>
<div class="projectButtons">
<span data-toggle="tooltip" data-placement="top" title="Edit Project Title">
<a data-toggle="modal" data-target="#editProjectTitleModal">
<i id="editProjectName" class="editProject fas fa-pencil-alt"
data-name="<%=project.name%>" data-id="<%=project.id%>"></i>
</a>
</span>
</div>
</div>
</div>
A simple modal is called when the a tag in project is clicked.
<div class="modal fade" id="editProjectTitleModal" tabindex="-1" aria-labelledby="exampleformModal" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<form class="" action="" method="">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Edit Title</h5>
</div>
<div class="modal-body">
<div class="input-group">
<input id="editProjectNameInput" autocomplete="off" pattern="[a-zA-Z0-9 ].{1,25}" title="1 to 25 characters" class="form-control" aria-label="With textarea" placeholder="Enter new title" required></input>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="submit" id="confirmEditProjectName" class="btn btn-primary">Save changes</button>
</div>
</form>
</div>
</div>
</div>
Jquery event handler which serves to change project.name, at first sends it to database and ammend DOM with new name. So the database get the new data, but the page is not reloaded and project.name changed simultaneously.
It grabs project-name and project-id and sends Ajax regular post - method, on success - change element's inner text to project-name
// Edit Project Title by ID
$(document).on('click', "#editProjectName", function() {
//Grab Id of the Project
var editProjectId = $(this).attr('data-id');
//Fill Modal input with current project.name
var currentTitle = document.getElementById('projectTitle ' + editProjectId).innerText;
$("#editProjectNameInput").val(currentTitle)
var url = '/editProjectName';
$('#confirmEditProjectName').on('click', function(event) {
//Take new project name from updated modal input
var newTitle = $("#editProjectNameInput").val();
//If they are same - alert
if (currentTitle === newTitle) {
event.preventDefault();
alert("New Title should be different")
} else {
event.preventDefault();
if (newTitle.length > 1 && newTitle.length <= 25) {
$.ajax({
type: "POST",
url: url,
data: {
projectName: newTitle,
projectID: editProjectId
},
success: function(result) {
//Hide modal and change element inner text to new value
$("#editProjectTitleModal").modal('hide')
document.getElementById('projectTitle ' + editProjectId).innerText = newTitle;
},
error: function(err) {
console.log(err);
}
})
}
}
})
})
I removed the space from the IDs and I changed from using the ID of #editProjectName to just using the class that is already on that object of editProject.
<%userData.forEach(function(project){%>
<div class="project" id='project<%=project.id%>'>
<div class="projectHeader">
<div class="projectTitle">
<h5 id="projectTitle<%=project.id%>" class="projectName">
<%=project.name%>
</h5>
<div class="projectButtons">
<span data-toggle="tooltip" data-placement="top" title="Edit Project Title">
<a data-toggle="modal" data-target="#editProjectTitleModal">
<i class="editProject fas fa-pencil-alt"
data-name="<%=project.name%>" data-id="<%=project.id%>"></i>
</a>
</span>
</div>
</div>
</div>
// Edit Project Title by ID
$(document).on('click', ".editProject", function() {
//Grab Id of the Project
var editProjectId = $(this).attr('data-id');
//Fill Modal input with current project.name
var currentTitle = document.getElementById('projectTitle' + editProjectId).innerText;
$("#editProjectNameInput").val(currentTitle)
var url = '/editProjectName';
$('#confirmEditProjectName').on('click', function(event) {
//Take new project name from updated modal input
var newTitle = $("#editProjectNameInput").val();
//If they are same - alert
if (currentTitle === newTitle) {
event.preventDefault();
alert("New Title should be different")
} else {
event.preventDefault();
if (newTitle.length > 1 && newTitle.length <= 25) {
$.ajax({
type: "POST",
url: url,
data: {
projectName: newTitle,
projectID: editProjectId
},
success: function(result) {
//Hide modal and change element inner text to new value
$("#editProjectTitleModal").modal('hide')
document.getElementById('projectTitle' + editProjectId).innerText = newTitle;
},
error: function(err) {
console.log(err);
}
})
}
}
})
})
After some research I have found out that once the on('click') is called it is On until the page get reloaded.
Thanks to this Question and Answer:
https://stackoverflow.com/a/6121501/13541013
I figured out - on('click') event should be switched off by calling $(this).off() (this is the event)
In my case I had to make $(this).off() right after:
$(document).on('click', "#editProjectName", function() {
$(this).off() ... further code
And it has to be done for every single on('click') event in the script.
I would like to show an input on the click, but being in a for loop I would like to show only the clicked one
<div v-for="(todo, n) in todos">
<i class="fas fa-minus ml-2"></i>
<li class="mt-2 todo">
{{ todo }}
</li>
<li class="button-container">
<button class="ml-1 btn btn-primary rounded-circle btn-sm" v-if="isHidden" v-on:click="isHidden = false"><i
class="THIS-CLICK"></i></button>
<input class="ml-5 border border-primary rounded" v-if="!isHidden" v-model="todo">
<button class="ml-1 btn btn-success rounded-circle btn-sm" v-if="!isHidden" v-on:click="isHidden = true"
#click="modifyTodo(n, todo)"><i class="far fa-save"></i></button>
</li>
</div>
I would like that on clicking on THIS-CLICK, only one input (that of the button clicked) is visible, but being in a for loop I don't know if it can be done
I would suggest to change the structure a bit in your app. You can clean up your code a lot by using v-if inside the button instead of two different buttons.
Also, moving as much javascript out from the markup as possible is a good practice.
I have an example below where this is done.
Regarding your question, you would have to add the key to each todo item.
new Vue({
el: "#app",
data() {
return {
todos: [{
name: 'wash hands',
isHidden: true
},
{
name: 'Stay home',
isHidden: true
}
],
};
},
methods: {
toggleTodo(n, todo) {
const hidden = todo.isHidden;
if (hidden) {
this.modifyTodo(n, todo);
todo.isHidden = false;
} else {
todo.isHidden = true;
}
},
modifyTodo(n, todo) {
//Some logic...
}
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div id="app">
<div v-for="(todo, n) in todos">
<i class="fas fa-minus ml-2"></i>
<li class="mt-2 todo">
{{ todo.name }}
</li>
<li class="button-container">
<input class="ml-5 border border-primary rounded" v-if="!todo.isHidden" v-model="todo.name">
<button #click="toggleTodo(n, todo)">
<i v-if="todo.isHidden" class="THIS-CLICK">click-this</i>
<i v-else class="far fa-save">save</i>
</button>
</li>
</div>
</div>
If you cannot do this, you could go with adding a new key to data like: hiddenTodos that would be an array of ids/a unique identifier to the todo you selected to hide.
in the template, it would be something like this:
<button #click="hiddenTodos.push(todo)">
...
<div v-if="hiddenTodos.includes(todo)"
How do you delete a div that is generated by a for loop? I have this code that generates divs:
EDIT: I have tried the changes of #Andrew Liberio but what happened is that my applicant divs have scattered all over the place. This is the new code and the script as well. Notice how I had put the ending semicolon of the for loop in order to get put the the index in the ajax. (Not seen in the code block for some reason but it goes like this >/script> <%}%>
<% ApplicantDAO applicantDAO = new ApplicantDAO();%>
<% for (int i = 0; i < applicantDAO.viewApplicant().size(); i++) {%>
<div class="column">
<div class="col-sm-3 col-xs-4">
<div class="list-group">
<a class="list-group-item active">
<img src = "th_1x1.jpg" class = "img-responsive" alt = "Responsive Image" width = "100%" height ="100">
<h4 class="list-group-item-heading" id="guardName<%=+i%>" id="guardName<%=+i%>"><%=applicantDAO.viewApplicant().get(i).getApplicantFirstName() + " "%>
<%=applicantDAO.viewApplicant().get(i).getApplicantLastName()%></h4>
</a>
<a class="list-group-item">
<p class="list-group-item-text" id="applyingFor<%=+i%>" id="applyingFor<%=+i%>"><%=applicantDAO.viewApplicant().get(i).getApplyingFor()%></p>
</a>
<a class="list-group-item" data-toggle="modal" href="#moreDetails<%=+i%>">
<button class="btn btn-primary btn-lg btn-block" id="moreDetails">More Details</button>
</a>
<a class="list-group-item">
<button type="button" class="btn btn-default" aria-label="Left Align">
<span class="glyphicon glyphicon-ok" aria-hidden="true"></span>
</button>
<button type="button" class="btn btn-default" aria-label="Left Align">
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
</button>
</a>
<script>
$(".delete").on("click", function () {
var id = $(this).attr("delete<%=applicantDAO.viewApplicant().get(i).getApplicantID()%>"); //get the id of the row
$.post("url_to_servlet_responsible_to_exclude_item", {
tId: id,
someOtherData: "anyData"
}).done(function () {
//if everything went ok,
//delete the div
$("div#" + id).remove();
});
})
</script>
But I dont know how to delete it at the same time delete it at the database. I use a jsp and servlet. This is my code for delete:
public boolean rejectApplicant(Applicant RejectedApplicant) {
try {
DBConnectionFactory myFactory = DBConnectionFactory.getInstance();
Connection conn = myFactory.getConnection();
String query = "delete from applicant where applicantID = ?";
PreparedStatement pstmt = conn.prepareStatement(query);
int rows = pstmt.executeUpdate();
conn.close();
pstmt.close();
return true;
} catch (SQLException ex) {
Logger.getLogger(ApplicantDAO.class.getName()).log(Level.SEVERE, null, ex);
}
return false;
}
I think that the same logic applies when transferring the values of the div to the database. The page is an applicant page where applicants are screened then if they do not pass, they will be removed and when they are accepted, the values will be passed to the database. Please suggest on what should I do. I already searched javascript and jquery but I just dont understand the terms like nodes etc. Any help or leads would be appreciated. Thank you!
You could pass an id to each div or/and to each button as #LAROmega suggested.
<div class="column" id="<%=applicantDAO.viewApplicant().get(i).getApplicantId()">
<div class="col-sm-3 col-xs-4">
...
<button type="button" class="btn btn-default delete" aria-label="Left Align" id="<%=applicantDAO.viewApplicant().get(i).getApplicantId()">
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
</button>
Then, you could use this script to delete the row using AJAX.
$(".delete").on("click", function(){
var id = $(this).attr("id"); //get the id of the row
$.post("url_to_servlet_responsible_to_exclude_item", {
tId: id,
someOthetData: "anyData"
}).done(function(){
//if everything went ok,
//delete the div
$("div#" + id).remove();
});
})
First, I think you should not use the function on("click" in a loop.
You should use class delete for each button that you want to delete.
<button type="button" class="btn btn-default delete" data-id="<%=applicantDAO.viewApplicant().get(i).getApplicantID()%>" aria-label="Left Align">
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
</button>
Outside of the loop, you call function on click
$(".delete").on("click", function () {
var id = $(this).attr("data-id"); //get the id of the row
$.post("url_to_servlet_responsible_to_exclude_item", {
tId: id,
someOtherData: "anyData"
}).done(function () {
//if everything went ok,
//delete the div
$("div#" + id).remove();
});
})