Different #click event on component - VueJS - javascript

My project start with VueJS and Buefy.
The component have two different actions click :
Click on Cyan area -> redirection to other page (Action 1)
Click on Magenta area -> show dropdown (Action 2)
But when I click to Action 2, always Action 1 works.
Here my component :
<MyComponent
:projects="data"
#click.native="actionOne()"
/>
And inside my component, I have dropdown (using Buefy component) :
<p>{{ data.projects }}</p>
<BDropdown aria-role="list">
<BButton
slot="trigger"
class="button"
type="is-text"
#click.prevent="actionTwo()"
>
<BIcon icon="dots-horizontal" />
</BButton>
<BDropdownItem aria-role="listitem">Update</BDropdownItem>
<BDropdownItem aria-role="listitem">Archive</BDropdownItem>
</BDropdown>
I try to use different event modifier but I can't have the expected behavior :
stop
prevent

This probably happens because of event bubbling. When you click on the dropdown element, the click event bubbles up to the cyan area. What you need to do is cancel the event bubbling for the dropdown element.
<BDropdown aria-role="list">
<BButton
slot="trigger"
class="button"
type="is-text"
#click="actionTwo($event)"
>
<BIcon icon="dots-horizontal" />
</BButton>
<BDropdownItem aria-role="listitem">Update</BDropdownItem>
<BDropdownItem aria-role="listitem">Archive</BDropdownItem>
</BDropdown>
<script>
export default {
methods: {
actionTwo(e) {
e.cancelBubble = true
}
}
}
</script>

I found the solution. The problem came to specific event from Dropdown component (Buefy). So I added stop modifier to Dropdown trigger click event and I added prevent in my component.
Here the solution :
<MyComponent
:projects="data"
#click.native.prevent="actionOne()"
/>
<BDropdown aria-role="list" #click.native.stop>
<BButton
slot="trigger"
class="button"
type="is-text"
>
<BIcon icon="dots-horizontal" />
</BButton>
<BDropdownItem aria-role="listitem">Update</BDropdownItem>
<BDropdownItem aria-role="listitem">Archive</BDropdownItem>
</BDropdown>

You can use the self modifier.
<MyComponent
:projects="data"
#click.native.self="actionOne()"
/>
As the documentation says:
only trigger handler if event.target is the element itself
i.e. not from a child element
(source)

Related

How to click on an element that is in the body pragmatically from inside of an angular component?

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.

How to get button value when event is propagated

I am making a react button component and the component looks like this
const Button = props => {
return (
<button
style={props.style}
onClick={props.onClick}
className={`btn ${props.color} ${props.loading &&
"loading"} ${props.block && "block"} ${props.className}`}
disabled={props.disabled}
type={props.type}
value={props.value}
>
<span className={"content"}>
{props.icon && <span className={"icon-left"}>{props.icon}</span>}
{props.children}
</span>
{props.loading ? <Spinner /> : null}
</button>
);
};
The issue arises when i try to add a value prop and an event listener to the button component.
If i do that and i try getting the event.target.value value from the onClick handler, it gets to work only when i click other parts of the button, clicking the span text returns an undefined
This seems logical since there is no value on the span, what is the best way i could use to fix this?
You should use event.currentTarget instead of event.target
The currentTarget event property returns the element whose event
listeners triggered the event.
More on reading here.
Use event.currentTarget.
Add an attribute data-value to the span. So on click get the event.currentTarget.value or event.currentTarget.dataset.value
Inside the handler do like this
let m = event.currentTarget.value?
event.currentTarget.value:
event.currentTarget.dataset.value

How to get the event target inside the parent component in ReactJS

I have a Main component with code
changeColor = (color) => {
}
toggle = (e) => {
console.log(e.target)
}
<div>
<EditComponent changeColor={this.changeColor.bind(this)}>
<TextComonent toggle={this.toggle.bind(this)}>
</div>
Edit component is
color = (value) => {
this.props.changeColor(value)
}
<div>
<button value='red' onClick={this.color.bind(this,"red")}>Red</button>
<button value='blue' onClick={this.color.bind(this,"blue")}>Blue</button>
</div>
Text component is
toggle = (e) => {
this.props.toggle(e)
}
<div>
<p class="black-color" onClick={this.toggle.bind(this)}>Text 1</p>
<p class="black-color" onClick={this.toggle.bind(this)}>Text 2</p>
</div>
I will be clicking on Text 1 or Text 2 first and I will get the event inside toggle function. Next I will click the button Red or Blue. Then I want to change the class to either red-color or blue-color for that particular Text that i have clicked before. How can I get the event inside the parent component to find the particular text or is there any other way to to this?
I want to get the event.target inside the Parent component. I got the event object in parent but event.target is null
<div>
<EditComponent changeColor={this.changeColor.bind(this)}>
<TextComonent toggle={this.toggle}>
</div>
try this way dont bind function in parent component and try,you will get the target
You are not using "bind" correctly. You don't need to bind with an anonymous function.
class Hello extends React.Component {
render() {
return (
<div>
<p onClick={(e) => this.toggle(e)}>
Test
</p>
</div>);
}
toggle = (e) => {
console.log(e.target.innerText);
}
}
From the event variable in toggle, you can perform your changes as need be.
I found the exact solution as to add event.persist(); to get the event.target inside parent component.

Event listener outside of Shadow DOM won't bind to elements inside of Shadow DOM

I have an Angular web component installed on my site. It uses Shadow DOM so it's super fast (which it has to be in my case).
On my site I also have a shortcut on h which opens up a popup that displays some helpful information. It's a must that this h keybinding stays as it is. Example code of how it was implemented can be seen here: https://jsfiddle.net/js1edv37/
It's a simple event listener that listens on document:
$(document).on("keyup", function(e) {
}
However, this also gets triggered when my web component has focused textarea or input elements. This happens because it uses Shadow DOM, which a script from the outside cannot access.
You can test it by pressing h on the keyboard inside and outside of the input and textarea elements.
Is there a way to let my script from outside of the Shadow DOM web component, still listen for the keyup event, but make it listen for all elements on the page? Even the ones inside the Shadow DOM.
In the Web Component, get the input element with a querySelector() call on the shadowRoot property:
let textareainshadow = div.shadowRoot.querySelector( 'textarea' )
Then listen to the keyup event and stop its propagation with the help of the stopImmediatePropagation() method.
textareainshadow.addEventListener( 'keyup' , ev => {
console.log( 'caught', ev.type )
ev.stopImmediatePropagation()
})
https://jsfiddle.net/7mkrxh25/1/
If you save the reference to the shadow root you can always access it's children as search on those
$(document).on("keyup", function(e) {
let focusedInputs = $("input:focus, textarea:focus").length + $(shadow).children("input:focus, textarea:focus").length;
if (focusedInputs > 0) {
return true;
}
if (e.keyCode === 72) {
trigger();
}
});
function trigger() {
alert("If this was triggered, everything is perfectly fine");
}
let div = document.querySelector("div");
let shadow = div.createShadowRoot();
shadow.innerHTML = "<textarea>This shouldn't fail</textarea>";
textarea {
width: 500px;
height: 100px;
}
input {
width: 250px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<textarea>Some stuff here</textarea>
<br />
<input type="text" value="Some more text here" />
<br />
<br />
<h1>Shadow DOM element WON'T fail now :)</h1>
<div></div>
Fiddle

How to handle onKeyDown event on div in ReactJS

I'm trying to handle key event when load page component.
First, I have a router:
<Router>
<Route exact path="/" component={Home} />
</Router>
In home component, I try to bind onKeyPress in div element but it's not work. I bind it on input element, it's worked.
return (
<div onKeyDown={this.__handleKeyDown} className="container" style={{ backgroundImage: `url(${this.state.backgroundbanner})` }}>
<input
className="hidden"
onKeyDown={this.__handleKeyDown}
ref={(input) => { this.dummyInput = input; }}
/>
<div className="container-shadow">
<h1 className="main-title">{this.state.title}</h1>
<h3 className="main-description">{this.state.description}</h3>
<ListMovie cursor={ cursor } />
</div>
</div>
)
How to bind event onKeyDown on div element or how to bind key event when load a page component in Route. Because, input element can be out-focus and this key event cannot be excute.
Thanks.
The reason as to why it doesn't work is that the div element requires the tabIndex attribute in order to be focusable and to handle keyDown events.
<div tabIndex="1" onKeyDown={this.__handleKeyDown}></div>
Approach 1:
For the event to trigger, your div needs to be selected. To do this you need to focus it in the componentDidMount event. And to do this you need a ref to your div.
Step 1: get a ref to your div
<div onKeyDown={this.__handleKeyDown} ref={(c) => {this.div = c;}}>
Step 2: Focus it on load
componentDidMount() {
this.div.focus();
}
Approach 2:
Listen to events on the entire document
componentDidMount() {
document.addEventListener('keydown', this.onKeyDown);
}
componentWillUnmount() {
document.removeEventListener('keydown', this.onKeyDown);
}

Categories

Resources