Does "document.querySelectorAll" work in a nuxt plugin? - vuejs2

I'm using nuxt in my vue project and I have created a plugin in which I want to select all button tags with document.querySelectorAll('.v-btn') however it does not work and I think I can not use document.querySelectorAll because plugins run before instantiating the root Vue.js Application but not sure about this. on the other hand I use plugin to call this function which can be used in whole app. Is there any way to solve this problem?
here is my function. I want to select all buttons in whole app and add a class to all of them. the result of console.log(btn) is 'NodeList(0)'.
const changeTheFontSizeOfButtons = function () {
const btn = document.querySelectorAll('.v-btn');
console.log(btn);
for (const button of btn) {
button.classList.add('v-size--large');
}

Related

Vue.js 3 : Accessing a dynamically created component

I have a vue.js 3 application that needs to dynamically create components and access them.
The proper way to dynamically create them and injected them in the DOM seems to be th wrap them in an app using createApp, and this part works, when I call test() a new copy of the components appears at the bottom of the DOM.
Now I need to be able to get a reference to that component son I can call public (exposed) methods on it.
In my (actual) code below, what would allow me to get a reference to my component ?
import { createApp, h } from "vue";
import ConfirmModal from '#/views/components/ui/confirm-modal.vue';
function test()
{
let componentApp = createApp({
setup() {
return () => h(ConfirmModal, { title: "Fuck yeah!", type: "primary" });
}
});
const wrapper = document.createElement('div');
wrapper.setAttribute('id', 'confirm-modal-0');
componentApp.mount(wrapper);
document.body.appendChild(wrapper);
let _confirmModal: ConfirmModal = ???????????????????
_confirmModal.show();
}
EDIT : Here's my use-case: I have a helper function in a service which is used to confirm actions (like deletes) using a Modal dialog. This helper/service is pure TS, not a Vue component, but needs to instanciate the modal (which is a vue component), have it injected in the DOM and have its public methods callable (by my helper/service).
Right now, the only thing that works is to have a sungle copy of the modal component in my root layout and have to root layout foward the ref to my service, which can then use the component. But this isn't great because I need multiple instances of the dialog, and isn't good SOC to have to root layout handle a modal dialog.

How to activate / deactivate an Electron.js submenu from inside a Vue.js Component according to a specific Vuex state?

I can't find the solution to this anywhere.
I have this sample vue-vuex-electron app that I've created and I want to enable / disable some submenus of the app according to whether the vuex state 'isLogged' is true or false. I managed to apply that to the nav router-links (using v-if), but not yet to the menu items... 'cause I don't know how to access the actual Menu (already set and rendered at the main process).
For example, at my Home.vue, I'd like to import the Electron.Menu of the app and set the following:
created(){
if(this.$store.getters.isLogged){
mainMenu.getMenuItemById('login').enabled = false
mainMenu.getMenuItemById('logout').enabled = true
mainMenu.getMenuItemById('currentWeather').enabled = true
} else{
mainMenu.getMenuItemById('login').enabled = true
mainMenu.getMenuItemById('logout').enabled = false
mainMenu.getMenuItemById('currentWeather').enabled = false
}
}
But, when I try to import the Menu it's returned as undefined, not the menu already created and set to the app.
HOW CAN I HAVE ACCESS TO THE ACTUAL ELECTRON MENU FROM INSIDE A VUE INSTANCE IN ORDER TO CHANGE IT ?
The whole project is here:
https://github.com/danielpm1982/open-weather-client
Thanks in advance ! :D
Daniel Pinheirodanielpm1982.comBrazil
OK, nobody knew this one, so I managed to work around it myself... and I'm sharing the solution to help others.
I actually could not find a way to get or manage the Electron Menu at the renderer process, from within the Vue components, so I let it to be updated at the main process itself, where I have access to all Electron components easily.
ipcMain.on('setMenuToLoggedInState', (e:Event, isLogged:boolean) => {
const mainMenu: Menu = Menu.getApplicationMenu() as Menu
if(isLogged){
mainMenu.getMenuItemById('login').enabled = false
mainMenu.getMenuItemById('logout').enabled = true
mainMenu.getMenuItemById('currentWeather').enabled = true
} else{
mainMenu.getMenuItemById('login').enabled = true
mainMenu.getMenuItemById('logout').enabled = false
mainMenu.getMenuItemById('currentWeather').enabled = false
}
});
Then, at the renderer side, or at the Home.vue component view, I simply emmit an event to the main process to notify it when the Vuex 'isLogged' state changes, that is, when I want it to update the Menu.
computed: {
...mapGetters(['isLogged'])
},
created(){
if(this.isLogged){
ipcRenderer.send('setMenuToLoggedInState', true)
} else{
ipcRenderer.send('setMenuToLoggedInState', false)
}
}
As, in the case of this app, both the Login as the Logout routes redirect to the Home View, the Home Vue component will always be able to check the 'isLogged' state at the Vuex store, on its creation, and notify the main process to update the Menu or subMenus according to that state.
I don't know if there's a better way for this, but it works this way.
I was avoiding to use ipcMain and ipcRenderer as much as I could, for not coupling the Vue components code with the Electron API, but in this case I had to use it.
Now, my Menu submenus are activated and deactivated according to the user login state, as well as the router-links of the nav bar are generated or not according to that same state.
Thanks to all those who might have tried to answer that.
The whole project is here: https://github.com/danielpm1982/open-weather-client
Daniel Pinheiro
danielpm1982.com
Brazil

Quasar CLI VUE instance

Help me solve with the problem please.
I am using jquery and jquery-ui to implement drag & drop in QASAR CLI.
But I ran into the fact that I cannot access the vue instance from jquery function events, since "this" no longer belongs to Vue, but refers to the selector element. Tell me how I can refer directly to the vue instance as it could be done in cdn version. There you could just give the name app = new Vue ... And then use it as app.data.variable
I believe this is more javascript question, than quasar/vue/jquery. You can easily set value of this by a bind function
let someFunction = function () {
console.log(this);
}
someFunction();
const obj = { 'test': 123 };
someFunction = someFunction.bind(obj);
someFunction();
Same thing applies to jquery function handlers. I guess you could pass your instance instead of obj
$(window).ready(function () {
console.log(this);
}.bind(obj));

Vue multiples components

I'm doing a project with ElementUI Tabs (just HTML and JS files, no .vue files) and I want to open a new Tab, and add html inside, like I've always used to do in Jquery and SemanticUI, for example, the user clicks the menu called "Person" and the Person View (a Vue component) opens in the tab (id = "tab1") to add a new person register, and if the user clicks again the "Person" menu, another tab opens (id = "tab2") with the Person View.
First Question: Because the Vue Component has no "el:" selector, how can I tell to component (Person View) to open inside the "tab1", and another click to open inside the "tab2" ? There is any selector like "el" in Vue.component()?
Second Question: Using Vue instance ( new Vue ({options}) ), it works, because is possible to use the selector "el", but I've read before in some blogs, that is not good practice, because the app must have only one instance of Vue. Is correct add more than one Vue instance ( new Vue () ) as used to be done adding many Vue.component ({}) in the project?
Third Question: I've read before that Vue.component() is a Vue instance, and so would be correct to say that Vue.component() and Vue() is the same thing, but with different sintax ?
Question 1:
Actually, a component does have an el. Your template determines what el is.
For example, I created an inline template for my select2 that look like this:
<select2>
<select></select>
</select2>
Vue.componet("select2", {blah blah blah});
in this case el is the select box directly.
If I did:
<select2>
<div>
<select></select>
</div>
</select2>
the component el would be the div.
Question 2: what you heard from those blogs is nonsense, at least as far as Vue 2 is concerned (never worked with ver 1)
You, as a coder, determine what el is in your code so it is safe to use as a selector. I do it all of the time.
Vues cannot overlap but you can have as many on a page as makes sense. On one set of my tabs, each tab is completely different from each other and independent of each other so each has its own Vue instance. On another, each tab is the same so a made a single component and generated it inside each tab as part of the parent Vue instance.
question 3:
Think of Components as parts and the Vue instance as the whole containing the parts. I personally use components to reduce and compartmentalize code. For example, I have a DataTables component, a select2 component and a tab component, in all cases I have a number of each on each page. Then all I need to do is include them in my Vue instance definition.
After almost two weeks trying, I got it !
First i created an object that has a component structure in a JS file
(personview.js) that i load with requireJS, and pass as a parameter to a
method of Vue Instance called appVue:
appVue.addComponent(componentName,{name:"personview",template:"<div>html tags...</div>",methods:...});
In appVue i added the method:
var appVue=new Vue({
el:'#app',
data() {
return {
components: {},
instances: {}
}
},
methods: {
addComponent(componentName,componentBody){
this.$data.components[componentName]=Vue.component(componentName,Vue.extend(componentBody));
}
}
}
When the user clicks on menu, the method openViewByClickOnMenu is called
and executes:
methods: {
openViewByClickOnMenu(){
//id to identify the components and scripts to load
var componentName="personView"; //for this example i forced the name
//call a method that adds the new tab, and inside the tab adds
//<div id="divX"></div> and return the counter ever increased.
//X in id attribute is the number genereate by the counter
var ctTab=body.addTab({label:menuItem.label});
// will be used to identify an instance of compoment
var componentId=componentName+ctTab; //will be personView1, personView2, etc..
// will be used to identify the div where i want to show component
var divTabId="div"+ctTab;
//load the personview.js with component body
requirejs([componentName],function(){
//creates a new instance of component
app.$data.instances[componentId]=new app.$data.componentes[componentName];
//mounts the component in the div that i want
app.$data.instances[componentId].$mount("#"+divTabId);
});
}
I think the Vue team could add a method in Vue instance to add
components dinamically more easily, sometimes there's no need to
load all html and js files because the user has no acess/permissions
to see some views. And i miss a way to load html native, like
Angular does, because sometimes we need generate html from template engine
inside a SpringBoot for example.

How to close collapse on clicking on a button using vuejs and quasar?

I'm using <q-collapsible> tag for a collapse action. That is working fine. But I need to close the collapse by clicking some other button through Vue js only.
Since I'm using quasar it has some functionalities like open() and close() and I don't know how to implement it. So if possible someone helps me how to proceed.
This can be done easily since quasar provides this functionality out of the box.
First, reference your quasar component
<q-collapsible ref="myCollapsible">
...
</q-collapsible>
<button #click="toggleCollapsible">toggle collapsible</button>
Then, execute the needed method
methods: {
toggleCollapsible () {
this.$refs.myCollapsible.toggle()
}
}
This is for toggle, you can do the same with open and close.