Im trying to remove the parent div of a text, that is looped for every flash.
I tried getting the Element by Id but it only deletes the first flashed text.
This is the code:
{% for message in get_flashed_messages() %}
<div class="todolistitems">
<b id="todoitem">{{ message }}</b>
<button onClick="testremove()" id="deletetodo"><i class="material-icons">done</i></button>
<br>
</div>
<script>
var msg = document.getElementById("todoitem")
function testremove() {
msg.parentNode.remove();
}
</script>
{% endfor %}
Here's a way to handle this.
First, don't use the same ID more than once. But, there's no need to use them at all here. We can listen to document for a click event and then test to see if it's a delete button. If so, remove the element associated with that button. How to find that element? Easiest to group them together inside a div container and then use the ever-handy .closest(parentSelector) method. When we listen for the delete click, we need to consider that depending on where in that button the user clicks, the target of the event will either be the button or the icon within
window.addEventListener('DOMContentLoaded', () => {
document.addEventListener('click', e => {
if (['material-icons', 'btn-delete'].some(c => e.target.classList.contains(c))) {
let targ = e.target.closest('.todo-item')
console.log(targ)
targ.parentNode.removeChild(targ)
}
})
})
<div class="todolistitems">
<div class='todo-item'>
<b class='msg'>todo1</b>
<button class='btn-delete'><i class="material-icons">done</i></button>
</div>
<div class='todo-item'>
<b class='msg'>todo2</b>
<button class='btn-delete'><i class="material-icons">done</i></button>
</div>
<div class='todo-item'>
<b class='msg'>todo3</b>
<button class='btn-delete'><i class="material-icons">done</i></button>
</div>
</div>
Related
So what I have is a simple form with couple of fields that is located inside a menu, that slides in when I click button 'btn-openmenu'. I am trying to use htmx to dynamically update the page to show results instantly and also Javascript to control the menu where the form is located.
What I am trying to accomplish is that when the submit button on the form is pushed, it will submit the form and close the menu.
What happens now is that the menu closes okay when the form is submitted. What also can happen is that if the form is not valid and a error pops up, but the menu still closes and the form is never submitted.
Here is the html where form is located form (/items/new-item/):
{% load crispy_forms_tags %}
<form id="createnewitem"
hx-post="/items/new-item/">
{% csrf_token %}
{{ newcoreprocess|crispy }}
<div style="margin-top: 10px;">
<button type="submit" class="btn submit-new">Create item</button>
<a class="btn" id="clear">Clear</button>
</div>
</form>
<script>
$(document).ready(() => {
$('#clear').on('click', function () {
var form = $("#createnewitem");
form[0].reset();
})
})
</script>
<script>
$(document).ready(() => {
$('.submit-new').click(function () {
var pagecontent = $("#content");
var menu = $(".menu");
var buttonSpan = $("#btn_openmenu").find('span');
pagecontent.css('marginLeft', '0');
menu.css('width', '0');
buttonSpan.text('Close');
})
})
</script>
Here is the html where the menu is opened and updated list would be rendered (/items/):
<div class="items-content" id="itemcontent">
<div class="container-fluid">
<div class="row" id="items-list">
{% include 'items/items-list.html' %}
</div>
</div>
<button class="btn" id="btn_openmenu"
hx-get="/items/new-item/"
hx-target="#createitemmenu"
hx-swap="innerHTML">
<i class="fas fa-plus-circle" id="add-item-icon"></i><span class="spanicon" id="add-item-span">Create item</span>
</button>
<div class="menu">
<div class="container-fluid" id="createitemmenu">
</div>
</div>
</div>
<script>
$(document).ready(() => {
$('#btn_openmenu').on('click', function () {
var thisElement = $(this);
var buttonSpan = thisElement.find('span');
var pagecontent = $("#itemcontent");
var menu = $(".menu");
if(buttonSpan.text() === "Close"){
buttonSpan.text('Create item');
menu.css('width', '0');
pagecontent.css('marginLeft', '0');
}
else {
if(buttonSpan.text() === "Create item"){
buttonSpan.text('Close');
pagecontent.css('marginLeft', '20%');
menu.css('width', '20%');
}
}
})
})
</script>
And here is the list (/items/item-list/)
{% if items %}
<nav class="nav processnav flex-column" style="padding-top: 10px;">
{% for item in items %}
<a class="nav-link" href="#">{{ item.order }} {{ item.name }}</a>
{% endfor %}
</nav>
{% else %}
<div class="container-fluid mt-3">
<span>No created items</span>
</div>
{% endif %}
What is working:
menu opens correctly
htmx renders the form in the menu
form can be submitted and if valid, the menu will close
What is not working:
if errors on submit, it still closes the menu
I have tried to edit the function submit-new.click, but whatever I change in that, it stops working at all and this is only function I got to work with valid submit
htmx doesn't render the updated list where new item is created
I have tried to edit the hx-post in the form, but whatever I edit the new item submit stops working and it renders some other content to the place, where the form is located.
I think there are just little things I am missing, but I cannot seem to get it function the way I want. Any help for the issue?
Using Django, my buttons are created using a for loop and assigned values based on model values.
Based on which button is click, I want to update the "new_note_header" with the innerHTML of the button.
I have created the following JavaScript, which works but only when the first button clicked.
<script>
function ProjectSelect () {
var x = document.querySelector('button').innerHTML;
document.getElementById('new_note_header').innerHTML = x;
}
document.addEventListener('DOMContentLoaded', function () {
document.querySelector('button').onclick = ProjectSelect;
});
</script>
<div class = project_container>
{% for project in projects %}
<button class = individual_project_container>
{{ project }}
</button>
{% endfor %}
</div>
<div class = note_header_container>
<div class = new_note_header, id = new_note_header>
New Note
</div>
</div>
I would be grateful for any help in adapting the JavaScript so it works for all buttons clicked.
querySelector will take the FIRST element that satisfies the selector
You could use querySelectorAll and assign a click event handler to each, but I recommend using delegation:
document.addEventListener('DOMContentLoaded', function() {
const nnHead = document.getElementById('new_note_header');
document.getElementById("project_container").addEventListener("click", e => {
const tgt = e.target.closest("button");
if (!tgt.matches(".individual_project_container")) return; // not a button
nnHead.textContent = tgt.textContent.trim();
});
});
<div class="project_container" id="project_container">
<button class="individual_project_container">Project 1</button>
<button class="individual_project_container">Project 2</button>
<button class="individual_project_container">Project 3</button>
</div>
<div class="note_header_container">
<div class="new_note_header" id="new_note_header">
New Note
</div>
</div>
I have this look-a-like code in my app :
let item;
$('.parent').on('click', function () {
item = $(this).attr('item') || 0;
});
$('.parent').on('click', '.children', this, function () {
doSomething();
});
<div class="parent" item="50">
<div class="children">
</div>
</div>
<div class="parent" item="51">
<div class="children">
</div>
</div>
<div class="parent" item="52">
<div class="children">
</div>
</div>
I have a parent element with several children in it. Clicking anywhere on the parent element will give me an item information, so I will be able to load functions according to this item variable on click on children.
My problem is : I have to delegate the onClick event on children to parent element otherwise the events will trigger in this order :
Click on any child
Click on parent, which is too late because I need item variable first
I have a functionality that replaces the parent element if activated, since it was dynamically inserted into the DOM, I have to delegate the onClick event as well, like this :
$('.grandParent').on('click', '.parent', function () {
item = $(this).attr('item') || 0;
});
Now my problem is that the events are triggering in the wrong order again :
Click on any child
Click on parent
How can I manage to set click event on parent as top priority?
Edit :
I will be more specific. I have a messages list on my page, each .message element contains the message content but also some functionnalities like edit, delete, set as favorite, like, etc.
Like this :
<div class="message" data-item="1">
<a class="edit">E</a>
<a class="delete">X</a>
<a class="favorite">Fav</a>
<a class="like">Like</a>
<div class="content">
Hello world !
</div>
</div>
<div class="message" data-item="2">
<a class="edit">E</a>
<a class="delete">X</a>
<a class="favorite">Fav</a>
<a class="like">Like</a>
<div class="content">
Hello world !
</div>
</div>
Each one of those functionnalities will trigger different functions when clicked : edit(), delete(), like(), etc.
All of them will make AJAX requests which will then send the item variable to my server in order to know what item has to be impacted by this click.
To avoid repetition in my events handlers, I am trying to get the data-item attribute's value with one event bound to click on .message element, relying on the bubbling of children elements.
Get the item where you actually want it and get rid of the handler on parent:
$('.parent').on('click', '.children', function () {
item = $(this).closest('.parent').attr('item');
doSomething();
});
EDIT:
Then get the item when you click on the grandparent:
$('.grandParent').on('click', '.children', function () {
item = $(this).closest('.parent').attr('item');
});
EDIT #2:
Based on the OPs updated requirements, do it like this:
<div class="message" data-item="1">
<a class="action edit" data-type="edit">E</a>
<a class="action delete" data-type="delete">X</a>
<a class="action favorite" data-type="favorite">Fav</a>
<a class="like">Like</a>
<div class="content">
Hello world !
</div>
</div>
<div class="message" data-item="2">
<a class="action edit" data-type="edit">E</a>
<a class="action delete" data-type="delete">X</a>
<a class="action favorite" data-type="favorite">Fav</a>
<a class="like">Like</a>
<div class="content">
Hello world !
</div>
</div>
$(document).on('click','.message .action',function(e) {
const item = $(this).closest('message').attr('item');
switch($(this).data('type')) {
case 'edit': doEdit(item); break;
case 'delete': doDelete(item); break;
case 'favorite': doFavorite(item); break;
}
});
See, one event handler?
It's a very common pattern to do what you're doing. In the absence of a more robust framework (e.g. React), then using plain jQuery this is how it should be done.
How can I select a button based on its value and click on it (in Javascript)?
I already found it in JQuery:
$('input [type = button] [value = my task]');
My HTML Code for the Button is :
<button type="submit" value="My Task" id="button5b9f66b97cf47" class="green ">
<div class="button-container addHoverClick">
<div class="button-background">
<div class="buttonStart">
<div class="buttonEnd">
<div class="buttonMiddle"></div>
</div>
</div>
</div>
<div class="button-content">Lancer le pillage</div>
</div>
<script type="text/javascript" id="button5b9f66b97cf47_script">
jQuery(function() {
jQuery('button#button5b9f66b97cf47').click(function () {
jQuery(window).trigger('buttonClicked', [this, {"type":"submit","value":"My Task","name":"","id":"button5b9f66b97cf47","class":"green ","title":"","confirm":"","onclick":""}]);
});
});
</script>
What is the equivalent in JS and how may i click on it
(probably like this: buttonSelected.click(); ) .
And how do i run the javascript of the button clicked ?
Use querySelector to select it. Then click()
Your HTML has a button and not an input element so I changed the selector to match the HTML.
let button = document.querySelector('button[value="my task"]');
button.click();
<button type="submit" value="my task" id="button5b9f54e9ec4ad" class="green " onclick="alert('clicked')">
<div class="button-container addHoverClick">
<div class="button-background">
<div class="buttonStart">
<div class="buttonEnd">
<div class="buttonMiddle"></div>
</div>
</div>
</div>
<div class="button-content">Launch</div>
</div>
</button>
Otherwise, use this selector:
document.querySelector('input[type="button"][value="my task"]')
Note that if you have multiple buttons with the same value you'll need to use querySelectorAll and you'll get a list of all the buttons.
Then you can loop over them and click() them all.
Edit - new snippet after question edit
jQuery(function() {
jQuery('button#button5b9f66b97cf47').click(function() {alert('success')});
document.querySelector('button[value="My Task"]').click();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button type="submit" value="My Task" id="button5b9f66b97cf47" class="green ">
<div class="button-container addHoverClick">
<div class="button-background">
<div class="buttonStart">
<div class="buttonEnd">
<div class="buttonMiddle"></div>
</div>
</div>
</div>
<div class="button-content">Lancer le pillage</div>
</div>
you can try:
var elements = document.querySelectorAll("input[type = button][value=something]");
note that querySelectorAll returns array so to get the element you should use indexing to index the first element of the returned array and then to click:
elements[0].click()
and to add a event listener u can do:
elements[0].addEventListener('click', function(event){
event.preventDefault()
//do anything after button is clicked
})
and don't forget to add onclick attribute to your button element in html to call the equivalent function in your javascript code with event object
I am not recommended this way because of excess your coding but as you mentioned, below are the equivalent way.
$(document).ready(function() {
var selectedbuttonValue = "2"; //change value here to find that button
var buttonList = document.getElementsByClassName("btn")
for (i = 0; i < buttonList.length; i++) {
var currentButtonValue = buttonList[i];
if (selectedbuttonValue == currentButtonValue.value) {
currentButtonValue.click();
}
}
});
function callMe(valuee) {
alert(valuee);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.2.3/jquery.min.js"></script>
<input type="button" class="btn" value="1" onclick="callMe(1)" />
<input type="button" class="btn" value="2" onclick="callMe(2)" />
<input type="button" class="btn" value="3" onclick="callMe(3)" />
Using JavaScripts querySelector in similiar manner works in this case
document.querySelector('input[type="button"][value="my task" i]')
EDIT
You might save your selection in variable and attach eventListener to it. This would work as you desire.
Notice event.preventDefault() -function, if this would be part of form it would example prevent default from send action and you should trigger sending form manually. event-variable itselfs contains object about your click-event
var button = document.querySelector('input[type="button"][value="my task" i]')
button.addEventListener('click', function(event){
event.preventDefault() // Example if you want to prevent button default behaviour
// RUN YOUR CODE =>
console.log(123)
})
Trying to select the current user when click on the coffee button inside popover.
Users are populated in the home page.
<div class="user">
...
<div class="popover hovercard" role="tooltip">
...
<div class="info">
<div class="info-inner">
<div class="interactions">
<a class="coffee-btn btn" href="#">Coffee</a>
</div>
</div>
</div>
</div>
...
</div>
I tried to select the "closest" user but apparently it's targeting all users.
Below is the JS code:
$(document).on("click", ".interactions .coffee-btn" , function(){
$(this).parents(".popover").popover('hide');
// get user dom
var cur = $(this).closest(".user");
console.log(cur); //returns an array, not what i want
cur.css("float", "left");
// create another popover
});
Should I assign users an id instead with angular and target them that way?
Try:
$(".interactions .coffee-btn").on("click", function(){
// get user dom
var cur = $(this).closest(".user");
console.log(cur); //returns an array, not what i want
cur.css("float", "left");
});
It's working for me here.
When you use $(this), on (document), you're selecting the document, not the button.