How to access element in React JS that render by JS plugin - javascript

Is there a way to access the HTML element that rendered by JS plugin in React JS Ecosystem. I can't use ref on those elements.
for example:- If I use React Slick plugin, It adds many HTML elements that can't access by React JS. I need to trigger a mouse hover event on those elements.
Does anyone have a solution for this kind of situation?
Thanks.

Suppose the id of the container div that wraps the <Slider/> component is called container then the following code should work in attaching the mouseover event to all the nodes (divs in the slider):
componentDidMount(){
let nodes = document.getElementsById("container").childNodes[0].childNodes
nodes.forEach(node => {
node.addEventListener('mouseover', () => {
//action to be performed here
}
})
}

maybe it will help
componentdidmount{
const elemnts = [...document.getElemetntByClassName('ClassName')]
elements.forEach(e => e.addEventListener('mouseover', () => {
// your code here
}))
}

Plugins has their own class and id. You can always inspect and customize the class they are using. But this may cause global changes. What you can do is to use custom class and selectors for separate components. Then you can make any changes in the css.

Related

Adding dynamic eventlistners in VueJS3/Nuxt app

Im currently struggling with something where i want to add a data attribute to a component and then based on when NUXT is loaded have a click event bind to all nodes that have this data attribute. Im not using v-on because i want to have this separated from current Vue logic. So example:
component a.vue is tagged with data-element
<a href="/somelink" data-element>link</a>
component b.vue also has HTM elements tagged with data-element
<button data-element>link</button>
When the app loads i need to then loop through all data-element and bind an eventlistner to them.
I tried the above method and that works to some degree but fails when reactivity sets in and the DOM is updated. I checked mixins (not recommended using VueJS3), used composition API, used a mutation observer that checked the DOM status for changes and based on new elements loaded it ads click events, looked at hooks etc but now im getting confused at what is the best way to proceed. Some solutions work to some extend but feels hacky. Or is there a completely different approach i am missing.
To be Sure that the DOM has been initialized you need to set your event listeners on "mounted" lifecycle
mounted() {
const elements = [...document.querySelectorAll('[data-element]')];
elements.forEach(element => {
element.addEventListener('click', () => { /* your code here. */ })
})
}

React Hooks - Using useRef without direct access to HTML Element Code?

With React I'm inside of one repository, and the HTML elements are loading from another repo, which I watch for using pageLoaded. Inside updateHeader there is just more HTML element selecting and attribute/class manipulation.
useEffect(() => {
if (pageLoaded.status) {
if (someCondition) {
updateHeader(ubeName);
} else {
document.querySelector('.headerbar-menu').style.display = 'block';
if (document.querySelector('.headerbar-menu.affiliates-wrapper')) {
document.querySelector('.headerbar-menu.affiliates-wrapper').style.display = 'none';
}
}
}
}, [pageLoaded.status])
The problem here is obviously we shouldn't be using querySelector, and i think it may be causing some unexpected functionality. The elements dont properly evaluate and render until some piece of state changes i.e. a scroll state handler, so on initial page load the elements dont show with their new attributes until a scroll.
I'd like to attempt to resolve using useRef, but don't have direct access to the html. Is there a way to dynamically connect a ref to an element without access to the HTML code?
Thanks for your time and attention!
The best way to do this, in my opinion, is in this sequence:
Attempt to select the element
If non-existant, set up a DOMSubtreeModified event handler or a MutationObserver
Clean up DOMSubtreeModified event handler or a MutationObserver (or keep it around to watch for updates)
This allows for use of query selectors in a safe and modern way which doesn't stray too far from React's recommendations

Is it good idea in React to modify attribute values of an element through Javascript?

Since React has its own copy of the DOM, what is the best way to modify an HTML element's attributes without affecting React's virtual DOM (Performance)?
Let's say I want to toggle between adding and removing an active class from a list of divs based on their visibility (Intersection Observer)
In Javascript I can just do:
if (inView) {
element.classList.add('active')
} else {
element.classList.remove('active')
}
Will this affect React's virtual DOM? If yes can you please suggest the better way to do it?

Vue template: How to automatically add custom attribute to elements that have a v-on:click directive

We are using single file vue components and in a mousemove event handler we'd like to be able to detect if the target element is clickable.
In our Vue templates we are using v-on directives: v-on:click="someCallback".
Unfortunately there doesn't seem to be an easy way to tell for a given element if an event listener was registered for it (i.e. via v-on directive).
For this we'd like to add a custom attribute to those elements with a v-on:click directve - i.e. "clickable". But this should happen automatically.
So we'd have to either wrap Vue's own "on"-directive into a custom one or somehow hook into Vue's rendering cycle - but this seems not very straight-forward: Couldn't find the directive on the Vue instance or the Vue component object.
What we have tried:
retrieving the information about registered listeners from the target element provided by the event object passed to the event handler. But apparently browsers don't provide this information.
searching the Vue component object for some object that stores information about which event listener has been registered for which element with which handler. We were not able to find this information - but it should be somewhere, right?
Hope anyone has a nice idea on how to accomplish adding a custom attribute to elements with v-on:click directive automatically.
Thanks!
EDIT:
So we have i.e.
<div id="x" #click="someMethod" />
in our template.
But we want to add a custom attribute automatically (we dont want to add it manually for all the trillion cases):
<div id="x" clickable #click="someMethod" />
Then in the event handler for addEventListener('mousemove', handler) we would check for this attribute: if (e.target.hasAttribute('clickable'))
But any other way of accomplishing this (so being able to tell inside the handler for mousemove if the element is clickable) would be fine too.
You could create a container component and import it into all your other vue components, ensuring it's the first component in your template, like:
<template>
<v-container>
// your template here
</v-container>
</template>
<script>
// Obviously replace the path and point to your location of the component
import ComponentContainer from './common/ComponentContainer.vue'
export default {
name: 'MyClientComponent',
components: {
'v-container': ComponentContainer
}
}
</script>
And this is the container component that looks for click events and adds the clickable class:
<template>
<div class="component-container">
<slot></slot>
</div>
</template>
<script>
export default {
name: 'ComponentContainer',
mounted() {
this.$slots.default.forEach(vn => {
this.addClickableClassNames(vn);
});
},
methods: {
addClickableClassNames(vnode) {
if (vnode) {
let data = vnode.data;
if (data && data.on) {
// Check for click events and add a
// clickable class if one exists
if (data.on.click && vnode.elm && vnode.elm.classList) {
vnode.elm.classList.add('clickable');
}
}
// Now recursively check children
if (vnode.children) {
vnode.children.forEach(vn => {
this.addClickableClassNames(vn);
});
}
}
}
}
}
</script>
This works, but I wouldn't like to comment on the performance of a large dom. And you, and other devs, need to remember to import into all components, which isn't ideal. But, it's a solution that might give you other ideas on improving and making more scalable.
I can't think of a way to "automatically" add this clickable attribute. I think unfortunately you will still need to "tag" your clickable elements one by one.
I would have a directive which you can add to any element in your templates.
Directive
Vue.directive('myDirective', {
inserted(el, bindings) {
el.addEventListener('mouseover', () => {
alert(bindings.value);
})
}
});
Usage
<span v-my-directive="true">Element 1</span>
<span v-my-directive="false">Element 2</span>
You will notice that in the template when using the directive a value is being passed to it. This is then read via bindings.value. Of course based on this value you can do whatever functionality you need.
JSFiddle: https://jsfiddle.net/tc45xf82/2/
Vue Docs: https://v2.vuejs.org/v2/guide/custom-directive.html

How to bind css classes to angular2 elements, post-compiling?

If I insert the html code directly in the HTML obviously that the css is noted and the element is correctly displayed.
However, if I try to dinamically create the element in javascript and insert it the css classes won't be recognized.
For example, I've tried:
var el = document.createElement("div").setAttribute("class","some_class");
(...).appendChild(el).
And el does not obey to the css rules set by some_class
The only way I've been able to do this is directly change the element properties in javascript:
var el = document.createElement("div").style.width = "20px"; //this works
(...).appendChild(el).
The element is correctly styled.
Unfortunately I wanted to go by the class names / ids.
So, any idea on how to do this? How exactly can I bind the newly created elements in javascript via _ngcontent-vkl-6 tags created after angular2 compiling?
Use Renderer or Renderer2 (if using angular 4+):
constructor(private renderer: Renderer) {}
createElement() {
const element = this.renderer.createElement(theElementToAppendTo, 'div');
this.renderer.setElementAttribute(element, 'class', 'some_class');
}
The way you're doing it isn't safe for angular, DOM manipulation should only be done via the Renderer or other bindings such as HostBinding.
This example uses the Renderer:
https://angular.io/docs/js/latest/api/core/index/Renderer-class.html
But if you're using angular 4+ you should use Renderer2 which has a different api:
https://angular.io/docs/ts/latest/api/core/index/Renderer2-class.html
I hope this helps.

Categories