I am creating a plugin using Typescript which creates a DOM for Header and attach that to the page. This project uses JQuery for DOM operations. I want to pass config Options to the plugin from the HTML page. For that, I am extending JQuery with my custom function and passing the options in it.
But the problem is when I load that HTML page, I get an error: "$(...).createCentralHeader is not a function".
Here is my Index.html file:
<!DOCTYPE html>
<html lang="en">
<body class="siteheader-body">
<div class="cep-Header"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="./dist/cep_HeaderCore.js"></script>
<script>
$('cep-Header').createCentralHeader({
headerUrl: "Hello World!!"
});
</script>
</body>
</html>
Here is my main.ts file:
import * as $ from "jquery";
$.fn.createCentralHeader = function(this: JQuery, options?: HeaderOptions) {
const settings: HeaderOptions = {
headerUrl: options.headerUrl
};
alert(settings.headerUrl);
};
Here is my central-header.d.ts :
interface HeaderOptions {
headerUrl?: string;
}
interface JQuery {
createCentralHeader(options?: HeaderOptions);
}
I am using webpack which uses ts-loader to transpile TS and bundle my plugin into a file cep_HeaderCore.js that is referenced in index.html.
One more important thing to note here is that if I invoke createCentralHeader from within the plugin, it works as expected. eg:
import * as $ from "jquery";
$.fn.createCentralHeader = function(this: JQuery, options?: HeaderOptions) {
const settings: HeaderOptions = {
headerUrl: options.headerUrl
};
alert(settings.headerUrl);
};
$("cep-Header").createCentralHeader({
headerUrl: "Hello World!!"
});
What is going wrong here?
You should add to angular.json
"scripts": [
"node_modules/jquery/dist/jquery.min.js"
]
and jquery is extended in main.ts file with next code
window['$'].fn.test = function (message: string) {
alert(message);
};
or with extending Windows interface without using property in quotes
Related
I have a really simple question but I couldn't find any documentations for it.
I have 4 ts files.
/main.ts
/sub/forms.ts
/sub/validators.ts
/sub/location.ts
I'm using Visual Studio Code to code and when I save a TypeScript file, it auto compiles it and creates a JS file (ES5).
my problem is.. when I save main.ts file, how can I have forms.ts, validators.ts and location.ts in it as well?
In PHP, we simple use include('filename.php');
Is there way to do it in TypeScript?
main.ts;
import { Forms } from "./sub/forms";
import { Validators } from "./sub/validators";
import { Location } from "./sub/location";
let emp1 = new Validators('TEST');
emp1.greet();
/sub/validators.ts;
export class Validators {
employeeName: string;
constructor(name: string) {
this.employeeName = name;
}
greet() {
console.log(`Good morning ${this.employeeName}`);
}
}
main.js (after auto save compile)
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var validators_1 = require("./sub/validators");
var emp1 = new validators_1.Validators('TEST');
emp1.greet();
it doesn't import the validators.ts code into main.js
main.js has this code
window.l = function () { }
try {
window.l = console.log.bind(console)
} catch (e) { }
which works in non-Vue apps. However, when calling
l("test")
from a Vue action/method, it complains it isn't defined.
How can that work?
Reasoning: need to output some debugging data, with as less typing as possible.
When you want to add global-level functionalities to Vue, you should generally use mixins or plugins.
For the next examples, I assume you are using vue-cli with the complete webpack template. Moreover, we will use App.vue as a practical reference, but you can apply the same principles to other components...
Mixins
Create a mixin named log.js (in a mixins folder) with the following code:
export default {
methods: {
l (...args) { // rest parameters
console.log(...args) // spread operator
}
}
}
Open App.vue, import your mixin and use it:
<script>
import log from './mixins/log'
export default {
name: 'app',
mixins: [log],
created () {
this.l('Foo', 'Bar') // Foo Bar
}
}
</script>
Plugins
Create a plugin named log.js (in a plugins folder) with the following code:
export default {
install (Vue, options) {
Vue.prototype.$l = console.log.bind(console)
Vue.l = console.log.bind(console)
}
}
Open your main.js and declare your global plugin:
import log from './plugins/log'
Vue.use(log)
Open App.vue, import Vue and use your plugin:
<script>
import Vue from 'vue'
export default {
name: 'app',
created () {
this.$l('Foo') // Foo
Vue.l('Bar') // Bar
}
}
</script>
You might say: "Hey, why should I have to write this or Vue? I just wanna write l, that's all!". Well... This is actually how Vue has been designed. In order to provide global functionalities (shared by all components), you have to add static properties to the Vue object or prototype properties (Vue.prototype) that are accessible through this in Vue instances.
EDIT
I have just thought about an alternative solution...
You can edit your index.html to add this:
<script>
var l = console.log.bind(console)
</script>
Then, to avoid ESLint errors, you should also edit your .eslintrc.js file to reference your new global variable:
globals: {
l: true
}
The file looks like this:
// http://eslint.org/docs/user-guide/configuring
module.exports = {
root: true,
parser: 'babel-eslint',
parserOptions: {
sourceType: 'module'
},
globals: {
l: true
},
env: {
browser: true,
},
// https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style
extends: 'standard',
// required to lint *.vue files
plugins: [
'html'
],
// add your custom rules here
'rules': {
// allow paren-less arrow functions
'arrow-parens': 0,
// allow async-await
'generator-star-spacing': 0,
// allow debugger during development
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0
}
}
Restart your dev server. Now you should be able to use l in your code:
<script>
export default {
name: 'app',
created () {
l('It works!')
}
}
</script>
Assign console.log like this.
window.l=console.log;
Get request by Systemjs is not adding extention .js to the url.
These are my TypeScript Classes
customer.ts
import {Address} from "./Address";
export class Customer {
private _customerName: string = "";
public CustomerAddress: Address = new Address();
public set CustomerName(value: string) {
if (value.length == 0) {
throw "Customer Name is required";
}
this._customerName = value;
}
public get CustomerName() {
return this._customerName;
}
Validate(): boolean {
return this._customerName != '';
}
}
address.ts
export class Address {
public Street1: string = "";
}
using following Systemjs init code
System.config({
defaultExtension: 'js',
});
System.import("Customer.js").then(function (exports) {
var cust = new exports.Customer();
});
Customer.js is loaded successfully but Address.js is not.
The GET request for Address.js does not contains .js extention
resulting following request in console
GET http://localhost:65401/Address 404 (Not Found).
I have tried to update following code in customer.ts to following
import {Address} from "./Address.js";
But it is syntactically wrong and it shows error in VS2013.
How can i force Systemjs to add extension ".js" to the GET request.
Thanks
The defaultExtension keyword is not a top level config option. It needs to be under packages directive, see: https://github.com/systemjs/systemjs/blob/master/docs/config-api.md#packages
That's why it's ignored and SystemJS doesn't append the extension. You can define one "global" package which is probably the easiest way to make sure the extension is always appended to every import path:
SystemJS.config({
packages: {
'.': {
defaultExtension: 'js'
}
}
});
I'm working on a angular2 application written in TypeScript.
This works:
I have a module called plugin-map.ts which looks something like this:
import { Type } from '#angular/core';
import { SomeComponent } from './plugins/some.component';
export const PluginMap: { [key: string]: Type<any> } = {
'e690bec6-f8d1-46a5-abc4-ed784e4f0058': SomeComponent
};
It gets transpiled to a plugin-map.js which looks something like this:
"use strict";
var some_component_1 = require('./plugins/some.component');
exports.PluginMap = {
'e690bec6-f8d1-46a5-abc4-ed784e4f0058': some_component_1.SomeComponent
};
//# sourceMappingURL=plugin-map.js.map
And in other modules I'm importing my PluginMap like this:
import { PluginMap } from './plugin-map';
What I want:
Now I want to create plugin-map.js at runtime when my server starts. So I want to get rid of my plugin-map.ts and instead have only a (generated) plugin-map.js. And I don't want to have any transpile-time dependencies to that plugin-map.js.
What I tried:
In modules where I need to access the PluginMap I replaced the import statement with a declaration like this:
declare const PluginMap: { [key: string]: Type<any> };
Now of course at runtime I get a Error: (SystemJS) 'PluginMap' is undefined. So my next step was to load plugin-map.js explicitly from my index.html like this:
...
<script src="js/system.src.js"></script>
<script src="systemjs.config.js"></script>
<script>
System.import('./app/plugins/plugin-map.js').catch(function (err) { console.error(err); });
System.import('app').catch(function(err){ console.error(err); });
</script>
...
When I start my application I can see that the browser actually requests the plugin-map.js file. But I still get the Error: (SystemJS) 'PluginMap' is undefined.
Question:
How/where do I have to load my generated plugin-map.js so that this works?
I had to make sure that PluginMap is available in the global context. So the generated plugin-map.js has to look like this:
var some_component_1 = require('./plugins/some.component');
PluginMap = {
'e690bec6-f8d1-46a5-abc4-ed784e4f0058': some_component_1.SomeComponent
};
and not like this:
"use strict";
var some_component_1 = require('./plugins/some.component');
exports.PluginMap = {
'e690bec6-f8d1-46a5-abc4-ed784e4f0058': some_component_1.SomeComponent
};
//# sourceMappingURL=plugin-map.js.map
Now it seems to work.
I have a Typescript project, which calls a function from a module.js module. Here is my initial code:
//app.ts
import { MobileServiceUser, setCache, getCache } from "nativescript-azure-mobile-apps/user";
export function onLoginTap(args) {
console.log("tap");
ai.busy = true;
var cache = getCache();
}
if I use the VSCode "go to definition" feature, then getCache() goes to the import statement at the top, if I do this again, then I go to:
//module.ts
declare module "nativescript-azure-mobile-apps/user" {
export class MobileServiceUser {
mAuthenticationToken: string;
mUserId: string;
constructor(o: { userId: string; });
}
export function setCache(user: MobileServiceUser): void;
export function getCache(): MobileServiceUser;
}
When I execute the code and the var cache = user_1.getCache(); line is executed, my app crashes, throwing error:
TypeError: user_1.getCache is not a function
File: "/data/data/inc.tangra.azuremobileservicessample/files/app/main-page.js, line: 94, column: 23
app.ts looks like this compiled to js:
var user_1 = require("nativescript-azure-mobile-apps/user");
function onLoginTap(args) {
console.log("tap");
ai.busy = true;
var cache = user_1.getCache();
}
Why isn't the code recognising the imported function?
Update: this repo shows the project structure (the first page of code is in sample/main-page.ts