Cleanest way to import/require a Vue.js directive? - javascript

I'm trying to organize my plugins into custom Vue Directives that could be a simple as:
Vue.directive('popout', {
bind() {
$(this.el).popOut();
}
});
And save these in separate files, to be imported in either the main JS file or the Vue(ify) components with something like:
require('./directives/popout.js');
I've tried a number of export default setups, but I can't seem to get it to work. What would be the cleanest (i.e. best-practice) way to do this?

I got the solution,below is the code
import Vue from 'vue';
export const global= {
bind(el, binding, vnode) {
console.log('you code');
}
};
this code goes in lets say directive/global.js file.
Then in you app.js or entry point file use this
import { global } from './directive/global.js';
Vue.directive('global', global);
first line will import the directive as we are using same name to only used global, second line to make you directive global. Hope it help.

Related

Laravel & Vuejs Integration - Vuejs mixins

I'm trying to create a mixin to handle my sweetalerts2 logic. Now, i've created a mixin named sweetAlerts.js inside a folder: assets/js/misins and i wrote the next block of code inside of it:
import swal from 'sweetalert2'
export default {
methods: {
$sAlert(data) {
swal(data)
},
$sToast(data) {
swal.mixin(data)
},
}
};
Then i've imported it on my app.js file like this:
import sweetAlerts from './mixins/sweetAlerts'
Vue.mixin(sweetAlerts)
The problem is that methods like this one doesn't work:
methods: {
launchAlert() {
this.$sAlert(data)
}
}
I know that sweetalerts2 works just fine because i've tested it inside my application. The main problem is that i can't create a mixin with all the alerts logic to implement it on any component i want.
Is there a solution for it ?

Importing javascript file for use within vue component

I am working on a project that requires using a js plugin. Now that we're using vue and we have a component to handle the plugin based logic, I need to import the js plugin file within the vue component in order to initialize the plugin.
Previously, this was handled within the markup as follows:
<script src="//api.myplugincom/widget/mykey.js
"></script>
This is what I tried, but I am getting a compile time error:
MyComponent.vue
import Vue from 'vue';
import * from '//api.myplugincom/widget/mykey.js';
export default {
data: {
My question is, what is the proper way to import this javascript file so I can use it within my vue component?
...
Include an external JavaScript file
Try including your (external) JavaScript into the mounted hook of your Vue component.
<script>
export default {
mounted() {
const plugin = document.createElement("script");
plugin.setAttribute(
"src",
"//api.myplugincom/widget/mykey.js"
);
plugin.async = true;
document.head.appendChild(plugin);
}
};
</script>
Reference: How to include a tag on a Vue component
Import a local JavaScript file
In the case that you would like to import a local JavaScript in your Vue component, you can import it this way:
MyComponent.vue
<script>
import * as mykey from '../assets/js/mykey.js'
export default {
data() {
return {
message: `Hello ${mykey.MY_CONST}!` // Hello Vue.js!
}
}
}
</script>
Suppose your project structure looks like:
src
- assets
- js
- mykey.js
- components
MyComponent.vue
And you can export variables or functions in mykey.js:
export let myVariable = {};
export const MY_CONST = 'Vue.js';
export function myFoo(a, b) {
return a + b;
}
Note: checked with Vue.js version 2.6.10
try to download this script
import * from '{path}/mykey.js'.
or import script
<script src="//api.myplugincom/widget/mykey.js"></script>
in <head>, use global variable in your component.
For scripts you bring in the browser way (i.e., with tags), they generally make some variable available globally.
For these, you don't have to import anything. They'll just be available.
If you are using something like Webstorm (or any of the related JetBrains IDEs), you can add /* global globalValueHere */ to let it know that "hey, this isn't defined in my file, but it exists." It isn't required, but it'll make the "undefined" squiggly lines go away.
For example:
/* global Vue */
is what I use when I am pulling Vue down from a CDN (instead of using it directly).
Beyond that, you just use it as you normally would.
I wanted to embed a script on my component and tried everything mentioned above, but the script contains document.write. Then I found a short article on Medium about using postscribe which was an easy fix and resolved the matter.
npm i postscribe --save
Then I was able to go from there. I disabled the useless escape from eslint and used #gist as the template's single root element id:
import postscribe from 'postscribe';
export default {
name: "MyTemplate",
mounted: function() {
postscribe(
"#gist",
/* eslint-disable-next-line */
`<script src='...'><\/script>`
);
},
The article is here for reference:
https://medium.com/#gaute.meek/how-to-add-a-script-tag-in-a-vue-component-34f57b2fe9bd
For anyone including an external JS file and having trouble accessing the jQuery prototype method(s) inside of the loaded script.
Sample projects I saw in vanilla JS, React and Angular were simply using:
$("#someId").somePlugin(options)
or
window.$("#someId").somePlugin(options)
But when I try either of those in my VueJS component I receive:
Error: _webpack_provided_window_dot$(...).somePluginis not a function
I examined the window object after the resources had loaded I was able to find the jQuery prototype method in the window.self read-only property that returns the window itself:
window.self.$("#someId").somePlugin(options)
Many examples show how to load the external JS file in VueJS but not actually using the jQuery prototype methods within the component.

Create base class for controller to extend/inherit in Ember application

I'm trying to create a Base Class for my controllers, so I can avoid duplication of code.
The problem here is that it is throwing me errors whenever I try to use it.
"Assertion Failed: You attempted to define a {{link-to "inventory"}} but did not pass the parameters required for generating its dynamic segments. Could not find module controllers/base-inventory imported from frontend/controllers/inventory"
To create my base controller I am using ember cli and this is what I did:
ember g controller base-inventory
Then
// base-inventory.js
const BaseInventory = Ember.Controller.extend({
//my code...
});
export default BaseInventory;
In the controller where I want to use this base class I did the following
import BaseInventory from 'controllers/base-inventory';
// also tried import { BaseInventory } from 'controllers/base-inventory';
// and export default new BaseInventory({});
export default BaseInventory.extend({
//more code here...
});
Any thoughts of what I am doing wrong?
I didn't plan to use mixins, because it doesn't seem the best option here at first. I am not really sure about the sharing content, which mixins provide. I don't think it would be a problem since I'm trying to inherit within controllers, but as I said I'm not sure about how it really works.
If it's not possible to do the way I'm trying to, I'll write a mixin.
Both files are in the same folder structure so import path should be like ./base-inventory
import BaseInventory from './base-inventory';

Using lodash in all of vue component template

Can I use lodash _ in all of my vue component?
for example:
I have components organized like below:
App.vue > Parent.vue > Child.vue
I would like all of my component to access _ lodash without defined in every component vm data
===
I am also trying using Mixins. it works. but the result not expected like this _().isEmpty() instead of _.isEmpty()
Some of the current answers may work in your scenario, but they have downsides:
Adding to the window object means your Vue project can't be server rendered, because servers don't have access to the window object.
Importing in every file works fine, but it can be a pain if you have to remember to do it in every file.
An alternative approach is to add your library to the Vue prototype. All components inherit from this so they will now all be able to access your library from the this keyword.
import _ from 'lodash';
Object.defineProperty(Vue.prototype, '$_', { value: _ });
Now lodash is available as an instance method for all components. In a .vue file you can do this without importing anything:
export default {
created() {
console.log(this.$_.isEmpty(null));
}
}
The advantage of using Object.defineProperty rather than a normal property assignment is that you can define a descriptor which allows you to make the property read-only, which it will be by default. This stops consuming components from overwriting it.
This is more thoroughly explained in this blog post (which I wrote).
Note: The downside to this approach is that you get the entire Lodash library, even if you only need one or two functions. If that's a problem, best to use import { reduce, whatever } from "lodash"; at the top of the file requiring it.
You could import the lodash into each component:
<script>
import _ from 'lodash'
export default {
methods: {
test (value) {
return _.isEmpty(value)
}
}
}
</script>
For inline templates separated from the js module code it should work with:
Vue.component('some-tag', {
computed: {
_() {
return _;
}
}
});
And then you can use it in template in "native" way - _.isEmpty(value).
import _ from 'lodash'
Vue.prototype._ = _
Insert these lines in your main.js file and it will work all over your app.
You could import lodash globally like this
window._ = require('lodash');
Once that has been imported, you will have access to _ from anywhere.
A simple approach that worked for me:
Vue.set(Vue.prototype, '_', _);
This should allow you to use _ in all component templates and vue instances.
You can use plugin/mixin like this.
import _ from 'lodash';
exports default {
install : function(Vue, options){
Vue.mixin({
computed : {
"_" : function(){
return _;
}
}
});
}
}
Bit late to the party but through my research of finding a way to import lodash and other libraries into all my .vue files, I encountered the webpack ProvidePlugin, which achieves everything the OP requested with almost no fuss. To implement this solution, following this fantastic tutorial.
I would note that in the tutorial, he left import "jquery" in his app.js file, which is not required. The plugin with import it automatically.
Check out vue-lodash!!
It's a new wrapper for using lodash in vue.
You can call it using
Vue._.random(20) // for getting random number between 20
this._.random(20) //or other method you want to use
in any of the component file :)
The proper way is to use provide / inject as such:
import _ from 'lodash';
const app = createApp({
provide: {
$_: _,
}
});
Then in аnоthег component:
<script>
export default {
name: 'аnоthег-component',
inject: [
'$_'
]
}
</script>
You can also create a base component and make all of your components extend it.
// base-component
import _ from 'lodash';
export default Vue.extend({
computed: {
_() {
return _;
},
},
});
// my-component
import BaseComponent from 'path/to/base-vue';
export default BaseComponent.extend({
template: '<p>Lodash is available: {{!!_}}</p>'
methods: {
doSomehting() {
// `this._` should be available
},
},
});
The pro of this approach is it's not intrusive, so no possible conflict with Vue in the future. Also, you can add even more things to the BaseComponent, like other libraries and external services, and they will be available to all other components.
The con is it's more verbose and you have to remember to inherit from the base component.
For vue users
Go to main.js
import _ from 'lodash'
Vue.set(Vue.prototype, '$_', _)
For nuxt.js users
create main.js inside plugin folder
plugin/main.js
import _ from 'lodash'
Vue.set(Vue.prototype, '$_', _)
Then add into
nuxt.config.js
plugins: ['~plugins/main.js'],
usage are same in both vue and nuxt js
then use in component
this.$_.map(arra,(x)=>{})

How can I export 2 items from a Typescript Module

Scenario
I'm tasked with creating a Knockout Components based UI using Typescript.
This is something I've done hundreds of times in vanilla JS, but I just can't seem to get TS to generate a JS module in the correct format to be consumed by Require JS.
Ideally, what I'd like is for Typescript to generate identical output to that written in JS, but right now I'd just like to get things working.
The Javascript
This is the Javascript that I'm trying to get TS to generate, this is Javascript from a DIFFERENT project that does not use TS, and in that project when the JS is in this format, everything works fine.
define(["knockout", "text!./menubar.html"], function (ko, menubarTemplate)
{
function menubarViewModel()
{
var self = this;
self.menuBrand = ko.observable("Menu Brand");
self.menuItems = ko.observableArray([]);
self.load();
return self;
}
menubarViewModel.prototype.load = function ()
{
var self = this;
$.getJSON("data/menudata.json", function (data)
{
self.menuItems(data);
});
};
return { viewModel: menubarViewModel, template: menubarTemplate };
});
In my actual JS file that uses the component all I need to do is:
define(["jquery", "knockout", "bootstrap"], function ($, ko)
{
ko.components.register("menubar",
{
require: "application/components/menubar"
});
ko.applyBindings();
});
The HTML for the menubar component is just a simple chunk of plain HTML markup sprinkled with "data-bind" attributes where needed to inject the data into the component.
As I say, this JavaScript version works perfectly, but the client I'm working for at the moment wants this in Typescript, so the first challenge I need to tackle is how to return
return { viewModel: menubarViewModel, template: menubarTemplate };
from a typescript module.
Typescript so far
Iv'e had a small amount of success, for instance if I do:
import ko = require("knockout");
module HelloComponent {
export class HelloViewModel {
helloText = ko.observable<string>("Hello World");
}
}
That produces a JS class, that ko tries to load, but complains that it has no template.
This says to me that if I can take the TS class above and export the require text HTML from the same class, then I might just make this work.
If I further expand that class as follows:
import ko = require("knockout");
import helloTemplate = require("text!application/components/hello.html");
module HelloComponent {
export class HelloViewModel {
helloText = ko.observable<string>("Hello World");
}
var tmp = helloTemplate;
}
I've been trying to solve this for a couple of days now, and most of the experimentation I've tried has either failed, or appears to run in the chrome debugger, but produces no output in the component.
There are dozens of posts here on SO, but none of them apply to Knockout Components, all the others apply to page level standard binding, which is different from KO components, it's the same scenario with the various blog posts I've been reading.
If anyone has an insight on how to implement this as per the advice in the KnockoutJS docs but using TS rather than JS, then I'd love to hear your ideas.
Update 12-08-2015 (Based on James Reply)
After changing one of my components to match 'James Brantly' s answer, I now see the following in Visual Studio:
Update 13-08-2015 (Post testing James Reply)
Even with the errors shown above, I've now put together several components, all using the same methodology, and everything works perfectly.
Visual studio still flags these files as having errors, but it still allows me to compile the project, and Typescript still does what it needs to and compiles to JavaScript.
At this point, am marking the question as answered, as the initial question has been solved.
I think the key to your question is that you want the module to return something like { viewModel: menubarViewModel, template: menubarTemplate };. You do that like this:
import menubarTemplate = require('text!./menubar.html');
class MenubarViewModel{
}
export = {
viewModel: MenubarViewModel,
template: menubarTemplate
}
In the code :
import ko = require("knockout");
module HelloComponent {
You are mixing internal modules (the module keyword now called namespaces) and file based modules (the import keyword).
DON'T
Use External modules only:
import ko = require("knockout");
export class HelloViewModel {
helloText = ko.observable<string>("Hello World");
}
More : https://www.youtube.com/watch?v=KDrWLMUY0R0&hd=1

Categories

Resources