How to attach click events to iframe content? - javascript

I have a scenario where I wanted to load a page on inital load. I found that this would do the trick:
<main id="mainContent">
<iframe id="InitalIframe" src="./Pages/Start/index.html" onload="this.before((this.contentDocument.body||this.contentDocument).children[0]);this.remove()"></iframe>
</main>
I have some links in my header which I attach click listners to:
(function() {
document.querySelectorAll(".link").forEach((item) => {
item.addEventListener("click", (event) => {
event.preventDefault();
const url = event.target.dataset["url"];
getHtmlFile(`./Pages/${url}/`, (data) => {
document.getElementById("mainContent").innerHTML = data;
executeScripts();
});
return false;
});
});
})();
This worked untill I added a few links inside of the Start/Index.html file which gets renderd via the iframe.
I have these two buttons inside of that html.
<button type="button" class="link refbtn" data-Url="One">
One
</button>
<button type="button" class="link refbtn" data-Url="Two">
Two
</button>
Since I attached my listners before the iframe has loaded they never get picked up.
But when I waited for the iframe to load:
document.getElementById("InitalIframe").onload = function() {
document.querySelectorAll(".link").forEach((item) => {
item.addEventListener("click", (event) => {
event.preventDefault();
const url = event.target.dataset["url"];
getHtmlFile(`./Pages/${url}/`, (data) => {
document.getElementById("mainContent").innerHTML = data;
executeScripts();
});
return false;
});
});
};
the click events did not get attached and I got a weird looking result on the page.
Question is how do I accomplish this?

For anyone struggling with the same:
I made my life easier by listening for document click events. when I found that an element with a certain class was clicked I triggered desierd functions:
document.addEventListener(
"click",
function(event) {
event.preventDefault();
const classes = event.target.classList;
if (classes.contains("link")) {
const url = event.target.dataset["url"];
app.fetcHtml(`./Pages/${url}/`, (data) => {
document.getElementById("mainContent").innerHTML = data;
});
}
return false;
},
false
);

You can get to work this with a different approach also. In other words, I had the method closest() in pure Javascript finding me the closest event target that is trigerred when I click inside the container. It will always get me the nearest <a> element which I clicked when I had wandered throught the clickable div/container area.
let base; // the container for the variable content
let dataSet;
base = document.getElementById(base.id); // target your Iframe in this case.
base.addEventListener('click', function (event) {
let selector = '.link'; // any css selector for children
// find the closest parent of the event target that
// matches the selector
let closest = event.target.closest(selector);
if (closest !== undefined && base.contains(closest)) {
dataSet= event.target.dataset["url"];
app.fetcHtml(`./Pages/${url}/`, (data) => {
document.getElementById("mainContent").innerHTML = data;
});
}
});
You can try and see if it works like this also.
Cheers

Related

Adding a function to an element via javascript

So I have a loop that initializes elements and attributes from an array, and I've managed to add everything I need except one thing, a function. The loop in question is below:
for (const character of result) {
let image = document.createElement("img");
image.src = character.src;
image.setAttribute('data-jval', character.jval);
image.setAttribute('id', character.id);
image.setAttribute('class', character.class)
image.setAttribute('draggable', 'true')
// the below function isn't being added to the divs
image.addEventListener('ondragstart', function(event){
let data = event.target.dataset.jval;
event.dataTransfer.setData("text", data);
})
let wrapper = document.createElement('div');
wrapper.appendChild(image);
section.appendChild(wrapper);
}
and the function I'm trying to add to my elements is:
function drag(event) {
let data = event.target.dataset.jval;
event.dataTransfer.setData("text", data);
}
Before trying to create the elements in JavaScript I had them in HTML, and they looked like this:
<img data-jval="a" id="jval-a" src="./images/あ.png" class="j-char-img" draggable="true" ondragstart="drag(event)"/>
but when I recreate it with my loop it looks like this, missing the ondragstart="drag(event"
<img src="/images/あ.png" data-jval="i" id="jval-i" class="j-char-img" draggable="true">
If the rest of my code would be useful I can post that as well.
Just "dragstart" instead of "ondragstart" event:
for (const character of result) {
let image = document.createElement("img");
image.src = character.src;
image.setAttribute('data-jval', character.jval);
image.setAttribute('id', character.id);
image.setAttribute('class', character.class)
image.setAttribute('draggable', 'true')
// the below function isn't being added to the divs
image.addEventListener('dragstart', drag);
let wrapper = document.createElement('div');
wrapper.appendChild(image);
section.appendChild(wrapper);
}
function drag(event) {
let data = event.target.dataset.jval;
event.dataTransfer.setData("text", data);
}
So basically you add the prefix on before the event when you write inline event handlers, just like before when you put your event handler inside your img tag. Same thing for any other events:
click => onclick
submit => onsubmit
keydown => onkeydown
#try to add Semicolon;
image.setAttribute('class', character.class);
image.setAttribute('draggable', 'true');
// the below function isn't being added to the divs
image.addEventListener('ondragstart', function(event){
let data = event.target.dataset.jval;
event.dataTransfer.setData("text", data);
});

How do you handle click-outside of element properly in vuejs?

Is there any proper solution for handling click-outside of elements?
there are general solutions out there, like Handling clicks outside an element without jquery :
window.onload = function() {
// For clicks inside the element
document.getElementById('myElement').onclick = function(e) {
// Make sure the event doesn't bubble from your element
if (e) { e.stopPropagation(); }
else { window.event.cancelBubble = true; }
// Place the code for this element here
alert('this was a click inside');
};
// For clicks elsewhere on the page
document.onclick = function() {
alert('this was a click outside');
};
};
But the problem is almost all projects have multiple and different popups in different components which i should handle their click-outsides.
how should i handle click-outisde without using a global window.on?(I think it is not possible to put all components outside-case handler in window.on )
After struggling with this and searching about this, i found how to solve this problem using vuejs directive without bleeding:
1. using libraries:
v-click-outside is a good one,
https://www.npmjs.com/package/v-click-outside
2. without a library:
```
//main.js
import '#/directives';
......
// directives.js
import Vue from "vue";
Vue.directive('click-outside', {
bind: function (element, binding, vnode) {
element.clickOutsideEvent = function (event) { // check that click was outside the el and his children
if (!(element === event.target || element.contains(event.target))) { // and if it did, call method provided in attribute value
vnode.context[binding.expression](event);
// binding.value(); run the arg
}
};
document.body.addEventListener('click', element.clickOutsideEvent)
},
unbind: function (element) {
document.body.removeEventListener('click', element.clickOutsideEvent)
}
});
```
use it every-where you want with v-click-outside directive like below:
//header.vue
<div class="profileQuickAction col-lg-4 col-md-12" v-click-outside="hidePopUps">
...
</>
you can check this on
You can also directly use VueUse vOnClickOUtside directive.
<script setup lang="ts">
import { vOnClickOutside } from '#vueuse/components'
const modal = ref(true)
function closeModal() {
modal.value = false
}
</script>
<template>
<div v-if="modal" v-on-click-outside="closeModal">
Hello World
</div>
</template>
It might be little late but i ve found a clear solution
<button class="m-search-btn" #click="checkSearch" v-bind:class="{'m-nav-active':search === true}">
methods:{
checkSearch(e){
var clicked = e.target;
this.search = !this.search;
var that = this;
window.addEventListener('click',function check(e){
if (clicked === e.target || e.target.closest('.search-input')){ //I ve used target closest to protect the input that has search bar in it
that.search = true;
}else {
that.search = false;
removeEventListener('click',check)
}
})
}}

How to use event delegation to execute a function based on clicked element's id?

I've worked with event delegation in the past but for some reason I'm having trouble setting up a single event listener that executes one of three functions depending on the ID of the element clicked.
Here's the code without event delegation:
eventListeners: function() {
document.getElementById("button-1").addEventListener('click',
function() {
shuffler.reset1();
shuffler.displayCards();
});
document.getElementById("button-2").addEventListener('click', function() {
shuffler.reset2();
shuffler.displayCards();
});
document.getElementById("button-3").addEventListener('click',
function() {
shuffler.reset3();
shuffler.displayCards();
});
I've tried using something along the lines of:
document.getElementsByClass("button").addEventListener('click', function
() {
if (event.target.id == "button-1") {
shuffler.reset1();
}
});
Attach the listener to the container that contains all buttons. Then, I'd use an object indexed by id, and check if the id of the element that was clicked exists in the object - if so, run the function:
const fns = {
'button-1': () => {
shuffler.reset1();
shuffler.displayCards();
},
// ...
}
document.querySelector('< something that contains all buttons >').addEventListener('click', ({ target }) => {
const { id } = target;
if (fns[id]) {
fns[id]();
}
});
Note that in this particular case, you can use just one function by checking the last number in the ID:
document.querySelector('< something that contains all buttons >').addEventListener('click', ({ target }) => {
const { id } = target;
if (id.startsWith('button-')) {
const buttonNum = id.match(/\d+/)[0];
shuffler['reset' + buttonNum]();
shuffler.displayCards();
}
});

Event listener on multiple elements with the same class

On the site I have a navbar. When I click on the a in navbar I want a new div (with content) appears and everything else "hides". I did it withdisplay: none. In the corner there should be an "X" which closes the div and makes "first screen" appear again.
I did the first part, but have some problems with closing. Here is my code:
const about = document.getElementById('li-about');
const work = document.getElementById('li-work');
const contact = document.getElementById('li-contact');
^These are links in a navbar.
const openSlide = (id) => {
document.querySelector('main article#' + id).style.display = 'block';
document.querySelector('header').style.display = 'none';
};
about.addEventListener('click', () => openSlide('about'));
work.addEventListener('click', () => openSlide('work'));
contact.addEventListener('click', () => openSlide('contact'));
And here is the code. It works. But when I want to do similar thing to a closing div function, it only works with about, not work and contact.
const closeSlide = (id) => {
document.querySelector('main article#' + id).style.display = 'none';
document.querySelector('header').style.display = 'block';
};
const close = document.querySelector('.close');
close.addEventListener('click', () => closeSlide('about'));
close.addEventListener('click', () => closeSlide('work'));
close.addEventListener('click', () => closeSlide('contact'));
Can you tell me why? There is no error in console, I tried to replace closeSlide function with a simple console.log and it doesn't work as well. Is it possible that JavaScript detects only one (first in HTML code) .close div?
Is it possible that JavaScript detects only one (first in HTML code) .close div?
Yes, document.querySelector returns the first matching element it finds in the DOM. If you want to add your listeners to every .close on the page, either loop through the NodeList returned by document.querySelectorAll:
const closeList = document.querySelectorAll('.close');
closeList.forEach(element => {
element.addEventListener('click', () => closeSlide('about'));
element.addEventListener('click', () => closeSlide('work'));
element.addEventListener('click', () => closeSlide('contact'));
};
or add a listener to an element containing all of your .close elements that only takes action if a .close was clicked:
document.querySelector('#some-container').addEventListener('click', evt => {
if (!evt.target.closest('.close')) return;
closeSlide('about');
closeSlide('work');
closeSlide('contact');
});

Toggle Event Listeners

I am trying to make a function that would allow me to toggle eventListener of an element.
In the example below, I have three buttons: main, on and off. When I click on the on button, the main button becomes functional. After I click off button, the main button should not work anymore (but now it still does).
Now I can achieve a desired behavior by clicking on button for the second time, but I guess it's a bad coincidence and it's not supposed to work that way.
Maybe I should add that I would like to work this out without using jQuery or similar and it needs to be a function, because I am going to use it for a lot of buttons.
(I suspect something with scope causes the problem (clickHandler when calling the function to activate the button is not the same as the clickHandler when calling the function to disable the button), but I can't think of a way to test it.)
// buttons definitions, not important
var mainButton = document.querySelector("#mainButton");
var onButton = document.querySelector("#onButton");
var offButton = document.querySelector("#offButton");
// main function
var toggleButtons = function(toggleVal, button, element) {
var activateButton, clickHandler, disableButton;
// callback function for listener bellow
clickHandler = function() {
document.querySelector(element).classList.toggle("yellow");
};
activateButton = function() {
button.addEventListener("click", clickHandler);
};
disableButton = function() {
button.removeEventListener("click", clickHandler);
};
// when first argument is 1, make the button functional, otherwise disable its functionality
if (toggleVal === 1) {
activateButton();
} else {
disableButton();
}
};
// when onButton is clicked, call main function with arguments
// this works
onButton.addEventListener("click", function() {
toggleButtons(1, mainButton, "body");
});
// this fails to disable the button
offButton.addEventListener("click", function() {
toggleButtons(0, mainButton);
});
.yellow {
background-color: yellow;
}
<button type="button" id="mainButton">mainButton
</button>
<button type="button" id="onButton">onButton
</button>
<button type="button" id="offButton">offButton
</button>
<p>mainButton: toggles background color on click
</p>
<p>onButton: turns on mainButtons's functionality</p>
<p>offButton: supposed to turn off mainButton's functionality</p>
var mainButton = document.querySelector("#mainButton");
var onButton = document.querySelector("#onButton");
var offButon = document.querySelector("#offButton");
var element; // declare the element here and change it from toggleButtons when needed.
function clickHandler() {
document.querySelector(element).classList.toggle('yellow');
}
function activateButton(button) { // You missed this part
button.addEventListener('click', clickHandler);
}
function disableButton(button) { // You missed this part
button.removeEventListener('click', clickHandler);
}
function toggleButtons(value, button) {
if (value === 1) {
activateButton(button); // You missed this part
} else {
disableButton(button); // You missed this part
}
};
onButton.addEventListener('click', function() {
element = 'body'; // you can change it to some other element
toggleButtons(1, mainButton);
});
offButton.addEventListener('click', function() {
element = 'body'; // you can change it to some other element
toggleButtons(0, mainButton);
});
Below code helps to toggle between two functions from an eventListener:
var playmusic=false;
function playSound() {
const audio = document.querySelector(`audio[data-key="${event.keyCode}"]`)
audio.currentTime = 0
audio.play()
playmusic=true;
}
function stopSound() {
const audio = document.querySelector(`audio[data-key="${event.keyCode}"]`)
audio.pause()
playmusic=false;
}
window.addEventListener('keydown',
function(){playmusic?stopSound():playSound()} )

Categories

Resources