I want to show a modal when I click on and icon. The modal template is inside a template string in my js.
html
<i id="settings-icon" class="fa fa-cog" onClick='attachModal()'></i>
javascript
const attachModal = () => {
const modal = `
<div class='modal>
Modal
</div>
`;
document.body.insertAdjacentHTML('beforeend', modal);
};
There is not error messages however I don't see the modal code in the dom after I click
I'd recommend using [innerHTML][1] and [node.remove()][1] for this since the modal is only either supposed to be visible or hidden. You can append the modal code to the html by using document.body.innerHTML += modal. Using += will concatenate the new HTML to the existing one without replacing/removing any of the existing HTML.
If isModal is true (meaning the modal is already visible) then use isModal.remove() which is a method that a child node can use to remove itself from it's parent (in this case body).
By adding the logic that both hides or shows the modal conditionally, you can reuse this function in what I assume will be a close or cancel button within the modal.
*Note: I use a p tag instead of an i tag for demonstrative purposes. The p tag is not crucial to the solution.
const attachModal = () => {
var isModal = document.getElementById('modal')
const modal = `<div id="modal">
MODAL
</div>`
if (isModal){
isModal.remove()
} else {
document.body.innerHTML += modal
}
};
<p id="settings-icon" class="fa fa-cog" onClick='attachModal()'>test</p>
Related
I have a website on which I have crisp chat service running and I'm trying to click on the chat box from one of my component's typescript files.
The crisp chat box is a div with the id of crisp-client inside body tag. How do I click on it from inside my typescript?
Inject Renderer2 in constructor -
constructor(private renderer: Renderer2) {}
Get the crisp-client element in your component -
let crispClient = this.renderer.selectRootElement('#crisp-client');
Perform click() event -
crispClient.click();
Working demo here
Added a test method on div to check -
<div id="crisp-client" onClick="console.log('crisp client clicked')"></div>
You can use the ViewChild decorator and pass a template reference variable as a string, and manipulate the event. Here's a simple example of clicking Button 1, which programmatically clicks Button 2 and due to that click, the text of Button 2 is changed:
<button #button1 (click)="clickButton2()">
Click to change the text of Button 2
</button>
<button #button2 (click)="changeText()">{{ buttonText }}</button>
buttonText = 'Button 2';
#ViewChild('button2') button2: ElementRef<HTMLElement>;
clickButton2() {
let el: HTMLElement = this.button2.nativeElement;
el.click();
}
changeText() {
this.buttonText="Changed!"
}
Here's a Stackblitz demo
UPDATE
You can access elements of body using document object in Angular. This way, you can achieve the click of the element which is inside body. Here's one more example where I am clicking the button which is inside body from a component.
<button (click)="handleClick()">Programatically click the button inside body</button>
ngOnInit() {
let btn = document.getElementById('main');
btn.addEventListener('click', (e: Event) => btn.innerHTML = "Clicked!");
}
handleClick() {
document.getElementById('main').click();
}
index.html
<html>
<body>
<my-app>loading</my-app>
<button id="main">Click</button>
</body>
</html>
Here's a Stackblitz demo.
I am using Django templating engine and JavaScript. My HTML looks like this
<p class="content-card__address">{{ z.formatted_address|truncatewords:6 }}</p>
<div class="content-card-inner">
<p class="content-card__review">Отзывы ({{ z.post_relate.all.count }})</p>
<p class="content-card__phone">{{ z.international_phone_number }}</p>
<div class="div-shaddow"></div>
<p class="content-card__text">Показать</p>
</div>
Cards with text to be generated on the backend using a template engine. My JavaScript code only works on the first card and I need it to work on all cards. With JavaScript I add a class to the div elements. Here is my JavaScript
let call = document.querySelector('.content-card__text');
let divShadow = document.querySelector('.div-shaddow');
call.addEventListener('click', clickCall)
function clickCall() {
call.classList.add('visually-hidden');
divShadow.classList.add('visually-hidden');
}
This code returns you the first element in the DOM and you add click handlers only for it
document.querySelector('.content-card__text')
It will work for you:
const buttons = document.querySelectorAll('.content-card__text');
buttons.forEach(button => {
button.addEventListener('click', clickCall);
});
But please also note that you need to take this into account when working with .divShadow if this element is not alone on the page
Update: example based on your comment
const buttons = document.querySelectorAll('.content-card__text');
const divShadow = document.querySelectorAll('.div-shaddow');
buttons.forEach((button, index) => {
button.addEventListener('click', () => clickCall(index));
});
function clickCall(index) {
buttons[index].classList.add('visually-hidden');
divShadow[index].classList.add('visually-hidden');
}
I want to change to make it function into my Angular project
the script code
<script>
let btn = document.querySelector("#btn");
let sidebar = document.querySelector(".sidebar");
let searchBtn = document.querySelector(".bx-search");
btn.onclick = function() {
sidebar.classList.toggle("active");
if(btn.classList.contains("bx-menu")) {
btn.classList.replace("bx-menu", "bx-menu-alt-right");
} else {
btn.classList.replace("bx-menu-alt-right", "bx-menu");
}
}
</script>
Angular does all of these actions differently. Instead of querying DOM elements and affecting them from a script, you bind those elements to the scope this.
Much of what you need to accomplish actually happens in the HTML, and there is no need for ID tags on your elements
In your app.component.ts
export class AppComponent {
isBXMenu = false; // this isn't required because its just a boolean used in the HTML but it's good form to have it here
bxMenuAlt = false; // this is now how you switch the class name. When you need it to be bx-menu-alt-right, set this.bxMenuAlt = true
toggleBXMenu():void() {
this.bxMenuAlt = !this.bxMenuAlt
}
}
In your HTML
<!-- here is your button -->
<i class='bx bx-menu' id="btn" (click)="isBXMenu=!isBXMenu"
*ngClass="{'bx-menu-alt-right': bxMenuAlt, 'bx-menu': !bxMenuAlt}" ></i>
Toggle sidebar BX Menu</button>
<!-- this is the new sidebar container -->
<div *ngClass="{'bx-menu':isBXMenu}" class='sidebar'>
<!-- ... -->
</div>
so I try to make some simple content of modal window as a shopping cart only using js, and there is a problem with delete of each item by "x" after I add them on the cart, I use event.target, but at that stage it gives me an error as "null", it is in the last row of the code. Dont be strict, its my first code :)
so each time I insert in cart
cartItems.innerHTML += `<div class="modal-items-flex ">
<div>
<h2> Item Price: ${itemPrice} </h2>
<h2 class="underscore">Item Name: ${itemTitle} </h2>
</div>
<div class="modal-item-delete">+</div>
</div>`
let removeButton = document.querySelector(".modal-item-delete");
removeButton.onclick=function(e){
e.target.parentElement.remove();
}
I would not attach a new event-listener to each item, but instead would delegate the event-handling to the parent, for example:
cartItems.addEventListener('click', (e) => {
const btn = e.target.closest('.modal-item-delete');
if (!btn) return;
btn.parentElement.remove();
});
Using Axios, I'm pulling in a static HTML file. This part is working
The user clicks on an edit button and I'm going through that static HTML and adding a new class if an existing class exists.
If that existing class exists, I want to add a new button with v-on in this static HTML template and re-render the content with this new button in the HTML which then spawns an overlay.
Is there anyway that I can add this new button in my code so that view re-renders and uses the Vue v-on directive?
Here is my code:
VIEW:
<template>
<div>
<div class="row">
<div id="kbViewer">
<b-button
class="request-edit"
#click="letsEditThisStuff({currentUrl: currentUrl})">Request An Edit</b-button>
<div v-html="htmlData">
{{ htmlData }}
</div>
</div>
</div>
</div>
</template>
data: function () {
return {
sampleElement: '<button v-on="click: test()">test from sample element</button>',
htmlData: '',
};
},
methods: {
pullView: function (html) {
this.axios.get('../someurl/' + html).then(response => {
let corsHTML = response.data;
let htmlDoc = (new DOMParser()).parseFromString(corsHTML, "text/html");
this.rawDog = htmlDoc;
this.htmlData = htmlDoc.documentElement.getElementsByTagName('body')[0].innerHTML;
})
},
letsEditThisStuff(item) {
let htmlDoDa = this.htmlData;
// This doesn't work - I'm trying to loop over the code and find all
// of the class that are .editable and then add a class name of 'editing'
// to that new class. It works with #document of course...
for (const element of this.htmlData.querySelectorAll('.editable')) {
element.classList.add('editing');
// Now what I want to do here is add that sampleElement from above - or however -
// to this htmlData and then re-render it.
let textnode = document.createElement(sampleElement);
textnode.classList.add('request-the-edit')
textnode.innerHTML = 'edit me!'
element.append('<button v-on="click: test()">test from sample element</button>')
console.log('what is the element?', element)
}
this.htmlData = htmlDoDa
},
}
I know that some of my variables are not defined above - I'm only looking at a solution that helps with this - basically take that stored data.htmlData, parse through it - find the classes with "editable" and append a button with a v-for directive to that specific node with "editable" ... Unfortunately, the HTML already exists and now I've got to find a slick way to re-parse that HTML and re-append it to the Vue template.
I found Vue Runtime Template and it works PERFECTLY!
https://alligator.io/vuejs/v-runtime-template/