How to call global function from controller class in AngularJs component - javascript

In app.module.js file, import JS file from external lib
import 'assets/scripts/admin';
with global function:
function anonymousAdmin() {
"use strict";
implementation();
}
Now in app.component.js file have controller with function call:
export const AppComponent = {
controller: class AppComponent {
$onInit() {
/* global anonymousAdmin */
anonymousAdmin();
}
}
};
Run Webpack/Babel to save all files (ES6) into one file (ES5). Unfortunately i have error in console:
ReferenceError: anonymousAdmin is not defined
Someone knows how I can call this function in the controller?

anonymousAdmin is not global function. The file is imported as ES module, and ES modules force strict mode that prevents them from leaking variables to global scope.
It should be explicitly defined as a global:
function anonymousAdmin() {...}
window.anonymousAdmin = anonymousAdmin;
If the file belongs to third-party module that cannot be directly edited, and considering that Webpack is being used, the latter can be configured to expose a variable from file ES module export with exports loader, something like:
...
module: {
rules: [
{
test: require.resolve('assets/scripts/admin'),
use: 'exports-loader?anonymousAdmin'
}
]
},
...
And the function is being imported like:
import { anonymousAdmin } from 'assets/scripts/admin';

Try this one. You need to have alias for the script.
import * as admin from 'assets/scripts/admin';
export const AppComponent = {
controller: class AppComponent {
$onInit() {
/* global anonymousAdmin */
admin.anonymousAdmin();
}
}
};

Related

Mix Node's CommonJS and Typescript's ES modules

I have a legacy app in Node.js v10 (but upgrading is an option) which uses CommonJS modules (require).
The codebase is written in JS.
Now, I want to refactor part of the project and write it in Typescript using TS modules (import/export) and classes.
What is the best way to interface those newly generated JS files (compiled from TS) from my legacy JS code?
Say I have a class in TS:
export default class DemoClass {
public static sayHello() {
console.log("Hello from demo class...");
}
}
which gets compiled to:
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var DemoClass = /** #class */ (function () {
function DemoClass() {
}
DemoClass.sayHello = function () {
console.log("Hello from demo class...");
};
return DemoClass;
}());
exports.default = DemoClass;
//# sourceMappingURL=DemoClass.js.map
I have set "module": "commonjs" in my tsconfig.json.
Now, how do I require that DemoClass.js from my legacy app.js and e.g. invoke sayHello()?
The following code seems to work, but this "default" stuff does not seem right:
var DemoClass = require('./lib/DemoClass');
DemoClass.default.sayHello();
Instead of using export default, use export =.
export = class DemoClass {
public static sayHello() {
console.log("Hello from demo class...");
}
}
Playground link

Use rollup.js with jQuery adaptor in same file

I have the main function to export and the jQuery adaptor in the same file. And I would like to keep them this way.
Is there a way with rollup.js to create the bundle file compatible with AMD, CommonJS and Browsers?
Right now I have this test file:
//src/foo.js
export default function(){
function initialise() {
var TEST = {};
TEST.version = '1.0.0';
TEST.hello = function(){
console.log("hello man!!");
};
return TEST;
}
//jQuery adapter
(function($){
$.fn.demo = function(options) {
$.fn.demo.test = 'test';
};
})(jQuery);
return initialise;
};
And I tried using this rollup config:
// rollup.config.js
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'umd',
globals: {
$: '$'
}
}
};
However I can't seem to have access to $.fn.demo:
// src/main.js
import jQuery from 'jQuery';
import pepe from './foo.js';
console.log(jQuery); //<--- undefined
console.log($); //<--- undefined
console.log("-- JS--");
console.log(pepe); //<---- working fine
console.log("-- $.fn.demo --");
console.log($.fn.demo); //<--- undefined
Note that in your main.js file pepe is a function (one which you exported from foo) and you didn't call it hence $.fn.demo is undefined. You must call pepe(); in order for you adapter to be executed.
See also how to tell Rollup that jquery is external and the jquery module ID equates to the global $ variable.

Importing a Typescript Module that has a constructor

I want to break up my file into several modules. One module has a constructor. I am able to import my module into another file, but I don't know how call my constructor in the new file.
namespace CreditReports{
export class CreditReportVM {
//some code
constructor(targetElement: HTMLElement) {
ko.applyBindings(this, targetElement);
this.init();
}
public init = () => {
//some code
}
}
}
You just need to export the namespace too.
export namespace CreditReports {
//...
}
Then when you want to call the constructor:
import { CreditReports } from "./my-module";
//...
new CreditReports.CreditReportVM(myElement);
You should replace "./my-module" with the file name (an path too) where your typescript module is in.

prototype function missing when calling third party node package in Angular 2+

I am trying to use a third party Node module in an angular 2+ project.
installed with npm install --save ModuleName
The function in question is in a file named Foo.js and looks like this:
var foo = function(param1, param2) {
...
this.init();
}
foo.protoype = {
constructor: foo,
init: function(){
...
},
...
}
module.exports = foo;
index.js for the node module looks like:
var ModuleName = require("./src/ModuleName");
ModuleName.foo = require("./src/Foo");
module.exports = ModuleName;
I am trying to use the module in a Directive:
import { Directive, OnInit } from '#angular/core';
import { ModuleName } from "ModuleName"
#Directive({
selector: '[customDirective]'
})
export class CustomDirective implements OnInit {
constructor() {
...
}
ngOnInit() {
let poorlyNamedVariable = ModuleName.foo(param1, param2);
}
}
When foo is called it produces ERROR TypeError: this.init is not a function
console.log(this) in foo shows an instance of ModuleName which, in turn, has an instance of foo, which has a prototype where init is defined.
I suspect the problem stems from some sort of scoping issue, but am still too new to both Angular and Node to untangle the mess.
Use import * as ModuleName from "ModuleName" for CommonJS modules.

Namespace is undefined after compile

I am writing a little game engine in typescript, and when I compile it to javascript, I get an error when running the javascript. It compiles without error too.
My main entry file (main.ts) starts with these two lines:
require('./core/Obj');
require('./core/Component');
It builds out fine but when I run it, the second require has some issues and gives this error:
Uncaught TypeError: Class extends value undefined is not a function or null
core/Obj.ts
namespace GameEngine {
export class Obj {
// Some functions/methods
}
}
core/Component.ts
namespace GameEngine {
export class Component extends Obj {
}
}
Then once it is compiled, it looks something like this:
(function (exports, require, module, __filename, __dirname, process, global) { (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[
function(require,module,exports){
var GameEngine;
(function (GameEngine) {
class Component extends GameEngine.Obj { // Error is here
}
GameEngine.Component = Component;
})(GameEngine || (GameEngine = {}));
},{}],
5:[function(require,module,exports){
var GameEngine;
(function (GameEngine) {
class Obj {
}
GameEngine.Obj = Obj;
})(GameEngine || (GameEngine = {}));
},{}]
});
Here is the gulp task that I am running:
gulp.task('compile-engine', function () {
return browserify()
.add('./GameEngine/main.ts')
.plugin(tsify, {})
.bundle()
.on('error', function (error) { throw error; })
.pipe(source('gameEngine.js'))
.pipe(buffer())
.pipe(gulp.dest('build/'));
});
Each module has its own GameEngine namespace - as modules don't pollute the global scope. (In the compiled bundle in your question, you can see that they are separate.) There is an answer here that explains namespaces and modules.
In using tsify, you're using (external) modules. Things can be made simpler if you do away with the namespacing. The TypeScript Handbook has this to say about using namespaces with modules:
A key feature of modules in TypeScript is that two different modules will never contribute names to the same scope. Because the consumer of a module decides what name to assign it, there's no need to proactively wrap up the exported symbols in a namespace.
You could change the exports and imports to something like this:
core/Obj.ts
export class Obj {
// Some functions/methods
}
core/Component.ts
import { Obj } from "./Obj";
export class Component extends Obj {
}
main.ts
import { Component } from "./core/Component";
// Do something with Component

Categories