I'm pretty new to Vue/JS and am currently trying to build an app.
I currently have a component set up as follows (there's obviously more to it but hopefully the below will help with my question):
<template>...</template>
<script>
export default {
data() {
return {...}
},
methods: {
method1() {
const Class1 = new Class1;
},
method2() {
...
}
}
}
class Class1 {}
class Class2 {
...want to use above method2() here
}
</script>
<style>...</style>
Now I am able to use Class1 from inside method1() but is there any way I can easily call method2() from Class2?
Many thanks in advance.
Class with method foo as an example
export default class Class1 {
function foo() {};
}
Calling a function from another class could be like this:
import Class1 from './class1';
<template>...</template>
<script>
export default {
data() {
return {
methods: {
method1() {
const x = new Class1;
return x.foo()
}
}
}
}
}
</script>
Posting a better elaborated answer:
In vue.js you can use an Event Bus method to comunicate with unrelated components. Basically is a component that is used to pass an event to other components. It can be very useful in this case.
event-bus.js:
import Vue from 'vue';
export const EventBus = new Vue();
Component that will emit the event:
<template>
<div #click="functionToEmitTheEvent()"></div>
</template>
<script>
// Import the EventBus we just created.
import { EventBus } from './event-bus.js';
export default {
data() {
return {
clickCount: 0
}
},
methods: {
functionToEmitTheEvent() {
this.clickCount++;
// Send the event on a channel (customClick) with a payload (the click count.)
EventBus.$emit('customClick', this.clickCount);
}
}
}
</script>
Script that will listen the event:
// Import the EventBus.
import { EventBus } from './event-bus.js';
// Listen for the customClick event and its payload.
EventBus.$on('customClick', clickCount => {
console.log(`Oh, that's nice. It's gotten ${clickCount} clicks! :)`)
});
All code written was copied from here: https://alligator.io/vuejs/global-event-bus/
I hope it helped!
Create Class1 and Class2 outside of your component as a ES6 class and export them. Then import the classes to your component. So something like this:
Class 1
export default class Class1 {
...
...
}
Class 2
export default class Class2 {
...
...
}
And then import those classes to your Vue component
<template>...</template>
<script>
import Class1 from './class1';
import Class2 from './class2';
export default {
...
data() {
return {
// your data
}
},
methods: {
method1() {
const Class1 = new Class1();
},
method2() {
const Class2 = new Class2();
..
return 'something';
},
method3() {
// call method 2
method2();
....
}
...
....
Thanks for the answers all - think my original question must not have been clear but I've managed to find the solution (stumbled across just now, after spending hours last night searching!) Here it is for anyone else wondering.
To make use of a method outside of a component, register the Vue instance globally when created (e.g. in main.js):
app = new Vue({
...
})
window.App = app;
And then any methods can be called by referencing the window.App e.g.
App.method2();
Full working code:
<template>...</template>
<script>
export default {
data() {
return {...}
},
methods: {
method1() {
const Class1 = new Class1;
},
method2() {
...
}
}
}
class Class1 {}
class Class2 {
App.method2();
}
</script>
<style>...</style>
Related
I write UI tests using PageObject Pattern (NodeJS + Webdriverio) and I have a base class (BasePage), a page class(MyPage), a popup component class(PopupComponentClass) with multipurpose behaviour, a popup class with a specific implementation(SpecificPopupComponentClass). I need to extend SpecificPopupComponentClass from PopupComponentClass.
page.js:
export default class BasePage {
get BASE_URL() {
return "https://url.com";
};
...some methods...
}
my.page.js:
import BasePage from "../page";
class MyPage extends BasePage {
constructor() {
super();
};
get URL() { return `${this.BASE_URL}/some/path` };
get title() { return $("h1") };
orderRandomTariff() {
...some actions...
};
}
export default new MyPage ();
popup.component.page.js:
import BasePage from "../pages/page";
class PopupComponent extends BasePage{
constructor() {
super();
};
get title() { return $("h1") };
}
export default new PopupComponent();
specific.popup.component.js:
import PopupComponent from "./popupFragment";
class SpecificPopupComponent extends PopupComponent {
constructor() {
super();
};
get popupStreetInput() { return $(".//div[#class='checkAddress']//*[./*[contains(text(),'Street')]]//input") };
fillStreet(street) {
...some actions with this.popupStreetInput...
};
}
export default new SpecificPopupComponent();
...and trying to use it in test.js:
import MyPage from "../../../../pages/my.page";
import SpecificPopupComponent from "../../../../fragments/specific.popup.component";
const myPage= MyPage ;
const popup = SpecificPopupComponent ;
describe("Test", () => {
before(() => {
myPage.open();
});
it("Check", () => {
popup.fillStreet("Street");
});
});
but I'm getting an error: "TypeError: Class extends vlaue #PopupComponent is not a constructor or null".
I suspect this is due to circular dependencies, but I can't understand, what I need to do to fix that.
It seems the issue here is how you're exporting the base class. You're instantiating it instead of just exporting the class you'll inherit from. It should be like this:
export default class PopupComponent extends BasePage {
constructor() {
super();
};
get title() { return $("h1") };
}
And then create the instance when you're going to use it
var myPage = new MyPage()
var popup = new SpecificPopupComponent()
myPage.open()
popup.fillStreet('street')
What you're doing there is equivalent to doing this:
class SpecificPopupComponent extends new PopupComponent() {
// ... what am I? 🤔
}
I suspect this is due to circular dependencies
You can validate or reject your suspects by copying all the code into the test file in the correct order without using imports. But I don't think it's an circular dependency
I created this Plunker to remove the usage of imports and prove this.
I am trying to run the code below, but it is not working. I think this is a scope problem, but I'm not sure how to fix this.
import CommonController from './CommonController';
import CategoryService from './category/Service.js';
class CategoryController extends CommonController {
constructor() {
super(CategoryService);
}
}
export default new CategoryController();
// ===================CommonController==========================
export default class CommonController {
constructor(service) {
this.service = service;
}
async get () {
console.log(this); // it returns undefined
}
}
// ===================CategoryService==========================
import Category from './Category'
import dto from './dto'
class CategoryService extends CommonService {
constructor() {
super(Category, dto);
}
}
export default new CategoryService();
// ===================CommonService==========================
export default class CommonService {
constructor(model, dto) {
this.model = model;
this.dto = dto;
}
}
if a run:
import CategoryController from './CategoryController';
CategoryController.get()
the console.log in CommonController get function will print undefined
Am I doing something wrong?
The issue is that you are calling get() on the class itself, instead of calling it on an instance of the class. Try creating an instance of CategoryController, like so:
cc = new CategoryController();
Then, you should be able to call:
cc.get();
Demo in the code below (same as yours, just slightly modified to reflect my point).
// ===================CommonController==========================
class CommonController {
constructor(service) {
this.service = service;
}
async get () {
console.log(this); // it returns undefined
}
}
// ===================CommonService==========================
class CommonService {
constructor(model, dto) {
this.model = model;
this.dto = dto;
}
}
// ===================CategoryService==========================
class CategoryService extends CommonService {
constructor() {
super(Category, dto);
}
}
class CategoryController extends CommonController {
constructor() {
super(CategoryService);
}
}
cs = new CategoryController();
cs.get();
I have a component my-parent. In this component, I use a child component my-child and import an external class MyClass with an own function exportedFunction. I tried to use this solution: VueJS accessing externaly imported method in vue component
Basiclly, I use mounted and the name of the function from the imported class. In methods I defined a new method, which calls the mounted one from the imported class. Than I pass the created method as property to my child, where I try to call the function with a #click and pass the parameter there.
Here is my code so far:
my-parent template:
<template>
<my-child :exportedFunction="callFunction"></my-child>
</template>
<script>
import MyClass from './MyClass';
export default {
mounted() {
exportedFunction()
},
methods: {
callFunction() {
exportedFunction()
}
}
}
</script>
my-child template:
<template>
<button #click="exportedFunction('hello world!')">Click me!</button>
</template>
<script>
export default {
props: ['exportedFunction']
}
</script>
MyClass code:
export default class MyClass {
exportedClass(parameter) {
console.log(parameter) // expected 'hello world' from child
}
}
Hope for some help!
I would ditch your MyClass component and instead have:
my-parent
<template>
<my-child :triggerEvent="callFunction"></my-child>
</template>
<script>
export default {
methods: {
callFunction() {
console.log('hello');
}
}
}
</script>
my-child
<template>
<button #click="$emit('triggerEvent')">Click me!</button>
</template>
As you want to use MyClass in your example you can keep it as is and have my-parent as:
<template>
<my-child :triggerEvent="callFunction"/>
</template>
<script>
import MyChild from "./MyChild";
import MyClass from "./MyClass.js";
export default {
components: {
MyChild
},
data() {
return {
myCls: new MyClass()
};
},
mounted() {
this.myCls.exportedClass("hello my class");
},
methods: {
callFunction() {
console.log("hello");
}
}
};
</script>
In my app.js inside the app class there is a variable that I want to export to another module. I tried many options, but unfortunately, the understanding of how to do it correctly did not come. Tell me, please, how to do it right? Export default is already in use in my class
export class App extends Component {
static propTypes = {
//somecode
};
constructor(...args: any): void {
super(...args);
}
render() {
// console.log('app render start');
const test = true;
return (
//somecode
);
}
componentDidMount() {
//somecode
}
componentDidUpdate(prevProps): void {
//somecode
}
}
In the example above, i need to export variable 'test'
I would be grateful for any help.
Assuming your intention with test is to define something like a "project constant" (which is what I gather, from your use of the const keyword), then you could simply declare test outside of the App class, and then export it from the module in the same way you are exporting the class:
App.js
/*
Export test variable
*/
export const test = true;
/*
Export your App class
*/
export class App extends Component {
static propTypes = {
//somecode
};
constructor(...args: any): void {
super(...args);
}
render() {
/*
Access test variable in "global scope" inside render method
*/
console.log(`test is: ${ test }`);
// console.log('app render start');
// const test = true;
return (
//somecode
);
}
componentDidMount() {
//somecode
}
componentDidUpdate(prevProps): void {
//somecode
}
}
And then, from another module in your project you could access test like so:
MyModule.js
import { App, test, } from 'path/to/App';
console.log(`test is: ${ test }`);
You could make test a static property on the App class, then just reference it from the App class since that is exported.
class Test extends React.Component {
static test = true;
}
console.info(Test.test);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
import Test from 'test';
console.info(Test.test);
This is an issue I run into fairly frequently, and I was hoping to discover the correct way to handle it.
So I have a setup like this:
parent.js:
export default {
x: 1
}
a.js:
import parent from 'parent.js'
export default parent.extend(a, { title: 'a' })
b.js:
import parent from 'parent.js'
export default parent.extend(b, { title: 'b' })
Cool, now I've got some children.
But I decide I would like to have a function in parent.js that checks if an object is an instance of a or b.
So I might do this:
parent.js:
import a from 'a'
import b from 'b'
export default {
x: 1,
checkType (obj) {
if (obj instanceof a) {
return 'a'
} else if (obj instanceof b) {
return 'b'
}
}
}
Well now that's a circular dependency. Is there an elegant way to handle this?
Having logic in the parent class that is aware of the subclasses is a serious anti-pattern. Instead, add methods in the subclasses that return the type. for instance, in a.js:
import parent from 'parent.js';
export default parent.extend(a, { title: 'a', checkObj() { return 'a'; }});
If the desired return from checkObj is always the value of the title property, then of course just:
// parent.js
export default {
x: 1,
checkObj() { return this.title; }
}
I don't know exactly what extend is doing here. I'm assuming it is some kind of subclassing mechanism.
In general, circular import dependencies, although there are ways to deal with them when truly necessary, are the universe trying to tell you that there is something wrong with the way you've structured your code.
If you're able to use es6 classes, then you can take advantage of the super() call in the constructor. I'll often do something like this:
Parent.js
export default class {
constructor(options, child) {
this.child = child;
this.x = 1;
}
checkType() {
return this.child;
}
}
A.js
import Parent from './Parent';
export default class extends Parent {
constructor(options) {
super(options, 'a');
}
}
B.js
import Parent from './Parent';
export default class extends Parent {
constructor(options) {
super(options, 'b');
}
}
If you don't want to use classes, maybe want a more FP style. You could make parent a function:
parent.js
export default function(child) {
return {
x: 1,
checkType (obj) {
return child;
}
extend (something) {
// assuming the returns something as you said
}
}
}
a.js
import parent from 'parent.js'
export default parent('a').extend(a, { title: 'a' })
b.js
import parent from 'parent.js'
export default parent('b').extend(b, { title: 'b' })