In my Vue.js application I want to have some global functions. For example a callApi() function which I can call every time I need access to my data.
What is the best way to include these functions so I can access it in all my components?
Should I create a file functions.js and include it in my main.js?
Should I create a Mixin and include it in my main.js?
Is there a better option?
I have a file with function like a func.js
like below
export const func = {
functionName: (data) => {
return something
}
}
In main.js add 2 string
import {func} from './func.js'
Vue.prototype.$func = func
and you can use from all components if in script tag like below
this.$func.functionName(somedata)
or if template tag like
$func.functionName(somedata)
Your best bet would be a Plugin, which lets you add features to the global vue system.
[from the vuejs Docs]
MyPlugin.install = function (Vue, options) {
// 1. add global method or property
Vue.myGlobalMethod = ...
// 2. add a global asset
Vue.directive('my-directive', {})
// 3. add an instance method
Vue.prototype.$myMethod = ...
}
Then you would just add
Vue.use(MyPlugin)
in your code before calling your function.
Vue.myGlobalMethod(parameters);
or in your case
Vue.callApi(parameters);
Mixins can be registered globally too. https://v2.vuejs.org/v2/guide/mixins.html#Global-Mixin
Related
I want to create a dynamically named variable so that I can use it as a module. I am using eval() to do it, but for some reason it's not working as expected and claiming that the constant I created inside of it doesn't exist.
I have a main folder with this structure:
main
|- commands
|- |- testmod.js
|- test.js
Testmod.js has a simple function export inside of it that logs something to console when run:
function cmd() {
console.log('it worked :)');
}
module.exports = { cmd };
And in test.js, I want to try importing it dynamically:
const foo = 'testmodule';
eval(`const ${foo} = require('./commands/testmod.js');`);
eval(`${foo}.cmd();`)
However, it runs with an error, ReferenceError: testmodule is not defined, and I don't know why.
Expected:
1. define a variable named foo
2. evaluate a string that requires contents of another js file, and name that import as the contents of variable foo
3. evaluate this: a module with name of variable foo and then run the command 'cmd()' inside of it.
expected output: it worked :)
Should I try to find a different method of dynamically naming variables? I'm 99% sure that this method of doing things is unstable and unintended, but if I could get it to work somehow it would be great.
Alright, so my solution was to create an Object, then assign stuff to it. This way, there aren't any new variables and its just an object that can be called later. Thanks Emiel.
const foo = 'testmodule';
let bar = {
foo: require('./commands/testmod.js'),
};
bar.foo.cmd();
In the following example, simply putting module.exports = {save} on the jsFileName.js file functions is not an option here, due to limitations on my codebase. Is this possible to access the function from the export, inside of callFunctionFromAboveFile.js shown below? See the below example of how I'd like to access that function. I've searched all the other answers to questions similar but they all mention using the exports differently as I stated in my first line above.
If there is a way to access it as it is shown, please share your answer or details as to why it's not possible. Also, other ways to handle this would be helpful but I can't change the class up much given the limitation to the codebase.
jsFileName.js
module.exports = function (JsFileName) {
JsFileName.save = function (stuff) {}
}
callFunctionFromAboveFile.js
const JsFileName = require('jsFileName');
// TODO I'm not sure how this would call the save() w/out using exports differently.
// TODO I have to use exports as I've posted it in jsFileName.js
The default export of jsFileName.js is a function that adds functions to its parameter JsFileName.
Apparently, you can pass any object which is then modified to act as the module's exports.
That means: Pass any object you want to have the modules' functionality. Note that the object is not returned, so you have to keep the reference to it yourself.
// callFunctionFromAboveFile.js
const JsFileName = {};
require("jsFileName") // Get default export (the function)
(JsFileName); // Call with any object you want to "enhance"
JsFileName.save(/*...*/);
I need to use the functions of a javaScript file in another javaScript file, but I do not have an HTML linking the 2, how to share it?
const {Builder} = require('selenium-webdriver')
var chrome = new Builder().forBrowser('firefox').build()
login(chrome);
this is my code main and i need get this other method to other JavaScript File.
function login(chrome, user, senha){
chrome.get('https://testerbeta.crm2.dynamics.com/main.aspx');
}
now the code is small, but the software that I have to test is great and I need to separate the methods in different javascripts files
I think what you're looking for are import and export, added in ES6.
Basically, in the file you want to get your functions from, just add export keyword before function declarement, just like that:
export function foo() {
return bar;
}
Then, in the file you want to inject your function in, you add this at the beginning of the file:
import { foo } from 'path/to/your/file_with_function_to_export.js'
More about that you can read here.
My case is that I need to require a module named Router in my index file meanwhile assign value to a variable of the module.
I have figured out several ways to achieve it. However, as a beginner, I want to know which one is the best practice or design and why cannot use the others.
Method 1 - export a setter & keep variable as 'private'
router.js
var handler;
exports.setHandler=function(h){handler=h};
exports.route=function(){console.log(handler)}
index.js
var router=require('./router');
router.setHanlder('test');
router.route();
Method 2 - let variable be 'public' and use 'this' to refer
router.js
exports.handler={}; //not necessary
exports.route=function(){console.log(this.handler)}
index.js
var router=require('./router');
router.hanlder='test';
router.route();
Method 3 - export a factory function to receive value as a parameter
router.js
module.exports=function(handler){
return {route:function(){console.log(return handler)}};
}
index.js
var router=require('./router')('test');
router.route();
Which one above should I use? Any other methods suggested?
I would suggest method 3, it being a callback;non-blocking code. Also, it is close to what seems natural to me!
I like to do it this way - I recommend trying to stay away from handlers like that with modules because it is a complexity trap that will catch you one day, that is, unless you need them =).
module.exports = function( options ) {
// set options
// based on options set vars and functions on this
if (options.test === true) this.route = function() {//....}
else this.route = function() {//......}
}
then in the using file
var Router = require('router.js');
var router = new Router({/* options */});
router.route();
It's possible to use method 2 as well. If you are using aws lambda, you will see that they used method 2 to export the function handler.
I have a global variable defined in my main template, which I use to store information bits from the back end, such as the environment context path. I can't move that variable inside a service.
How can I expose that variable to Karma when I run the unit tests?
You either declare that global variable within your test file:
var global = "something";
describe('Your test suit', function() {
...
});
or add a Javascript file where it's defined to your karma.conf.js file:
// list of files / patterns to load in the browser
files: [
...,
'file-containing-the-global-variable.js'
],
If you are coming from Angular 2+ the only way I found that works is to create the variable or object globally using window:
Google Recapthca Loaded from a script:
<script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit" async defer></script>
In this example a call to the google Recaptcha will create a global variable called grecaptcha.
In our component we decide to render a new Google Recaptcha. Of course since we do not declare grecaptcha we need to use declare var to say hey I promise it is declared somewhere:
declare var grecaptcha;
private CreateGoogleCaptcha() {
grecaptcha.render('recaptcha', {
sitekey: this.siteKey,
callback: this.GoogleCaptchaCallback,
badge: 'inline'
});
}
private GoogleCaptchaCallback(token) {
// Handle Callback Logic
}
Now that our function works we decide to run a test but of course we would like to mock our grecaptcha as we don't have control over it.
So we name our global variable we would like to create and add the functions we would like:
beforeEach(() => {
fixture = TestBed.createComponent(GoogleRecaptchaComponent);
component = fixture.componentInstance;
window['grecaptcha'] = {
render() {
console.log('mocked global variable and function');
}
}
}
Update:
Creating the global variable in the beforeEach is fine but what about when it has some sort of callback function such as above that calls a function from your component? Easy enough we just move the login to our test and in our mock we set it to our components function:
it('should ', () => {
window['grecaptcha'] = {
render: function() { GoogleRecaptchaComponent['GoogleCaptchaCallback']('token'); }
};
spyOn<any>(GoogleRecaptchaComponent, 'GoogleCaptchaCallback');
GoogleRecaptchaComponent['CreateGoogleCaptcha']();
expect(GoogleRecaptchaComponent['GoogleCaptchaCallback']).toHaveBeenCalled();
});
Note: spyOn<any>: The <any> is used so we can refence without error the function because it is private, otherwise we will get a typescript error;
The first solution didn't work for me in Angular 2.1.x. It simply would not recognize the variable in my imported service. What I had to do was put my environment variable in my karma-test-shim.js file and remove var so it would be globally available.
Mine looks like this:
Error.stackTraceLimit = Infinity;
require('core-js/es6');
require('reflect-metadata');
require('zone.js/dist/zone');
require('zone.js/dist/long-stack-trace-zone');
require('zone.js/dist/proxy'),
require('zone.js/dist/sync-test'),
require('zone.js/dist/jasmine-patch');
require('zone.js/dist/async-test');
require('zone.js/dist/fake-async-test');
// Add environment variables here so that tests will inject them in source code
API_URL = 'http://localhost:8080/api/';
var appContext = require.context('../src', true, /\.spec\.ts/);
appContext.keys().forEach(appContext);
var testing = require('#angular/core/testing');
var browser = require('#angular/platform-browser-dynamic/testing');
testing.TestBed.initTestEnvironment(
browser.BrowserDynamicTestingModule,
browser.platformBrowserDynamicTesting()
);
I was trying to integrate angular v13 with google-place-autocomplete without any npm package, just vanilla google-place-autocomplete. When i tried to test, karma said: '"google" is not defined'.
So i found the awswers above, and it worked for me like this:
Created a file in root directory (in my case, i named: google-place.js)
Added a mock object with the instructions that is used in component.
class Autocomplete {
constructor(input, options) {
const addListener = (eventName, callback) => { }
const getPlace = () => { }
return { addListener, getPlace }
}
}
var google = {
maps: {
places: {
Autocomplete: Autocomplete
}
}
};
Added in karma.conf.js a property called "files", and end up like this:
files: [
"./google-place.js"
]
And it was not necessary to add a declare var google in every spec. Is global now.