Invoke JQuery method from Angular 2 component - javascript

I'm working on creating an Angular 2 front end on an existing project that previously just used JQuery. Is it possible to invoke a JQuery method inside of an Angular 2 component, when that JQuery function exists in a separate file? I'm writing my components in TypeScript, in case that is important to know.
For example, I have a JavaScript file called EditCheckBoxes.js with a method called editCheckBoxes(). In order for editCheckBoxes() to work, I need it to be invoked after a certain component is initiated. My attempted solution was this:
ngOnInit(): void {
editCheckBoxes();
}
This code gives me the following error:
Cannot find name 'editCheckBoxes'.
Is there any way I can get this to work?
Also, I added declare var $: any; to my component file, so I am able to use JQuery within that component, but I'd rather not copy entire files into my components in order to use them.
EDIT:
The folder structure looks like this:
Plan
app
selling
My Angular 2 component
Scripts
EditCheckBoxes.js
In my component, the import statment looks like this: import { editCheckboxes } from '../../Scripts/EditCheckboxes';

You need to import the editCheckboxes method in your typescript file for it to be available.
To do that you first need to export the editCheckboxes function from EditCheckBoxes.js
export function editCheckboxes() { ... }
Next you should just import that function inside your component
import { editCheckBoxes } from './EditCheckBoxes';
Now it can be called in your component: editCheckBoxes();

In order to import function from js file you should at first export it like so:
// EditCheckBoxes.js
module.exports = function editCheckBoxes () { ... };
then add a d.ts file in same directory as your js-file with definition of your module that would be used by Typescript
// EditCheckBoxes.d.ts
declare function editCheckBoxes (): void;
export = editCheckBoxes;
then in your Typescript file you would specify your definition file, import your function and use it like so:
/// <reference path="../../Scripts/EditCheckBoxes.d.ts" />
import editCheckBoxes = require('../../Scripts/EditCheckBoxes');
ngOnInit (): void {
editCheckBoxes();
}

Related

Is an explicit export necessary when a function is made available from an index file?

I use vanilla JavaScript to define various components in separate folders. For example, the definition for the accordion component can be found in accordion/accordion.js and is structured as follows:
import toggleCollapsible from "../../helpers/toggle-collapsible";
const SELECTOR_ACCORDION = ".accordion";
const SELECTOR_SLAT = ".accordion-slat";
function Accordion(accordion) {
...
}
Array.from(document.querySelectorAll(SELECTOR_ACCORDION)).forEach((accordion) => Accordion(accordion));
export default Accordion;
There is also an index.js file which is used only for making the component available elsewhere via export * from "./accordion";
Leaving out export default Accordion; part in accordion.js seems to work just fine. So is there any reason why I shouldn't drop it and simply use just export * from "./accordion"; in the index file?
If you don't export anything from the module, then export * from ... will also export nothing.
However, just importing that module has that side effect of activating the array for elements on the page, which feels unclean (and indeed, might not work if the script is in <head>, for instance...).
I'd wrap the Array.from() stuff in a function that's exported:
export function activateAccordions() {
Array.from(...);
}
and then import and call that in your index.
import {activateAccordions} from "./accordion";
activateAccordions(); // TODO: might need to call this only after the page is loaded
Then, if you additionally need to be able to accordion something arbitrary,
export function Accordion()
and import it too...

How to use an Vanilla Javascript Class in a Vue Component?

I have a laravel project which globally registers vue in the app.js file. Vue works in my project as I have it working in another part of my app. What makes this situation unique is I do not have somewhere, like a blade file, to pass my vue component through as a medium to be used. I have a vanilla js file and a vue component. I want to be able to use the methods created in my test.js file inside of my testing.vue file. I am simply trying to pass some data from my js to my vue and then console.log() it out to ensure the data is being passed properly. I do use npm run dev to compile assets. The code is pretty boiler plate at this point since my main objective right now is to just pass the data properly. I did confirm the import path as well and it is correct. Not sure why the console.log() is not showing in the browser. This is my current code:
Test.js
export class Test {
testing() {
console.log('this is a test');
}
}
Testing.vue
<template>
<div>
</div>
</template>
<script>
import {Test} from '../../js/Test';
export default {
name: 'Testing',
mounted() {
console.log(Test.testing());
}
}
</script>
You must create an instance of the Test class in order to use the method. In your Testing.vue file:
<template>
<div>
</div>
</template>
<script>
import {Test} from '../../js/Test';
export default {
name: 'Testing',
mounted() {
// IMPORTANT to create instance of a class
const myTestInstance = new Test();
console.log(myTestInstance.testing());
}
}
</script>
The method testing() on class Test is not a static method and thus need object to invoke. Alternately, if you don't want to create object, then you can declare the method as static as shown below:
export class Test {
static testing() {
console.log('this is a test');
}
}
You can then us it like this: Test.testing().

Typescripting custom plugins in Nuxt

In my Nuxt project, I created a custom plugin file that returns an object. /helpers/settings:
export const settings = {
baseURL: 'https://my-site.com',
...
};
I register this file in /plugins/settings.ts:
import Vue from 'vue';
import { settings } from '~/helpers/settings';
Vue.prototype.$settings = settings;
And in nuxt.config.js:
export default {
...
plugins: [
'~/plugins/settings',
Then, in a component, I can use my plugin like so:
export default Vue.extend({
data() {
return {
url: `${this.$settings.baseURL}/some-path`,
Everything works as expected, except in that in my console, I get a typescript error from the line that I refer to my plugin in my component:
Property '$settings' does not exist on type 'CombinedVueInstance<Vue, unknown, unknown, unknown, Readonly<Record<never, any>>>'.
Hence my question: what is the proper way to apply a type to my custom plugin so that I don't get this error every time I use it?
According to the docs, you'll need to augment the type file for Vue.
Place the following code in a file named plugin-types.d.ts.
// 1. Make sure to import 'vue' before declaring augmented types
import Vue from 'vue'
// 2. Specify a file with the types you want to augment
// Vue has the constructor type in types/vue.d.ts
declare module 'vue/types/vue' {
// 3. Declare augmentation for Vue
interface Vue {
$settings: string
}
}
This answer also work but I found an easier, though dirtier, way to fix it without the need of adding the plugin-types.d.ts file.
Just add a property to you componen with the name of plugin like following:
#Component
export default class YourComponent extends Vue {
private $settings!: string; // your plugin here
private url: string = `${this.$settings.baseURL}/some-path`
}

Pulling in types for use in a .d.ts file with declare module without making it a module file

I am attempting to write a type declaration for an NPM package (or more specifically an untyped directory within a package) my project depends on.
The package itself is react-big-calendar and it doesn't bundle its own types, however there is #types/react-big-calendar which provides types for the main package, but not for the react-big-calendar/lib/addons/dragAndDrop "sub-package" it has in itself.
The above gets me working import BigCalendar from 'react-big-calendar' which is great, and I want to also get working import withDragAndDrop from 'react-big-calendar/lib/addons/dragAndDrop' so I figured I'd just declare module my way there.
I cannot place the declare module statement in any TSX file, because it has to be in its own file which is not an ES module, but it also cannot be an import+export free TS file, because I am also using CRA which enforces isolatedModules and so disallows non-module TS/X files.
I can and should place it in a .d.ts file, like this:
declare module 'react-big-calendar/lib/addons/dragAndDrop' {
function withDragAndDrop(calendar: any): any;
export = withDragAndDrop;
}
This looks fine, but is not much of an improvement typing-wise. The function I am looking to type basically takes a React component and returns it with some extra props. But even to just type is as a function which takes the specific BigCalendar component and returns it is a problem, because I cannot use an import statement (to pull in the component type) in the d.ts file. If I do, it turns into a module file and that breaks the declare module statement.
I am looking for something like this:
declare module 'react-big-calendar/lib/addons/dragAndDrop' {
function withDragAndDrop(calendar: BigCalendar): typeof BigCalendar & {
props: {
extraProp1: string;
// …
extraPropN: string;
}
};
export = withDragAndDrop;
}
With that I should be able to use the HOC like this: const DragAndDropCalendar = withDragAndDrop(BigCalendar); followed by <DragAndDropCalendar originalProp={value} extraProp1={value} />.
The thing that is missing is pulling in the types to the .d.ts file in a way which doesn't turn it into a module breaking the declare module statement stripping me of types, bringing me to square one again.
What options do I have there? I tried to use require but that returns any and I couldn't figure out if <reference is the right tool here or not.
I figured out how to import the original component types (React Big Calendar in this case, but the solution is generic) in the typings (which in this case are for the RBC drag and drop addon).
withDragAndDrop.d.ts:
declare module 'react-big-calendar/lib/addons/dragAndDrop' {
import BigCalendar, { BigCalendarProps, Event } from 'react-big-calendar';
type withDragAndDropProps<TEvent> = {
onEventDrop: (args: { event: TEvent, start: stringOrDate, end: stringOrDate, allDay: boolean }) => void;
onEventResize: (args: { event: TEvent, start: stringOrDate, end: stringOrDate, allDay: boolean }) => void;
};
declare class DragAndDropCalendar<TEvent extends Event = Event, TResource extends object = object>
extends React.Component<BigCalendarProps<TEvent, TResource> & withDragAndDropProps<TEvent>>, {}
function withDragAndDrop(calendar: typeof BigCalendar): typeof DragAndDropCalendar;
export = withDragAndDrop;
};
Usage:
import withDragAndDrop from 'react-big-calendar/lib/addons/dragAndDrop';
import "react-big-calendar/lib/addons/dragAndDrop/styles.css";
const DragAndDropCalendar = withDragAndDrop(BigCalendar);
// TSX:
<DragAndDropCalendar<MyEvent> … onEventDrop onEventResize />

.default is not a constructor using declaration file with javascript package

I am using external javascript package, which doesn't have default export and declaration file. I thought of writing one myself, but I have a problem importing it after I do just that.
Javascript package that I wrote declaration file to looks like this:
function Speech() {
// code
}
Speech.prototype.say = function (saying) {
// code
};
module.exports = Speech;
My declaration file:
declare class Speech() {
constructor()
say(saying: string): Speech
}
export default Speech
When I try to import this package in my .ts files using imports like this:
import Speech from './index'
And try to initialize it:
const speech = new Speech()
I get an error saying index_1.default is not a constructor.
If I import module using another import like:
import Speech = require('./index')
It works as intended and doesn't throw any errors.
Is it possible to somehow fix declaration file, so that I could use default imports and I wouldn't have to use require?
Or is using import with require the right way in my situation?
Thanks

Categories