I'm trying to get a modal to open using insertAdjacentHTML so the issue Is insertAdjacentHTML modal isn't opening when inserted onto the DOM. I can only assume I'm missing a simple concept. please help :)
// ----------------Models Materialize Framework----------------
document.addEventListener('DOMContentLoaded', function() {
let elems = document.querySelectorAll('.modal');
let instances = M.Modal.init(elems);
});
// Add Extra Colums
const addMoreBtn = document.getElementById("addmorebtn");
const addColums = document.getElementById("addcolumns");
addMoreBtn.addEventListener('click', (e) => {
e.preventDefault();
const first =
`
<div id="addcolumns">
<!-- Button / Modal / Form Inputs -->
<!-- Button -->
<div class="row">
<div class="col s12 center">
<a href="#exercise1" class="disabled-exersice-btn btn-floating btn-small darken-4 z-depth-2 black center modal-trigger">
<i class="material-icons white-text">add </i>
</a>
</div>
<!-- Modal -->
<div class="modal modal-position" id="exercise1">
<div class="valign-wrapper center-align">
<div class="row">
<form class="exercises-form col s12 valign-wrapper center-align" autocomplete="off">
<div class="input-field">
<input type="text" placeholder="Exercise:" id="autocomplete-input" class="autocomplete center">
<label for="autocomplete-input"></label>
<div class="removebtn-padding">
<input class="modal-close btn black" type="submit" value="Submit">
</div>
</div>
</form>
</div>
</div>
</div>
</div>
`
const position = "afterend";
addColums.insertAdjacentHTML(position, first);
});
You'll need to initialise any new modals that get added to to DOM after they are added.
var elems = document.querySelectorAll('.modal');
var instances = M.Modal.init(elems);
Related
From using querySelector, querying a form element and adding an event listener to the latter, I want to understand how the submit button is involved. Is it because the submit button is what gives meaning to the form? And please provide me with some good resources on JavaScript and DOM scripting. Thanks and regards.
// const taskInput = document.getElementById('task');
// const heading = document.querySelector('h5');
function handleEvent(evt) {
evt.preventDefault();
const { type, target } = evt;
console.log({ type, target });
}
const form = document.querySelector('form');
// submit
form.addEventListener('submit', handleEvent);
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"/>
<link href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/css/materialize.min.css" rel="stylesheet"/>
<div class="container">
<div class="row">
<div class="col s12">
<div id="main" class="card">
<div class="card-content">
<span class="card-title">Task List</span>
<div class="row">
<form id="task-form">
<div class="input-field col s12">
<input type="text" name="task" id="task" value="Walk the dog">
<label for="task">New Task</label>
</div>
</div>
<input type="submit" value="Add Task" class="btn">
</form>
</div>
<div class="card-action">
<h5 id="task-title">Tasks</h5>
<ul class="collection">
<li class="collection-item">
List Item
<a href="#" class="delete-item secondary-content">
<i class="fa fa-remove"></i>
</a>
</li>
</div>
</div>
</div>
</div>
</div>
I have 4 boxes labeled a1, a2, a3, a4 as an example. And when someone clicks on 2 boxes, I want the label (a1, a2 as an example) to print on html output. I just spent over an hour and the best I can come up was printing undefined and null.
Sorry, here is my code
HTML
<div class="container">
<div class="row">
<div class="col-md-3" label="a1">
<a class="btn btn-primary" href="#" role="button">Button 01</a>
<div class="output"></div>
</div>
<div class="col-md-3" label="a2">
<a class="btn btn-primary" href="#" role="button">Button 02</a>
<div class="output"></div>
</div>
<div class="col-md-3" label="a3">
<a class="btn btn-primary" href="#" role="button">Button 03</a>
<div class="output"></div>
</div>
<div class="col-md-3" label="a4">
<a class="btn btn-primary" href="#" role="button">Button 04</a>
<div class="output"></div>
</div>
</div>
</div>
const button = document.querySelector('.btn');
button.addEventListener('click', printLabel);
function printLabel(){
const name = document.querySelector('label');
const print = document.querySelector('.output');
print.innerText = name;
}
label isn't really a standard attribute of the <div> tag. You could try id if you're just looking for a quick solution. Also, you're accessing everything in a pretty strange way.
You should change label to id. The id attribute is pretty much universal to all HTML elements (that I know of) and will allow you to uniquely identify that element.
<div class="container">
<div class="row">
<div class="col-md-3" id="a1">
<a class="btn btn-primary" href="#" role="button">Button 01</a>
<div class="output"></div>
</div>
<div class="col-md-3" id="a2">
<a class="btn btn-primary" href="#" role="button">Button 02</a>
<div class="output"></div>
</div>
<div class="col-md-3" id="a3">
<a class="btn btn-primary" href="#" role="button">Button 03</a>
<div class="output"></div>
</div>
<div class="col-md-3" id="a4">
<a class="btn btn-primary" href="#" role="button">Button 04</a>
<div class="output"></div>
</div>
</div>
</div>
Add a unique id to all of the div elements that are meant to be your "output". This will allow your code to direct the "output" to the right element.
<div class="container">
<div class="row">
<div class="col-md-3" id="a1">
<a class="btn btn-primary" href="#" role="button">Button 01</a>
<div class="output" id="a1-output"></div>
</div>
<div class="col-md-3" id="a2">
<a class="btn btn-primary" href="#" role="button">Button 02</a>
<div class="output" id="a2-output"></div>
</div>
<div class="col-md-3" id="a3">
<a class="btn btn-primary" href="#" role="button">Button 03</a>
<div class="output" id="a3-output"></div>
</div>
<div class="col-md-3" id="a4">
<a class="btn btn-primary" href="#" role="button">Button 04</a>
<div class="output" id="a4-output"></div>
</div>
</div>
</div>
Finally, a couple of changes to your JavaScript. The first change you'll see is that I changed document.querySelector('.btn') to document.querySelectorAll('.btn'). The difference between these methods is that the first one selects ONLY the first element it finds that matches the selector, but the second one selects all elements that match the selector and creates an array.
Next, we loop through that array to add an event listener for each element.
After that, we add a parameter e (for event) to the printLabel() function because addEventListener() passes an event object in the callback function (printLabel). This object gives information about the target element related to the event.
Next, we get the target element of the event and that's your button. Then we get the parentElement of your button because your id or "label" is on the parent element. Then, you can get the name from the id of the parent element.
As a note, remember that id attributes CANNOT have spaces or . or # or really most special characters besides _.
Finally, we need to select your "output" element, and we'll use the id to do that.
document.querySelector('#' + name + '-output'); will get the element that has an id with the given name + -output. For example, if you click button a1 this will get the element with the id of a1-output. The # signifies that you're searching for an id.
Now that we stored this element in a variable print, we can place the text in it using the innerHTML property.
const button = document.querySelectorAll('.btn');
for(var i=0; i < button.length; i++) {
button[i].addEventListener('click', printLabel);
}
function printLabel(e) {
var target = e.target;
var parent = target.parentElement;
const name = parent.id;
const print = document.querySelector('#' + name + '-output');
print.innerHTML = name;
}
I created a JSFiddle to help you.
If you have any questions, please let me know.
<script>
function printDiv(divName){
var printContents = document.getElementById(divName).innerHTML;
var originalContents = document.body.innerHTML;
document.body.innerHTML = printContents;
window.print();
document.body.innerHTML = originalContents;
}
</script>
<h1> do not print this </h1>
<div id='printMe'>
Print this only
</div>
<button onclick="printDiv('printMe')">Print only the above div</button>
We can use event bubbling and data attributes to our advantage here. Replace your label attribute which is non-standard with a data attribute. Also, don't use a if it is not a navigation element, use button instead.
//Get the divs
let divs = document.querySelectorAll("[data-label]")
for(var i = 0; i < divs.length; i++){
//Add the event listener to the DIVs, yes the divs
divs[i].addEventListener("click", function(event){
//Did a button fire the event?
if(event.target.tagName === "BUTTON"){
//update the output div in the clicked div
this.querySelector(".output").innerText = this.dataset.label;
}
});
}
<div class="container">
<div class="row">
<div class="col-md-3" data-label="a1">
<button class="btn btn-primary" role="button">Button 01</button>
<div class="output"></div>
</div>
<div class="col-md-3" data-label="a2">
<button class="btn btn-primary"role="button">Button 02</button>
<div class="output"></div>
</div>
<div class="col-md-3" data-label="a3">
<button class="btn btn-primary" role="button">Button 03</button>
<div class="output"></div>
</div>
<div class="col-md-3" data-label="a4">
<button class="btn btn-primary" role="button">Button 04</button>
<div class="output"></div>
</div>
</div>
</div>
just change your script part to the following to make it work without changing HTML
<script>
//getting all buttons
var buttons = document.getElementsByClassName("btn");
//adding event listner to all buttons
for (var i = 0; i < buttons.length; i++) {
buttons[i].addEventListener("click", printLabel, false);
}
function printLabel() {
const outputDiv = this.parentElement.querySelector(".output"); // this will select only closet div with given class
outputDiv.innerText = this.parentElement.getAttribute("label");
}
</script>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link href="css/bootstrap.css" rel="stylesheet" id="bootstrap-css">
<title>Chat Test</title>
</head>
<body>
<div class="container">
<div class="row">
<div class="col">
<div id="AVAInteractArea" class="col mb-4 bg-dark justify-content-center"
style="max-height: 25rem; overflow-y: auto">
<div class="d-flex justify-content-start mb-4">
<h5>
<span class="badge badge-primary">AVA</span>
Hi, how are you?
</h5>
</div>
<div class="d-flex justify-content-end mb-4">
<h5>
Hi, I am good about you?
<span class="badge badge-secondary">You</span>
</h5>
</div>
<script>
function addDiv(parent_div) {
var div = document.createElement('div');
var parent = document.getElementById(parent_div);
div.innerHTML = '<p>TEST</p>';
parent.appendChild(div);
}
var button = document.getElementById('AVAInteractTypeSubmit');
if (button) {
button.addEventListener('click', function () {
// change dynamically your new div
addDiv('AVAInteractArea');
});
}
</script>
</div>
<form class="col-lg-6 offset-lg-3 mb-5">
<div class="row form-group justify-content-center">
<input id="AVAInteractType" type="text"
placeholder="Ask AVA about law"
class="form-control-lg border-white"
style="outline: none"
autofocus="autofocus">
<button id="AVAInteractTypeSubmit" class="btn-lg btn-primary" style="outline: none">Ask</button>
</div>
<button id="AVAInteractSpeak" class="btn-lg btn-primary" style="outline: none">Or speak to AVA</button>
</form>
</div>
</div>
</div>
</body>
</html>
I am trying to make it so that when I click the button with id="AVAInteractTypeSubmit", it adds a div to the parent div with id="AVAInteractArea". However, whenever I run this code, no such div appears to be added to the parent div. I don't know why it isn't working please help me. I don't want to use jQuery, I just want the Javascript code in the script tag above fixed.
Edit
Thank you #brk for fixing my problem. But now I want to do something different, I want to add everything to a function dedicated to adding the div inside the parent div, so I replaced all the code in the script tag with
function addUserAVAInteraction() {
var div = document.createElement('div');
var parent = document.getElementById('AVAInteractArea');
div.innerHTML = '<div class="d-flex justify-content-end mb-4"><h5>Hi, I am good about you?<span class="badge badge-secondary">You</span></h5></div>';
parent.appendChild(div);
}
And I added a attribute to the button, onclick="addUserAVAInteraction()". Whenever I click the button with id="AVAInteractTypeSubmit", it adds the div to the parent div but only for a second, then it immediately goes away. I need it like how it was working with #brk's solution, please help.
Default button type is submit. So on clicking the button it is refreshing. Add event.preventDefault
function addDiv(parent_div) {
var div = document.createElement('div');
var parent = document.getElementById(parent_div);
div.innerHTML = '<p>TEST</p>';
parent.appendChild(div);
}
var button = document.getElementById('AVAInteractTypeSubmit');
if (button) {
button.addEventListener('click', function(e) {
e.preventDefault();
// change dynamically your new div
addDiv('AVAInteractArea');
});
}
<div class="container">
<div class="row">
<div class="col">
<div id="AVAInteractArea" class="col mb-4 bg-dark justify-content-center" style="max-height: 25rem; overflow-y: auto">
<div class="d-flex justify-content-start mb-4">
<h5>
<span class="badge badge-primary">AVA</span> Hi, how are you?
</h5>
</div>
<div class="d-flex justify-content-end mb-4">
<h5>
Hi, I am good about you?
<span class="badge badge-secondary">You</span>
</h5>
</div>
</div>
<form class="col-lg-6 offset-lg-3 mb-5">
<div class="row form-group justify-content-center">
<input id="AVAInteractType" type="text" placeholder="Ask AVA about law" class="form-control-lg border-white" style="outline: none" autofocus="autofocus">
<button id="AVAInteractTypeSubmit" class="btn-lg btn-primary" style="outline: none">Ask</button>
</div>
<button id="AVAInteractSpeak" class="btn-lg btn-primary" style="outline: none">Or speak to AVA</button>
</form>
</div>
</div>
</div>
This is probably a simple task for you Jquery Guru's but I am really battling to do this.
I have two links and I want them to hide and show two forms.
Initially both forms must be hidden, and when you click on button 1 it must show form 1 and when you click the same button again, it must hide form 1. However if Form 1 is shown, and you click on BTN 2 it must hide Form 1 and show Form 2 and similarly if Form 2 is shown, and you click on BTN 2 again it must hide Form 2.
Sort of like Toggling between the two forms but being able to also hide the other form is if it visible.
This is as far as I have gotten. But it is not working like I want, and moreover it seems to be conflicting with the scripts on Bootstrap 4.
$(document).ready(function() {
$("#btn1").click(function() {
$("#form1").toggle(300);
$("#form2").hide(300);
});
$("#btn2").click(function() {
$("#form2").toggle(300);
$("#form1").hide(300);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Btn 1
Btn 2
<div id="form1" style="display: none;">
<div class="col-lg-12 text-center">
<h4>Advanced Search Leather</h4>
</div>
<!-- Colours -->
<div class="col-lg-12">
<h4>Form 1</h4>
</div>
</div>
<div id="form2" style="display: none;">
<div class="col-lg-12 text-center">
<h4>Advanced Search Gumboots</h4>
</div>
<!-- Colours -->
<div class="col-lg-12">
<h4>Form 2</h4>
</div>
</div>
I also tried this. This works by changing between the forms, but if a form is opened, clicking the same button doesnt close (toggle) the form. By the way, this script works in Bootstrap 4.
$("#leather").click(function() {
var id = $(this).attr("id");
$("#pages div#gumboots").css("display", "none");
$("#pages div#" + id + "").css("display", "block");
});
$("#gumboots").click(function() {
var id = $(this).attr("id");
$("#pages div#leather").css("display", "none");
$("#pages div#" + id + "").css("display", "block");
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<button type="button" id="leather">leather</button>
<button type="button" id="gumboots">gumboots</button>
<div id="pages">
<div id="leather" class="mydivshow" style="display: none;">
<div class="row">
<div class="col-lg-12 text-center">
<h4>Advanced Search Leather</h4>
</div>
<!-- Colours -->
<div class="col-lg-12">
<h4>Colours</h4>
</div>
</div>
</div>
<div id="gumboots" class="mydivhide" style="display: none;">
<div class="row">
<div class="col-lg-12 text-center">
<h4>Advanced Search Gumboots</h4>
</div>
<!-- Colours -->
<div class="col-lg-12">
<h4>Colours</h4>
</div>
</div>
</div>
</div>
Simply change the css() function to toggle() function. css() function will not toggle.
$("#leather").click(function() {
var id = $(this).attr("id");
$("#pages div#gumboots").css("display", "none");
$("#pages #" + id + "").toggle();
});
$("#gumboots").click(function() {
var id = $(this).attr("id");
$("#pages div#leather").css("display", "none");
$("#pages #" + id + "").toggle();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<button type="button" id="leather">leather</button>
<button type="button" id="gumboots">gumboots</button>
<div id="pages">
<div id="leather" class="mydivshow" style="display: none;">
<div class="row">
<div class="col-lg-12 text-center">
<h4>Advanced Search Leather</h4>
</div>
<!-- Colours -->
<div class="col-lg-12">
<h4>Colours</h4>
</div>
</div>
</div>
<div id="gumboots" class="mydivhide" style="display: none;">
<div class="row">
<div class="col-lg-12 text-center">
<h4>Advanced Search Gumboots</h4>
</div>
<!-- Colours -->
<div class="col-lg-12">
<h4>Colours</h4>
</div>
</div>
</div>
</div>
To scroll to an element in my Bootstrap modal, I can check the offset of the element. There are for instance 8 div's, each with their own id (#row-1, #row-2, etc.). If I open the modal and then input the following into the console, I get the correct offset value.
$('#row-6').offset()['top'];
But when I console.log this into the code itself, after opening the modal with .modal('show'), I get 0 back.
How can this difference occur? I tried all the solutions I could find on here, but all solutions gave me the same 0.
My problem would also be solved if I could scroll to the element in any other way with JavaScript.
You must wait for the modal to be shown:
// The modal is shown
$('#yourModal').on('shown.bs.modal', function() {
// Get the right offset
var offset = $("#yourelement").offset();
var offsetTop = offset.top;
var offsetLeft = offset.left;
});
My guess would be that the elements are not done being shown yet in order to give you the correct value? Try using a setTimeout to verify this:
setTimeout(function(){ $('#row-6').offset()['top']; }, 3000);
You said:
My problem would also be solved if I could scroll to the element in
any other way with javascript.
So, here is my suggestion to your problem:
html:
<button id="modal_show" class="btn btn-warning">Show modal</button>
<div id="myModal" class="modal modal-flex fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true" style="margin-top:60px;">
<div class="modal-dialog">
<div class="modal-content" style="padding:5px;">
<div class="modal-body">
<div class="row" id="row1">
<div class="col-xs-12">
<p>
This is row 1
</p>
</div>
</div>
<div class="row" id="row2">
<div class="col-xs-12">
<p>
This is row 2
</p>
</div>
</div>
<div class="row" id="row3">
<div class="col-xs-12">
<p>
This is row 3
</p>
</div>
</div>
<div class="row" id="row4">
<div class="col-xs-12">
<p>
This is row 4
</p>
</div>
</div>
<div class="row" id="row5">
<div class="col-xs-12">
<p>
This is row 5
</p>
</div>
</div>
<div class="row" id="row6">
<div class="col-xs-12">
<p>
This is row 6
</p>
</div>
</div>
<div class="row" id="row7">
<div class="col-xs-6">
<p>
This is row 7
</p>
</div>
<div class="col-xs-6">
<p class="pull-right">
<span class="scroller" data-to="3">Go To 3</span>
</p>
</div>
</div>
<div class="row" id="row8">
<div class="col-xs-6">
<p>
This is row 8
</p>
</div>
<div class="col-xs-6">
<p class="pull-right">
<span class="scroller" data-to="2">Go To 2</span>
</p>
</div>
</div>
</div>
<div class="modal-footer">
<div class="row">
<div class="col-xs-12 pull-right">
<button type="button" class="btn btn-warning" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<!-- /.modal-content -->
</div>
<!-- /.modal-dialog -->
</div>
Jquery:
$('#modal_show').on('click', function(){
$('#myModal').modal({show: true});
});
$('.scroller').click(function(){
var targetId = $(this).attr("data-to");
$('#myModal').animate({
scrollTop: $("#row"+targetId).position().top
}, 1000);
});
and some css:
.row {
min-height:100px;
}
.scroller {
cursor:pointer;
text-decoration:underline;
}
When you scroll down to div's 7 and 8, you will notice links that scroll you up to div #3 and #2 respectively.
working fiddle: http://jsfiddle.net/xL9at8sc/
Hope that helps you and others...