Accessing properties/methods of a Vuejs component globally - vuejs2

I want to create a custom component and to use it like
<div id="app">
<router-view />
<my-custom-loader />
</div>
My component has some methods which I want to use globally anywhere like
this.$loader.show();
this.$loader.hide();
I can create the component but not sure how to inject its method/properties so that it's available everywhere.

Component create a encapsulated scope in vuejs.
AFAIK you should not be doing this as I feel this to be more like a workaround that a perfect vuejs way of doing this.
You can setup a ref on the <my-custom-loader> component.
<div id="app">
<router-view />
<my-custom-loader ref="loader"/>
</div>
Since the component looks like the child of root vue instance mounted on #app you can use it to acess $refs
var vm = new Vue({
el: '#app'
});
//my-custom-loader component's instance
var loader = vm.$rers.loader;
Then you can setup this loader which is the my-custom-loader component's instance on the Vue.prototype. This now allows you to acess $loader in any component using this.$loader
Vue.prototype.$loader = loader;
Now you can acess its methods using
this.$loader.hide();
this.$loader.show();
keep in mind the warning of using refs as mentioned in the docs
$refs are only populated after the component has been rendered, and it is not reactive. It is only meant as an escape hatch for direct child manipulation - you should avoid using $refs in templates or computed properties.
As for me I recommend you use custom events or register a global event bus or use vuex if your app is very big and has complex state management

Related

Difference between router-link and RouterLink in Vue

When using Vue Router, I found that I could use <router-link> as well as RouterLink to achieve the same result, i.e. navigate between different routes.
Similarly, there's <router-view> as well as RouterView component.
Following two code examples give me the same result:
With <router-link> and <router-view>:
<template>
<router-link to="/">Home</router-link>
<router-link to="/about">About</router-link>
<hr />
<router-view></router-view>
</template>
With <RouterLink> and <RouterView>:
<script setup>
import { RouterLink, RouterView } from "vue-router";
</script>
<template>
<RouterLink to="/">Home</RouterLink>
<RouterLink to="/about">About</RouterLink>
<hr />
<RouterView />
</template>
Question
What is the difference between <router-link> and RouterLink (and between <router-view> and RouterView?)
I couldn't find anything on Vue Router docs. Searching for RouterView or RouterLink doesn't show any results related to them. Docs only mention <router-link> and <router-view>.
P.S. Scaffolding a new Vue project with npm init vue#latest command uses RouterLink and RouterView components instead of router-link and router-view.
It's the same components, just with different cases, in vue it's recommended to use the PascalCase syntax as mentioned here :
In SFCs, it's recommended to use PascalCase tag names for child components to differentiate from native HTML elements. Although native HTML tag names are case-insensitive, Vue SFC is a compiled format so we are able to use case-sensitive tag names in it. We are also able to use /> to close a tag.
They are the same thing. Any component can be used either by writing its name as PascalCase or kebab-case.
One is the component name and one is the vue class. I don't think there is a difference. If you would create your own component e.g. MyComponent.vue, you can also use <MyComponent> or <my-component>

Make Vue not throw error if component is not defined

I'm developing a component which have an optional child component.
<template>
<div>
<child-component :propA="valueOfA"/> <!-- this child will certainly appear -->
<optional-child-component :propB="valueOfB" /> <!-- this child may not appear -->
</div>
</template>
This is for a library I'm developing. optional-child-component comes from a 3rd-party library that the users of my library may want to use. I won't force them to install 3rd-party libraries if they don't want. The problem is that, currently, if the 3rd-party library is not installed then Vue will throw an error saying that optional-child-component is not defined.
How do I include an optional component in my code given that this component may not be defined/registered?
Not sure whether this is the best way but you could maybe check $options.components to see which components are registered.
In the example below there are 3 child components. One of them is registered globally, one is registered locally and the third isn't registered at all. That third component won't be rendered.
Vue.component('comp-a', { template: `<div>a</div>` })
new Vue({
el: '#app',
components: {
'comp-b': {
template: `<div>b</div>`
}
}
})
<script src="https://unpkg.com/vue#2.6.11/dist/vue.js"></script>
<div id="app">
<comp-a v-if="$options.components['comp-a']"></comp-a>
<comp-b v-if="$options.components['comp-b']"></comp-b>
<comp-c v-if="$options.components['comp-c']"></comp-c>
</div>
There may be a complication here around case, e.g. kebab-case vs PascalCase, but I doubt that would be an insurmountable obstacle to getting this to work.

how can i pass registered vue component as prop to a component

Need to pass component to child component, using props or you have better way to solve this problem
I registered component needed to pass globally or just registered this component locally. But these solutions can't solve my problem.
Here is my code to register component needed to pass locally:
a.vue html
<dropdown :icon="UserIcon"></dropdown>
a.vue js
components: {'dropdown', Dropdown, 'icon-user': UserIcon}
dropdown.vue html
<div class="dropdown"><icon></icon></div>
dropdown.vue js
props: ['icon']
UserIcon.vue
<i class="user-icon"></i>
the browser reminds me that icon is unknown custom element. It seems like vue does not support this way to use component, doesn't it?
I solve this problem using slot.
and there is another question comes...
a.vue
<dropdown><template v-slot:icon><icon-user></icon-user></template></dropdown>
dropdown.vue
<div class="dropdown"><slot name="icon"></slot></div>
But icon-user component didn't show...
and I did this work, cuz I remove the name attribute of slot.
a.vue
<dropdown><template><icon-user></icon-user></template></dropdown>
dropdown.vue
<div class="dropdown"><slot></slot></div>

Correct way to use Vue component mutiple times in one page

I am trying to create a simple 24 hour time input that I can use across multiple browsers.
In the past I have used Vue to create components which are used once on a page, and I attach them to an id as follows:
<script>
$(function () {
new Vue({
el: "#my-time-element"
});
});
</script>
But what happens when I want to use it multiple times in one page? I tried attaching it using a class definition (attach to .my-element) but it only renders for the first matching element. (The component is registered globally.)
Perhaps I am supposed to wrap the page in a single Vue component, then embed my time component in its template? Perhaps I need to make a jQuery collection of all .my-element elements, then cycle through and instantiate Vue for each one? What is the correct way to approach this?
Perhaps I am supposed to wrap the page in a single Vue component, then embed my time component in its template?
That is definitely the easiest way to do it.
You do not have to change so many things compared to your regular HTML page: simply make sure to provide an ID to one of your root container, then use your Custom Component tag anywhere within and as many times you like.
You just need to prepare Vue by globally declaring your custom component first, with Vue.component:
Vue.component('my-component', {
template: '#my-component',
});
new Vue({
el: '#app',
});
<script src="https://unpkg.com/vue#2"></script>
<div id="app">
<h1>Hello World</h1>
<my-component>Component instance 1</my-component>
<my-component>Component instance 2</my-component>
</div>
<template id="my-component">
<div style="border: 1px solid black">
<h2>My component</h2>
<slot></slot>
</div>
</template>
Perhaps I need to make a jQuery collection of all .my-element elements, then cycle through and instantiate Vue for each one?
That is also a possible solution, but probably defeats the Vue spirit…

Aurelia custom element without outer node

Is it possible to let Aurelia render a custom element without the capsulating component node? Or replace the custom-element node with its content?
Example:
app.html
<template>
<require from = "./components/custom-component.html"></require>
<custom-component></custom-component>
</template>
app.ts
export class App {
}
custom-component.html
<template>
<p>This is some text from dynamic component...</p>
</template>
Result
Based on this example: Is it possible with aurelia to render the <p> element from the component as direct child of the <body>, so that there will be no custom-component-node?
Use the containerless attribute on your component.
example: https://gist.run/?id=8e57000c7b8423dc0246a7006d90ba79
you can also decorate your custom components with the containerless() decorator.
see: http://aurelia.io/hub.html#/doc/article/aurelia/framework/latest/cheat-sheet/9