How to add custom vue component with using Javascript? - javascript

I am trying to create a live translation instance on my app, and when the user clicks the translate button, a custom Vue component should be added to all the elements that have a data-key attribute. I know and researched that there is a way to add the component to the template section and control its visibility by v-if, but I can't do that because the app is huge and there is no way I can implement the component to all pages, I want more automated solution.
Here is what i tried so far:
onTranslate() {
this.inTranslationMode = !this.inTranslationMode
if (this.inTranslationMode) {
const elements = document.querySelectorAll('[data-key]')
elements.forEach(element => {
const key = element.getAttribute('data-key')
//add TranslationPopup component with the key
let div = document.createElement('div')
div.innerHTML = `<translation-popup translationKey="${key}"></translation-popup>`
element.appendChild(div)
})
}
}
How can I manage this without adding the component to all pages, is there a better solution in Javascript that I can try?

Related

Angular: How to use a component dynamically in another component?

I have an DialogService for Angular Material:
constructor(private dialog: MatDialog){}
openDialog(dialogData){
const dialogRef = this.dialog.open(DialogComponent, {
data: dialogData
}
}
and a DialogComponent to open the dialog with:
let componentToRender
constructor(#Inject(MAT_DIALOG_DATA) public dialogData){
this.componentToRender = dialogdata.componentToRender
}
and this template for it:
<div class="dialog">
<ng-container></ng-container> // Here i want to dynamically render a given component
</div>
I want to give my dialogService with the dialogData a reference to an component that i want to be rendered inside my diaologComponent <ng-container>
The result should be, that i can call my service with a reference to a component to open a dialog container that renders this given component inside the component.html's ng-container. For example like so:
let dialogData = {}
dialogData.componentToRender = COMPONENT_TO_RENDER_INSIDE_OF_DIALOG
this.dialogService.openDialog(dialogData)
The idea is to make something like a dialog-container where the body can be any component i want to render inside of the dialog-container
I hope it is enough to write only the essential code, because I ask this question from another computer and could not copy paste the stuff I already have. thank you :)
For now I kind of solved this with ViewContainerRef.
I use the createComponent() method and give it the Component I want to render.
Then I insert the create ref inside my ng-template.
#ViewChild('container', {read: ViewContainerRef}) container!: ViewContainerRef
const componentRef = this.viewContainerRef.createComponent(MY_COMPONENT_DYNAMICALLY_GIVEN)
this.container.insert(componentRef.hostView)
This works but also renders my component selector tag around my content.
<my_inserted_component> <!-- I need to get rid of this :D -->
<!-- contents of my_inserted_component -->
</my_inserted_component>
That sadly results into Layouting problems. So now I need to find out how to change my CSS or (better) how to get rid of the outer tag with the component selector name.
EDIT: Also I should mention that I am on Angular 14

When i use ref to nuxt-link, i can't change styles on it (Nuxt.js)

In my function I am using ref, which is binded to link, and when I try to change color (ref.style.color = 'red'), I see a error. Because ref which is binded to nuxt-link is Object, and it hasn't style property. I know that I can use the tag <a></a>, but does someone has ideas how can i make it with nuxt-link?
More info:
I have a link
<nuxt-link
ref="card"
#mousemove.native="move"
#mouseleave.native="leave"
#mouseover.native="over">
Click
</nuxt-link>
In my function i want to change link position, useng transform.
move () {
const card = this.$refs.card
card.style.transform = `perspective(500px)`
}
End i get this message in console
TypeError: Cannot set properties of undefined (setting 'transform')
By selecting nuxt-link using $refs will only return Vue Component instead of node element due to nuxt-link is a component in Nuxt.js.
The correct way to selecting node element is using $el.
Answer referred from here.
Example:
const card = this.$refs.card.$el
card.style.transform = `perspective(500px)`
To be mentioned, I'm not sure what you trying to achieve but assuming you want to modify the style of an element in Vue way, you are supposed to use :style="theElementStyles" then only you update the element style with this.theElementStyles = { transform: 'perspective(500px)' }.
More details about inline style binding can check on Vue documentation.

SVG react component grabbing element by id

I have a SVG as a react component called AdultDog. My plan is to make all the tags in this react component that dont contain a certain number in the ID field disappear so that only tags with an id that contains a number are shown. i.e tags that have an ID 402 in it are shown. Ive tried to use document.querySelectorAll(":not([id^='402'])"); but this has two problems.
document.querySelectorAll grabs the whole html page not the AdultDog component, so how can i make it only select AdultDog?
with document.querySelectorAll(":not([id^='402'])"); it only selects ids called '402' but i want ids that have other words in it. i.e 402-tooth and 402-recede
import {ReactComponent as AdultDog} from '../../images/dog-dental-chart-with-treatments_v6.svg';
function DisplayTooth(props) {
const navigate = useNavigate();
console.log(props.toothnumber, 'Display tooth')
useEffect(() => {
var elements = document.querySelectorAll(":not([id^='tooth-402-GH-02'])");
console.log('elements', elements)
}, [props.toothnumber])
return (<div>
<div className='tooth-box'>
<AdultDog></AdultDog>
</div>
</div>
);
}
export default DisplayTooth;
This is quite a lot so any help would be appreciated! i cant find much documentation on SVGs as is.
Typically, you'd be creating all the <AdultDog> components, e.g. {dogs.map(dog => <AdultDogs key={dog.id} dog={dog}/>)} and you could just add a filter e.g. dogs.filter(your filter logic here).map() to drop some of the dogs.
Another approach is to add a class to some elements so you can toggle it on/off.

Using Vuesax Sidebar component with a spa and am looking to auto detect page and set active property

I am using vuesax sidebar component and don't know how to updated the computed property getActive
I am on laravel 5.7 in a vue spa and the active class if dedicated by the computed property and it changes when you click on each link but not by what page you are on. I have tried using a vue router link to and manually set the class with the class-active property that is used for router links
<vs-sidebar-item to="/dashboard" index="1" icon="menu">
Dashboard
</vs-sidebar-item>
<vs-sidebar-item to="/orders" index="2" icon="all_inbox" >
Orders
</vs-sidebar-item>
https://i.gyazo.com/0053e00288c63e5c1eb1c77500d1a053.png
Right now if you click on the repective link it will change the active property but if you were to go to the url bar and change your page that way it will not be reflected in the navbar.
I fixed this by adding some custom logic to the afterEach function within the Vue Router.
router.afterEach((to,from) => {
// Clear all buttons
const btns = document.querySelectorAll('.vs-sidebar-item-active');
btns.forEach( el => {
el.classList.remove('vs-sidebar-item-active')
});
// Highlight correct button
var item = document.querySelector("div.page-" + to.name);
if (item) {
item.classList.add('vs-sidebar-item-active');
}
});
You need to add the appropriate class names to the vs-sidebar-items. Here I've got classes of page-*** to match the name of the route.

Need to Generate React Router's Link Component to HTML string or Alternative

I am using the visjs.org javascript Timeline library. You can provide the timeline with an array of objects which represent events on the timeline. Each event has a content property which can be assigned a string or HTML. I am wanting to provide anchor tags to this property.
I am using react-router and wanting to provide the HTML generated by react-router's component for my anchor tags (currently I am just creating static HTML Item 1 which is a react-router route).
In my limited view, it appears that I need something similar to how ReactDom's renderToString function would work to generate the HTML string for this property.
Originally, I had a simple Timeline Container that passed the timeline event objects to a timeline component:
return (
<div>
<Timeline timelineItems={ timelineItems }/>
</div>
);
and a simple Timeline Component that would utilize the vis.js timeline library to bind to a DOM element:
componentDidMount() {
const { timelineItems } = this.props;
this.timeline = this.createTimeline(timelineItems);
}
render() {
return (
<div id = "timeline"> </div>
);
}
createTimeline(items) {
var container = document.getElementById("timeline");
var data = new vis.DataSet(items);
var options = {
width: '100%',
editable: true
};
return new vis.Timeline(container, data, null, options);
}
But what I would like to do in the Timeline Container would be something like this where I pass each event item to an TimelineItem component:
<div>
<Timeline timelineItems={ timelineItems.map((item) => {
let content = <TimelineItemComponent item={item}/>;
return Object.assign({}, item, {content});
}) }/>
</div>
and the a TimelineItem Component returning the <link>:
class TimelineItemComponent extends React.Component{
render() {
const { item } = this.props;
<div>
<Link to={`timeline/${item.id}`}>{`The #${item.id}`}</Link>
</div>
}
}
OR forgo the additional TimelineItemComponent and just assign the <Link to={timeline/${item.id}}>{The #${item.id}}</Link> to the content property.
But obviously the problem is that these generate objects and the content property needs HTML (again - like how ReactDom.renderToString works server side).
Any thoughts how I can do that?
NOTE: This is a universal app, so the original version is being rendered server side.
UDPATE:
If I use a standard anchor link that retains a dynamically created href="timeline/1" then it will cause the page to be completely rendered as well as a concatenation of the URL path for every link clicked.
For example, if selecting link with 'timeline/1' will update the URL path to /timeline/1 as expected. But selecting another item on the list will update the path to /timeline/timeline/2
I want it to behave just as if I had added a to the page which won't re-render the page.

Categories