How to append big HTML snippets into DOM with Javascript? - javascript

I have an app which uses EJS templating to populate data.
In order to add new projects I have made a simple input form which takes all required parameters.
After an input completed an Ajax request being sent, on success I want to inject this snippet into DOM.
In simple words - After new project added I want to display play instantly by injecting into DOM without reloading the page
Is there an elegant way of inserting this div ladder as a template into DOM? It works,
<div class="projects">
<div class="projectHeader">
<div class="projectTitle">
<span>
<a data-toggle="modal" data-target="#editDeadLineModal">
<i data-id="<%=project.id%>" class="projectDeadline far fa-calendar-alt fa-2x" data-toggle="tooltip" data-placement="top" title="Set Deadline"></i>
</a>
</span>
<h5 class="projectName <%=project.id%>" data-toggle="tooltip" data-placement="top" title="Deadline <%=deadline%>" style="align-items: center;">
<%=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>
<i class="separatorDash fas fa-minus"></i>
<span data-toggle="tooltip" data-placement="top" title="Delete Project">
<a data-toggle="modal" data-target="#deleteProjectModal">
<i id="deleteProject>" class="deleteProject far fa-trash-alt" data-id="<%=project.id%>"></i>
</a>
</span>
</div>
</div>
</div>
</div>
What I have tried is recreating the entire div ladder in string and append it to parent node.
Like this:
// Add new Project
$('#addNewProjectBtn').on("click", function() {
$("#newProjectModal").on('show.bs.modal', function() {
$(".confirmNewList").on("click", function(event) {
var url = '/addNewList';
var newListTitle = $("#newListNameInput").val()
event.preventDefault();
$.post({
url: url,
data: {
listName: newListTitle
},
success: function(result) {
$("#newProjectModal").modal('hide')
$("#newListNameInput").val('');
var id = result.data.id
var name = result.data.name
//Append new project
$(".projects").append("<div class='project col-4' id='project" + id + "'> <div class='projectHeader'> <div class='projectTitle'> ...and so on until the end")
},
error: function(err) {
console.log(err);
}
})
}
}
})
})
})
In simple words - After new project added I want to display play instantly by injecting into DOM without reloading the page
Is there an more elegant and specially efficient way of inserting this div ladder as a template into DOM?
The method which I have tried above - works, But on attempt to interact with it by calling modals - modals do not get it's data-*, as well the bootstrap tooltips don't work.

you can try create new html file instead, and append like this in your page
$.get("yourfile.html", function (data) {
$("#appendToThis").append(data); // or use .html();
});
OR you can directly pass this HTML structure from your backend, so you can directly use append function.

After some research I discovered that the event handler can be delegated.
Since the html snippet I am trying to append to projects is added after document.ready (document is loaded and handlers are bind) the only thing required to make the new snippet be active on event is to delegate the event handler to the parent of element that is appended.
Like this :
$("body").delegate("#addNewProjectBtn", "click", function() {
$("#newProjectModal").on('show.bs.modal', function() {
$(".confirmNewList").on("click", function(event) {
var url = '/addNewList';
var newListTitle = $("#newListNameInput").val()
event.preventDefault();
$.post({
url: url,
data: {
listName: newListTitle
},
success: function(result) {
$("#newProjectModal").modal('hide')
$("#newListNameInput").val('');
var id = result.data.id
var name = result.data.name
//Append new project
$(".projects").append("<div class='project col-4' id='project" + id + "'> <div class='projectHeader'> <div class='projectTitle'> ...and so on until the end")
},
error: function(err) {
console.log(err);
}
})
}
}
})
})
})
By delegating the event handler to it's parent - the event handler is preserved in the parent.

Related

ajax not work when click open in new window after right click in django template

i created a link with ajax this is a html coded:
<a id="post_click" href="{{ post.online_url}}" rel="nofollow">
<button class="w-100 " type="button" name="button">
<span class="">link</span>
</button>
</a>
and this is ajax :
$(function () {
$('#post_click').on('click', function () {
var Status = $(this).val();
var id = {{post.id}}
$.ajax({
url: "/post-click/" + id,
data: {
},
dataType : 'json'
});
});
});
if i push left click ajax work fine in sever side, but when i push left right click and choose open in new window ajax doesnt work
you have to set the good url in href for doing that :
<a id="post_click" href="/post-click/{{post.id}}" rel="nofollow">
link
</a>

AJAX incorrectly GETs and POSTs multiple data

I am working on a feature of my webapp that allows a user to add a place to a list. The current path is to open a modal which shows the user's lists and allows them to choose which list to add the data to.
The problem I have is two fold:
For some reason when the user click's a list it tries to send the data multiple times depending on how many lists there are (eg. if there are 2 lists it tries to send the data to the chosen list twice.) This is causing all sorts of headaches at my database.
The modal doesn't seem to reset or something meaning every time I reopen the modal 2 more lists are added meaning there are all these duplicates (example).
I have tried adding and removing event handlers etc. but I can't seem to debug the issue myself. Thank you in advance for any support you can offer.
Here is the JS function
const addToListModal = function(venueName) {
$('#userlist-modal').modal('show');
$.ajax({
type: 'GET',
url: '/api/userlist/',
data: {
'username': userName
},
success: function(data) {
data.forEach(item => {
var listName = item.list_name;
var listId = item.id;
var listItem = $("#userListsModal").append(
`<li class="userlistModal" id="${listName}" data-name="${listName}" data-pk="${listId}">
${listName}
</li>`)
$(listItem).on('click', function(e) {
if (e.target && e.target.matches("li.userlistModal")) {
var listname = e.target.getAttribute('data-name');
var listId = e.target.getAttribute('data-pk');
addVenueToList(listId, venueName);
e.preventDefault();
}
})
})
}
});
};
AJAX Post:
const addVenueToList = function(listId, venue) {
$.ajax({
type: "POST",
url: '/api/uservenue/',
dataType: 'json',
data: {
csrfmiddlewaretoken: document.querySelector('input[name="csrfmiddlewaretoken"]').value,
'user_list': listId,
'venue': venue
},
success: function(data) {
console.log('User added: ' + data)
},
});
}
And here is the pertinent HTML
<div class="modal" id="userlist-modal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content rounded-0">
<div class="modal-header">
<h5 class="modal-title" id="ModalLabel"></h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div id="lists-column" class="mt-1 ml-2 mb-1 col-2" style="height: 367px;">
<ul id="userListsModal" class="list-group list-group-flush" style="width: 250px">
{% csrf_token %}
{{ form.as_p }}
</ul>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
$(listItem).on('click', function(e) { …
listItem is not what you think it is here.
You did
var listItem = $("#userListsModal").append(`<li class="userlistModal" …
before - but that does not return a reference to the newly appended item, it returns the jQuery object you started with (that is necessary, for method chaining to work).
So what you are doing here, is adding a click handler for #userListsModal. And since this happens in a loop over your list items, you are adding this same click handler twice (here in this situation), resp. as many times, as you have list items.
Your check
if (e.target && e.target.matches("li.userlistModal")) {
inside the callback function still works - because when you click on any of the list items, the event bubbles up the DOM tree. You are handling it when it reaches #userListsModal, but the event target is still the list item you clicked on.
You need to either add these event handlers to the individual new list items you just appended, or – probably better in a case like this – use event delegation, set up one handler for this, outside of the loop that creates the list items.
Try using jQuery's one() method: one
So, instead: $(listItem).on('click', function(e) {...})
Do this: $(listItem).one('click', function(e) {...})
I think the problem here is that the list (of lists) is not cleared every time you open the modal dialog. So every time the same items are appended and new 'click' event handlers are added. Try to call jQuery empty() method before running AJAX '/api/userlist' (it will remove all event handlers as well)
const addToListModal = function(venueName) {
$("#userListsModal").empty();
$('#userlist-modal').modal('show');
$.ajax({
// ...

Javascript Issue with aria-hidden popup

I have this ajax code that gets a res.json(event) from the server and then creates an object based on the value received.
Here is part of that code:
html += `<div class="card-header" id="headingOne-${i}">` +
`<div class="event-time"><time class="published" datetime="2017-03-24T18:18">${data[i].events.targetReminder} | ${data[i].events.targetAmPM}</time><div class="more"> <svg class="olymp-three-dots-icon"><use xlink:href="svg-icons/sprites/icons.svg#olymp-three-dots-icon"></use> </svg><ul class="more-dropdown"><li>Mark as Completed</li> <li>Delete Event </li></ul></div></div>` +
`<h5 class="mb-0 title"><a href="" data-toggle="collapse" data-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne" >${data[i].events.title}<i class="fa fa-angle-down" aria-hidden="true"></i>` +
` <span class="event-status-icon" data-toggle="modal" data-target="#public-event"><svg class="olymp-calendar-icon" data-toggle="tooltip" data-placement="top" id ="uncomplet-${i}"data-original-title="UNCOMPLETED"><use xlink:href="svg-icons/sprites/icons.svg#olymp-calendar-icon"></use></svg></span></a></h5></div>` +
`<div id="collapseOne" class="collapse show" aria-labelledby="headingOne" data-parent="#headingOne-${i}"><div class="card-body" id="${data[i].events._id}" onClick="reply_click()">${data[i].events.caption}</div><div class="place inline-items"><svg class="olymp-add-a-place-icon"><use xlink:href="svg-icons/sprites/icons.svg#olymp-add-a-place-icon"></use></svg><span>${data[i].events.location}</span></div></div></div>`;
And here is the output of the code:
The aria-hidden that I'm talking about is this one
<div class="modal fade" id="public-event" tabindex="-1" role="dialog" aria-labelledby="public-event" aria-hidden="true">
What I have tried and already know it's not a proper solution is here
Code test
I created a script that change aria-hidden => true or false but I don't know how to link it with my box
<script type="text/javascript">
function reply_click()
{
document.getElementById('public-event').setAttribute('aria-hidden', 'false');
}
</script>
another failed try:
<script type="text/javascript">
function reply_click()
{
alert('this function is called')
$(`#mark-${i}`).onclick = function() {
document.getElementById('public-event').setAttribute('aria-hidden', 'false');
};
}
</script>
I also added in the HTML this function onClick="reply_click()" but nothing is happening. I only get the alert('this function is called')
Could you suggest me an idea, please?
By looking at your question and discussion on the comment section I think that you are trying to add click event on your dynamically generated div section(html part) and open the pop up modal.
We can achieve that by using $('#id' OR '.class').modal('show') in jquery.
So why don't you add a class any where inside your div section of html and bind a click function using jquery. Suppose you have added a class name showModal on the very first div after card-header like, div="card-header showModal"
$('#eventCard').on('click', '.showModal', function(){
$('#public-event').modal('show');
});
We cannot directly use $('.showModal').click...... because document structure is change after appending the html section after #eventCard which was initially was not present. Hpe this works.
could this be your problem ? you create an item dynamically with javascript, but the item you want to select, click event, is not actually created at that time. Once the item you want to export is created, you can select it and want to make the changes you want.
udpated: I added a snippet of what I meant. in order for me to select the H1 tag that occurs after I click on the button, I have to write a function that will occur after it occurs.
const button = document.querySelector(".clickme");
const container = document.querySelector(".container");
button.addEventListener("click", () => {
container.innerHTML += `
<h1 class = "change-modal"> ı cant select this</h1>
<div class="modal fade" id="public-event" tabindex="-1" role="dialog" aria-labelledby="public-event"
aria-hidden="true"> `
})
const changeModal = document.querySelector(".change-modal")
console.log(changeModal)
<button class="clickme">Click me</button>
<div class="container" style="background-color: red;">
</div>
<h1 class="change-modal">ı select this</h1>
updated2 :
for (let i = 0; i < data.length; i++) {
html += // your html
$("eventCard").append(html);
//after this, you can select the item and type the function because the items are created here.
}
Updated 3!!! : I explained how to do things with javascript without using jquery. Hopefully you know what I mean.
async getData() { // fetch operations using javascript
const data = await fetch(url); // your api url
const jsonToData = await data.json(); // here you can Request api and obtain the data
return jsonToData;
}
getData().then((data) => {
console.log(data) // ıts probably an array.
for (let data = 0; data < jsonToData.length; data++) {
// data operations, what if you want to
html += // you printed document items,
}
})
.then(() => {
//!!! IMPORTANT!!! this is where you need to perform the operation of selecting the element function. you can also write a function that can work for the code here, but I've written it one by one for now.
const clickedElement = //type whatever element you want to click on. !!
clickedElement.addEventListener("click", function() {
const elementToChange = document.getElementById(".public-event");
elementToChange.setAttribute('aria-hidden', 'false');
})
})
.catch(err => console.log(err))

Add Friend with Ajax - Django

I'm using Django-Friends
I'm trying to have it so when a user clicks on the add friend, the button disappears(or ideally says Request sent). However, when I click the button, it doesn't disappears. I am new at Django and Ajax, so I'm assuming that this is an error on my part. Most likely the HttpResponse.
That part actually confuses me a lot. The HttpResponse, render, render_to_response, etc. I know that I can use render or render_to_response when I want to load a template. But what if I don't want to load up a new template or go to a new page? Like I want to be able to complete an action like add a friend, or add a page, etc; all on one page. I know you can use ajax to do it, but I don't know the django technical aspect of it.
Anyway, here's my code. Right now, nothing happens. The button doesn't disappear, and there is no friendships request sent.
profile.html
<div class="text-center">
<div>
"{{currUserprofile.tagline}}"
</div>
{{currUser.profile.city}}, {{currUser.profile.state}}
{{currUser.id}}
</div>
<!-- <button id="addfriend" data-profileid="{{currUser.id}}" class="btn btn-primary" type="button"> <span class="glyphicon glyphicon-plus"></span>
Request Friend</button>
--> <!--Find a way to signify looking or not looking to mentor -->
<button id="addfriend" data-profileid="{{currUser.id}}" class="btn btn-primary" type="button"> <span class="glyphicon glyphicon-plus"></span>
Request Friend</button>
ajax.js
$(document).ready(function () {
$('#addfriend').click(function () {
var profile_id = $(this).data("profileid");
$.get('/myapp/addfriend/id=' + profile_id, function (data) {
$('#addfriend').fadeOut();
});
});
})
views.py
#login_required
def profile(request, id):
context = RequestContext(request)
currUser = User.objects.get(pk = id)
profile = UserProfile.objects.filter(user = currUser)
return render_to_response('myapp/profile.html', {'currUser': currUser, 'UserProfile': UserProfile}, context)
#login_required
def addfriend(request, id):
context = RequestContext(request)
other_user = User.objects.get(pk=id)
new_relationship = Friend.objects.add_friend(request.user, other_user)
profile = UserProfile.objects.filter(user = other_user)
return HttpResponse(new_relationship)
Here is a working JSFiddle, but you can't post data {profile_id: profile_id}with a getyou should use a postor add the data as params, as I did:
HTML:
<button id="addfriend" data-profileid="{{currUser.id}}" class="btn btn-primary" type="button"> <span class="glyphicon glyphicon-plus"></span>
Request Friend</button>
JS:
$(document).ready(function () {
$('#addfriend').click(function () {
var profile_id = $(this).data("profileid");
$.get('/myapp/addfriend/?profile_id=' + profile_id, function (data) {
$('#addfriend').fadeOut();
});
});
});

twitter bootstrap modal -- how to pass data to callback function

is there a way to pass additional data to bootstrap modal function callback?
for example, lets say my link that causes the modal to open has an extra attribute in it with a bit of useful data in it, how could I reference that attr?
HTML
<span listid="80" href="#editTaskList" data-toggle="modal" class="btn btn-mini right"><i class="icon-edit"></i> Edit Task List</span>
JS
$('#editTaskList').on('show', function () {
// get the source of the click, and then get the data i need.
});
Could this work for you ?
<span listid="80" href="#editTaskList" data-toggle="datamodal" class="btn btn-mini right"><i class="icon-edit"></i> Edit Task List</span>
var $editTaskList = $('#editTaskList');
$('body').on('click.modal.data-api', '[data-toggle="datamodal"]', function (e) {
var $this = $(this);
$editTaskList.data('anyAttr',$this.data('anyAttr'));
$editTaskList.modal('show');
e.preventDefault();
})
$editTaskList.on('show', function () {
var myData = $editTaskList.data('anyAttr');
});
I know that this is an old question, but this is the first thing i've found on google. So, I want to put some important information here...
You NEED to put your callback function binded on events BEFORE you call the modal, for example:
$('#modal').on('shown', function(){
// Do something when the modal is loaded
});
$("#modal").modal();
This is very important and helped me a lot, so, here it is...
Like this -
<span id="modal_opener" data-extrastuff="stuff" listid="80" href="#editTaskList" data-toggle="modal" class="btn btn-mini right"><i class="icon-edit"></i> Edit Task List</span>
$('#modal_opener').click(function() {
var stuff_i_want = $(this).attr('data-extrastuff');
});

Categories

Resources