I have an angular service, from which I would like to consume a plain javascript module.
When I instantiate it from he constructor I get the following error:
TypeError: Engine is not a constructor
My service is as follows:
import { Injectable } from "angular2/core";
import * as Engine from './engine';
#Injectable()
export class MyService {
constructor() {
this.engine = new Engine(); // causing error
}
doStuff() {
return this.engine.doStuff();
}
}
And my module code:
var _ = require('lodash');
function Engine() {
this.stuff = [];
};
WorkoutEngine.prototype.doStuff = function() {
console.log('do stuff');
};
module.exports = Engine;
I can't figure out where I am going wrong?
Since you are trying to inject Engine to the constructor of MyService,
#Injectable()
export class MyService {
// Let angular inject the engine.
constructor(private engine: Engine) {
}
.....
}
Related
I have coded a js file to return some values to ts files, in my angular project.
var webGlObject = (function() {
return {
init: function() {
alert('webGlObject initialized');
}
}
})(webGlObject||{})
import { Component, OnInit } from '#angular/core';
import '../../../lib/jquery-3.2.1.min.js';
import '../../../server/getSummary.js';
declare var webGlObject: any;
#Component({
selector: 'mop-designer-dashboard',
templateUrl: 'mop-designer-dashboard.component.html',
styleUrls: ['mop-designer-dashboard.component.css'],
})
export class MopDesignerDashboardComponent implements OnInit {
debugger;
scoreBoardList: any = [];
breadcrumb: any = [];
constructor() {
/* prepare breadcrumb */
this.breadcrumb = [
{
label: 'Mop Designer',
href: '/#/mop-designer'
}
];
debugger;
webGlObject.init();
}
ngOnInit() {
console.log('test');
}
}
but declare var webGlObject: any; doesn't create any object
and I get following error:
>
ZoneTask.invoke # zone.js?fad3:339
VM292602:61 Error: Uncaught (in promise): Error: Error in :0:0 caused by: webGlObject is not defined
ReferenceError: webGlObject is not defined
at new MopDesignerDashboardComponent
This is because you are creating it as a class and using as an object.
Try this:
Put following in js file:
var webGlObject = function() {
this.init= function() {
alert('webGlObject initialized');}}
And create an instance in ts file:
declare var webGlObject: any;
export class YourComponent{
constructor(){
let wegObj = new webGlObject();
wegObj.init();
}
}
I'm converting a component (AngularJS 1.6) from javascript to typescript.
class NewProjectCtrl {
price: number;
static $inject = ['$http'];
constructor($http) {
let ctrl = this;
ctrl.price = '50';
...
}
createProject() {
$http.post('/api/project', ctrl.project)
...
}
}
angular
.module('app.projects-selection')
.component('newProject', {
templateUrl: 'app/projects-selection/components/new-project/new-project.tmpl.html',
controller: NewProjectCtrl,
bindings: {
user: '<',
}
});
Typescript complains on the $http in my createProject method (Cannot find name $http). All the examples I can find only uses dependency injections in the constructor.
You've forgot this. After injecting use this.$http
Also let me suggest you some approach according to styleguides:
namespace myNameSpace {
class NewProjectCtrl {
private static $inject = ['$http'];
public price: number;
constructor(private $http) {}
createProject() {
this.$http.post('/api/project', ctrl.project)
}
}
class NewProjectComponent implements ng.IComponentOptions {
constructor() {
this.bindings: {
user: '<',
};
this.templateUrl: 'app/projects-selection/components/new-project/new-project.tmpl.html';
this.controller: NewProjectCtrl;
}
}
angular
.module('app.projects-selection', [])
.component('newProject', new NewProjectCtrl());
}
You're creating a class, not a mere function. $http is injected into your constructor function and exists there, but it does not exist in createProject. You need to store it on the instance as property:
private $http; // should be declared first too, preferably with type hint
constructor($http) {
this.$http = $http;
}
createProject() {
this.$http.post('/api/project', ctrl.project)
}
TypeScript has a shorthand for that:
constructor(private $http) {
}
createProject() {
this.$http.post('/api/project', ctrl.project)
}
let ctrl = this also seems rather weird, I don't think that makes a lot of sense. I don't know what else you're doing in the constructor, but I'd refactor what you have to this:
class NewProjectCtrl {
price: number = 50;
static $inject = ['$http'];
constructor(private $http) { }
createProject() {
this.$http.post('/api/project', ctrl.project);
}
}
I am using Google API Javascript library in my Angular 2 application. I have created a service which is injected in components. Here is the code:
import { Injectable } from '#angular/core';
const url = 'https://apis.google.com/js/client.js?onload=__onGoogleLoaded';
#Injectable()
export class GoogleAPIService {
public client: any;
public calculatorService: any;
public actionService: any;
loadAPI: Promise<any>
constructor(){
this.loadAPI = new Promise((resolve) => {
window['__onGoogleLoaded'] = (ev) => {
console.log('gapi loaded');
resolve(window['gapi']);
this.client = window['gapi'].client;
this.loadEndPoints('{Endpoint URL}/_ah/api');
}
this.loadScript();
});
}
doSomethingGoogley(){
return this.loadAPI.then((gapi) => {
console.log(gapi);
});
}
loadScript(){
console.log('loading..')
let node = document.createElement('script');
node.src = url;
node.type = 'text/javascript';
document.getElementsByTagName('head')[0].appendChild(node);
}
loadEndPoints(apiRoot) {
// Loads the OAuth and calculatorendpoint APIs asynchronously, and triggers login
// when they have completed.
var apisToLoad;
var callback = function() {
console.log('API Loaded '+apisToLoad);
if (--apisToLoad == 0) {
//this.endpoint1= this.client.endpoint1; //Doesn't Work
//this.endpoint2= this.client.endpoint2;
}
}
apisToLoad = 3; // must match number of calls to gapi.client.load()
this.client.load('oauth2', 'v2', callback);
this.client.load('endpoint1', 'v1', callback, apiRoot);
this.client.load('endpoint2','v1',callback,apiRoot);
}
}
I have three questions:
How do I get the endpoints gapi.client.endpoint1 as a public variable in the service?
How do I call the methods in the api? In javascript, u can jst call gapi.client.endpoint1.method().execute()
How do I make this service singleton?
Any help is appreciated.
EDIT:
Here is the working version of the service. I use it as provider in my Root module. thus, its available as singleton throughout the application.
import { Injectable } from '#angular/core';
const url = 'https://apis.google.com/js/client.js?onload=__onGoogleLoaded';
const gapiOnLoaded = '__onGoogleLoaded';
const clientName = 'gapi';
const endpointhost = '[HTTPS URL FOR ENDPOINTS]';
const apiEndPoint = endpointhost + '/_ah/api';
#Injectable()
export class GoogleAPIService {
private gapi: any;
private loadAPI: Promise<any>;
constructor() {
this.loadAPI = new Promise((resolve) => {
window[gapiOnLoaded] = (ev) => {
this.gapi = window[clientName];
// Loads the OAuth and other APIs asynchronously, and triggers login
// when they have completed.
let apisToLoad;
let callback = function() {
if (--apisToLoad === 0) {
resolve(window[clientName]);
}
};
apisToLoad = 3; // must match number of calls to gapi.client.load()
this.gapi.load('client:auth2', callback);
this.gapi.client.load('[ENDPOINT_1_NAME]', 'v1', callback, apiEndPoint);
this.gapi.client.load('[ENDPOINT_2_NAME]', 'v1', callback, apiEndPoint);
};
this.loadScript();
});
}
public GetClient(): any {
return this.loadAPI.then((res) => {
return this.gapi;
});
}
private loadScript() {
let node = document.createElement('script');
node.src = url;
node.type = 'text/javascript';
document.getElementsByTagName('head')[0].appendChild(node);
}
}
Inject this service in other services. I created a service for each of the endpoints.
#Injectable()
export class Endpoint1Service {
private gapi: any;
constructor(private googleApiService: GoogleAPIService) {
}
public isLoad() {
return this.googleApiService.GetClient().then((gapi) => {
this.gapi = gapi;
return true;
});
}
public action(data: DataType){
this.gapi.client.endpointname.apimethod(data).execute();
}
}
Services are singletons by default. You should provide it in your AppModule, and then it will be available to all of your components. Just make sure to include it in your component constructors.
import {NgModule} from '#angular/core';
import {BrowserModule} from '#angular/platform-browser';
import {HttpModule} from '#angular/http';
import { AppComponent } from './app.component';
import { routing } from './app.routing';
import { GoogleService } from './google.service'; // important
#NgModule({
imports: [
BrowserModule,
HttpModule,
routing,
],
declarations: [ AppComponent],
providers: [ GoogleService ], // important
bootstrap: [ AppComponent],
})
export class AppModule {
}
To make an endpoint available outside of your service, you can use the public keyword in front of the function that calls the endpoint. To call the endpoint in angular2, you can use the built-in http service from #angular/http. Here's an example service (only using HTTP GET) that will return an Observable for the endpoints you call.
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
import { Observable } from 'rxjs';
#Injectable()
export class GoogleService {
constructor(private http: Http) { }
public endpoint1(): Observable<any> {
return this.http.get("http://endpoint.one.com");
}
public endpoint2(): Observable<any> {
return this.http.get("http://endpoint.two.com");
}
}
You can then use the service like this in your component.
import { Component, OnInit } from '#angular/core';
import { GoogleService } from './google.service'; // important
#Component({
selector: 'app',
templateUrl: 'app.component.html'
})
export class AppComponent implements OnInit {
constructor(private googleService: GoogleService) { }
ngOnInit() {
this.googleService.endpoint1().subscribe(callback1, handleError);
this.googleService.endpoint2().subscribe(callback2, handleError);
}
callback1(data){
// do something with the data from ONE
}
callback2(data){
// do something with the data from TWO
}
handleError(error: any){
console.error(error);
}
}
I recommend reading up a bit on using Observables in this post from Angular University.
I don't think modifying the DOM to load gapi is particularly good practice. It's probably better to use gapi and gapi.auth TypeScript definitions by installing them with NPM.
I've posted instructions on how to do this in my answer to Import gapi.auth2 in angular 2 typescript.
I may just be attempting to combine too many "new-to-me" concepts at once, but I am trying to write a custom Angular directive using a TypeScript class. At the moment, I'm not trying to do anything terribly useful, just a POC.
I have a TypeScript file that looks like this:
module App {
'use strict';
export class appStepper {
public link:(scope:angular.IScope, element: angular.IAugmentedJQuery, attrs: angular.IAttributes) => void;
public template:string = '<div>0</div><button>-</button><button>+</button>';
public scope = {};
public restrict:string = 'EA';
constructor(){ }
public static Factory(){
var directive = () =>
{ return new appStepper(); };
return directive;
}
}
angular.module('app').directive('appStepper', App.appStepper.Factory());
}
It compiles to this in JavaScript:
(function(App) {
'use strict';
var appStepper = (function() {
function appStepper() {
this.template = '<div>0</div><button>-</button><button>+</button>';
this.scope = {};
this.restrict = 'EA';
}
appStepper.Factory = function() {
var directive = function() {
return new appStepper();
};
return directive;
};
return appStepper;
})();
App.appStepper = appStepper;
angular.module('app').directive('appStepper', App.appStepper.Factory());
})(App || (App = {}));
My angular module looks like (I don't even know if I need to do this):
angular.module('app',['appStepper'])
And I attempt to use it in my view:
<div app-stepper></div>
And get these errors:
Uncaught Error: [$injector:nomod]
Uncaught Error: [$injector:modulerr]
Why doesn't my app know about my directive?
Though it is not quite the same question, this answer included an example of what I'm attempting to do: How can I define my controller using TypeScript?
I followed the example in the Plnkr it referenced and found success: http://plnkr.co/edit/3XORgParE2v9d0OVg515?p=preview
My final TypeScript directive looks like:
module App {
'use strict';
export class appStepper implements angular.IDirective {
public link:(scope:angular.IScope, element: angular.IAugmentedJQuery, attrs: angular.IAttributes) => void;
public template:string = '<div>0</div><button>-</button><button>+</button>';
public scope = {};
public restrict:string = 'EA';
constructor(){ }
}
angular.module('app').directive('appStepper', [() => new App.appStepper()]);
}
I am getting an error when trying to attach my config class to my angular app. I get a message saying: $injector:nomod] Module 'ngLocale' is not available! I have a reference to angular.js and angular-route.js
Here is my Config Code.
module TSApplication {
export class Config {
static $inject = ["$routeProvider"];
constructor($routeProvider: ng.route.IRouteProvider) {
this.registerRoutes($routeProvider);
}
private registerRoutes(rProvider: ng.route.IRouteProvider) {
rProvider.when("/", { templateUrl: "/partials/example.html", controller: "ExampleCtrl" });
}
}
}
(function () {
var app = TSApplication.App.angularModule;
app.config(TSApplication.Config);
})();
And here is my App Module code:
module TSApplication {
"use strict";
export class App {
static angularModule = angular.module("App", ['ngRoute']);
}
}
(function () {
// Toaster Junk
})();
Am I missing something simple? If I don't include the config I do not receive an error.
It looks like you are passing TSApplication.Config to the angular config function which is treating it as a function. Therefore, in your "constructor" this isn't actually what you think it is because no instance of TSApplication.Config was created. You could remedy this by changing registerRoutes to a static method and then calling it in your constructor like this Config.registerRoutes($routeProvider);.