How to load angular1 dependencies using systemjs? - angularjs

I'm using typescript, angular1 and systemjs in the following example.
The problem that I have is I'm not able to load the dependencies for the module app as in
module('app', ["ngComponentRouter", "hub"])
I see an error in the chrome dev tab that the injecting a module failed.
The System.import loads the app module which supposed to load the hub module also. But how to inject the hub module as a dependency for app module?
index.html
<app></app>
<script src="~/lib/system.js/dist/system.src.js"></script>
<script>
System.config({
defaultJSExtensions: true,
baseURL: "wwwroot",
map: {
"angular": "/lib/angular/angular.min.js",
"hub": "/App/hub.js"
}
});
System.import('./App/app');
</script>
app.ts
import * as angular from 'angular';
import * as hub from './hub/hub'
module App {
"use strict";
export class AppController {
static $inject = [
"$router"
];
constructor(private $router: any) {
$router.config([
{ path: "/hub", component: "hub", as: "Hub" },
{ path: "/home", component: "home", as: "Home" }
]);
$router.navigateByUrl("hub");
}
}
angular.
module('app', ["ngComponentRouter", "hub"]).
controller('AppController', AppController).
directive('app', () => {
return {
restrict: "E",
template: "<ng-outlet><ng-outlet>",
controller: "AppController"
}
});
}
hub.ts
export module Hub {
export class Tile {
title: string;
name: string;
constructor(title: string, name: string) {
this.name = name;
this.title = title;
}
}
export class HubController {
selectedTiles: number[];
hubTiles: Tile[];
static $inject = [
"$scope",
"$router"
];
constructor(private $scope: any, private $router: any) {
this.hubTiles = [new Tile("USA", "home"),
new Tile("Canada", "home"),
new Tile("Mexico", ""),
new Tile("India", ""),
new Tile("Germany", ""),
new Tile("Australia", "")];
this.selectedTiles = [];
$scope.$watch(() => this.selectedTiles, (newValue: number[], oldValue: number[]) => {
if (newValue[0] != oldValue[0]) {
$router.navigateByUrl(this.hubTiles[newValue[0]].name);
}
}, true);
}
}
var hub = angular.
module("hub", ["ngComponentRouter", "winjs"]).
controller("HubController", HubController).
directive("hub", () => {
return {
templateUrl: "./app/hub/hub.html",
controller: HubController,
controllerAs: "hub"
}
});
}

Related

Access Directive method from the Controller

I am writing an app in AngularJs using Typescript and I am having trouble accessing a method in a directive from the controller class. I added 'control: '=', to the scope of the directive thinking this would bind the control of the methods in the directive to the controller but I am getting an error
The controller code is:
import {DaypartingSegmentsContainer} from "lib/js/publisher/deal/objects/dayparting/dayparting.segments.container";
#Component({
bindings: {
deal: "="
},
controllerAs: "$ctrl",
module: DealApp,
require: {
DealForm: '^form',
},
selector: 'deal-edit-dayparting',
template: require('./templates/deal.edit.dayparting.html'),
})
#Inject(
"$scope",
"$q"
)
export class DealEditDaypartingCtrl extends SxControllerBase {
public daypartingSegmentsContainer : DaypartingSegmentsContainer;
constructor(protected $scope : ng.IScope,
private $q : angular.IQService) {
super($scope);
}
public $onInit() : void {
let self : DealEditDaypartingCtrl = this;
this.daypartingSegmentsContainer.getCommonTimes();
}
}
The directive class is:
import {Inject, Directive} from "lib/js/angularjs/decorators/sx-forward";
import DealApp from "lib/js/publisher/deal/lib.deal.app";
import DealEditDaypartingCtrl from "lib/js/publisher/deal/edit/deal.edit.dayparting";
import "lib/js/publisher/deal/objects/dayparting/dayparting.jquery.factory";
import {DaypartingDayName} from "lib/js/publisher/deal/objects/dayparting/dayparting.day.name";
import {
minutesToString,
stringToMinutes
} from "lib/js/publisher/deal/objects/dayparting/dayparting.time.functions";
#Directive({
selector: 'dayparting-segments-container',
require: '^dealEditDayparting',
replace: true,
module: DealApp,
scope: {
dayName: '<',
control: '=',
},
template: require('./templates/dayparting.segments.container.html'),
controllerAs: '$ctrl',
link: function(scope : any, element : any, attrs : any, daypartingCtrl : DealEditDaypartingCtrl) : void {
scope.daypartingCtrl = daypartingCtrl;
// Delete button watch
scope.$watch(
() => {
return daypartingCtrl.deleteSegment;
},
(shouldDelete : boolean) => {
if (shouldDelete === true) {
scope.$ctrl.onDelete();
}
}
);
// Calendar leave watch
scope.$watch(
() => {
return daypartingCtrl.calendarLeave;
},
(calendarLeave : boolean) => {
if (calendarLeave === true) {
scope.$ctrl.onCalendarMouseLeave();
}
}
);
},
})
#Inject('$scope', 'JQueryFactory' )
export class DaypartingSegmentsContainer {
constructor(private $scope : any,
private JQueryFactory : any) {
this.tooltipIsOpen = false;
this.jquery = JQueryFactory.get();
}
public getCommonTimes() : void {
console.log("i am in getCommon times!!!")
}
}
export default DaypartingSegmentsContainer;
I keep getting a console error saying - Cannot read property 'getCommonTimes' of undefined
The code was staring at me the full time. I added the below piece of code and its now working:
scope.$watch(
() => {
return daypartingCtrl.daypartingOninit;
},
(daypartingOninit : boolean) => {
if (daypartingOninit === true) {
scope.$ctrl.getCommonTimes();
}
}
);

Angular 2+ services to angularJs

I m trying to convert Angular 2+ service and use it in angularJs project.
app/users.service.ts
import { Injectable } from '#angular/core';
#Injectable()
export class UsersService {
private users: any = [
{ id: 1, name: 'john' },
{ id: 2, name: 'jane' }
];
constructor() { }
getUsers() {
return this.users;
}
}
then I tranform it into js with rollup
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('#angular/core'), require('#angular/upgrade/static'), require('#angular/platform-browser')) :
typeof define === 'function' && define.amd ? define(['exports', '#angular/core', '#angular/upgrade/static', '#angular/platform-browser'], factory) :
(factory((global.mymodule = {}),global.ng.core,global._static,global.platformBrowser));
}(this, (function (exports,core,_static,platformBrowser) { 'use strict';
var UsersService = /** #class */ (function () {
function UsersService() {
this.users = [
{ id: 1, name: 'john' },
{ id: 2, name: 'jane' }
];
}
UsersService.prototype.getUsers = function () {
return this.users;
};
UsersService.decorators = [
{ type: core.Injectable },
];
/** #nocollapse */
UsersService.ctorParameters = function () { return []; };
return UsersService;
}());
var MyModule = /** #class */ (function () {
function MyModule(upgrade) {
this.upgrade = upgrade;
}
MyModule.decorators = [
{ type: core.NgModule, args: [{
imports: [platformBrowser.BrowserModule, _static.UpgradeModule],
declarations: [],
providers: [UsersService],
exports: []
},] },
];
/** #nocollapse */
MyModule.ctorParameters = function () { return [
{ type: _static.UpgradeModule, },
]; };
return MyModule;
}());
exports.UsersService = UsersService;
exports.MyModule = MyModule;
Object.defineProperty(exports, '__esModule', { value: true });
})));
I add downgradeInjectable to convert angular2+ service into angularJs
angular.module('users.service', [])
.factory('usersServices', downgradeInjectable(usersServices));
next I try to load it in angularJs
(function() {
'use strict';
angular.module(
'ng1.module', [
'usersServices'
]);
})();
I m missing something because it doesn't work :/
I can't find ressource to do it, all people a trying to convert ng1 service to ng2 but not the reverse.
Someone can help ?
Thank you
Instead of importing 'usersServices' (the service factory) in the module 'ng1.module', you should import the actual module with 'usersServices' in it instead:
(function() {
'use strict';
angular.module(
'ng1.module', [
'users.service'
]);
})();

Example of injecting services in Angular 1.5 components

Can anyone give an example on using services with Angular 1.5 components?
I'm trying to inject a service in an Angular 1.5 component, but it doesn't work.
I have a login component like so:
class Login {
constructor($scope, $reactive, $state, myService) {
console.log(myService.somevariable); //doesn't work
}
}
// create a module
export default angular.module(name, [
angularMeteor
]).component(name, {
templateUrl: 'imports/ui/components/${name}/${name}.html',
controllerAs: name,
controller: Login
});
My service looks like this:
angular.module(name).service("myService", function () {
this.somevariable = 'somevalue';
});
I just cant seem to be able to get the service injected in the component.What am I doing wrong?
SOLUTION:
With sebenalern's help, I got it working.
I needed a service to validate an email address using a regular expression. I did it like this:
import angular from 'angular';
import angularMeteor from 'angular-meteor';
class Validator {
validateEmail(email) {
var re = /^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return re.test(email);
}
}
const name = 'validator';
// create a module
export default angular.module(name, [
angularMeteor
])
.service("Validator", Validator);
I then injected the service like so:
import {name as Validator} from '../../../api/services/validator'
class Login {
constructor($scope, $reactive, $state, Validator) {
'ngInject';
this.$state = $state;
$reactive(this).attach($scope);
this.Validator = Validator;
}
login() {
if(this.Validator.validateEmail(this.credentials.email)) {
// email is valid.
}
}
}
const name = 'login';
export default angular.module(name, [
angularMeteor,
Validator
]).component(name, {
templateUrl: `imports/ui/components/${name}/${name}.html`,
controllerAs: name,
controller:Login
})
Hope this helps :)
So one problem I see is you should be using the keyword this inside the constructor
this.$scope = $scope;
Another thing it is probably easier to stay away from classes and use functions:
class Login {
constructor($scope, $reactive, $state, myService) {
console.log(myService.somevariable); //doesn't work
}
}
Becomes:
angular
.module('name')
.service('myService', myService);
function myService () {
this.somevariable = 'somevalue';
}
To me it seems a lot cleaner. Also another thing about ES6 classes is
ES6 Classes are not hoisted, which will break your code if you rely on hoisting
For more info see link.
Now here is the working code I came up with:
First we declare the module:
angular.module('name', []);
Next we register our service and then create the service definition:
angular
.module('name')
.service('myService', myService);
function myService () {
this.somevariable = 'somevalue';
}
Next we do the same procedure for our controller and also we inject $scope and our service into it.
angular
.module('name')
.controller('Login', Login);
function Login($scope, myService) {
$scope.someVar = myService.somevariable;
}
Last I registered our component:
angular
.module('name')
.component('my-html', {
templateUrl: 'my-html.html',
controller: Login
});
And that is it on the javascript side.
Here is my html code:
<!DOCTYPE html>
<html lang="en-us" ng-app='name'>
<head>
<script src="//code.angularjs.org/1.5.0-rc.1/angular.js"></script>
<script src="controller.js"></script>
</head>
<body >
<h ng-controller="Login">{{ someVar }}</h>
</body>
</html>
I hope this helps!!
Here is how I am doing it and it works well. It works fine with classes. I assume you are using TypeScript.
class AdminHomeService {
consignment: IConsignment;
get: () => IConsignment;
constructor() {
this.consignment = new Consignment();
this.consignment.id = 10;
this.consignment.customer = "Customer3";
this.consignment.customerList = [{ id: 1, name: "Customer1" }, { id: 2, name: "Customer2" }, { id: 3, name: "Customer3" }];
this.consignment.shipperList = [{ key: "1", value: "Shipper1" }, { key: "2", value: "Shipper2" }, { key: "3", value: "Shipper3" }];
this.consignment.consigneeList = [{ key: "1", value: "Consignee1" }, { key: "2", value: "Consignee2" }, { key: "3", value: "Consignee3" }];
this.consignment.billingList = [{ key: "1", value: "Billing1" }, { key: "2", value: "Billing2" }, { key: "3", value: "Billing3" }];
this.consignment.carrierList = [{ key: "1", value: "Carrier1" }, { key: "2", value: "Carrier2" }, { key: "3", value: "Carrier3" }];
this.get = () => {
return this.consignment;
}
}
}
class AdminHomeComponentController {
consignment: IConsignment;
selectedCustomer: any;
static $inject = ["adminHomeService"];
constructor(private adminHomeService: AdminHomeService) {
this.consignment = new Consignment();
this.consignment = this.adminHomeService.get();
this.selectedCustomer = {};
this.selectedCustomer.selected = { "name": this.consignment.customer };
}
customerAddClick(): void {
}
}
class AdminHomeComponent implements ng.IComponentOptions {
bindings: any;
controller: any;
templateUrl: string;
$routeConfig: angular.RouteDefinition[];
constructor() {
this.bindings = {
textBinding: "#",
dataBinding: "<",
functionBinding: "&"
};
this.controller = AdminHomeComponentController;
this.templateUrl = "templates/admin.home.html";
//this.$routeConfig = [
// { path: "/admin", name: "AdminHome", component: "adminHome", useAsDefault: true }
//];
}
}
angular.module("adminHome", [])
.component("adminHome", new AdminHomeComponent())
.service("adminHomeService", AdminHomeService);
This post helped me a lot: http://almerosteyn.com/2016/02/angular15-component-typescript

TypeScript + AngularJS directive: cannot call 'new' on class

I have some issue with declaring a class. I have the following code:
module Directive.toast{
import ToastService = Toaster.ToasterService;
'use strict';
interface IToastScope extends ng.IScope {
message:string;
display:boolean
}
class ToastDirective implements ng.IDirective {
templateUrl= '/toast.html';
restrict= 'AE';
replace= true;
scope = {
};
public message:any;
public display:boolean;
constructor(public Toast:ToastService, public $timeout:angular.ITimeoutService) {
}
link:ng.IDirectiveLinkFn = (scope:IToastScope, element:ng.IAugmentedJQuery, attributes:ng.IAttributes) => {
scope.message = this.Toast.message.text;
this.$timeout(function() {
this.message.display= false;
element.remove();
}, 5000);
};
static factory():ng.IDirectiveFactory {
return () => new ToastDirective();
}
}
var app = AppModule.getModule();
app.directive('toast', ToastDirective.factory());
}
Which gives me an error:
error TS2346: Supplied parameters do not match any signature of call target.
However, if I delete the injections from the constructor, it will pass through the compiler - but I do need to inject those dependencies, to use them in the linking functions to the directive. Any ideas?
I would do something like this;
export var ToastDirective = (public Toast:ToastService, public $timeout:angular.ITimeoutService) : angular.IDirective =>
{
return {
templateUrl: '/toast.html',
restrict: 'AE',
replace: true,
scope: {
message: "=",
display: "="
},
link: (scope: IToastScope, element:angular.IAugmentedJQuery, attributes: angular.IAttributes) => {
scope.message = Toast.message.text;
$timeout(()=> {
scope.message.display=false;
element.remove();
}, 5000);
}
}
ToastDirective.$inject = ["ToastService", "$timeout"];
var app = AppModule.getModule();
app.directive('toast', ToastDirective);
}

How to access typescript directives isolated scope value in typescript controller class?

I have a Typescript directive class and a controller class like below. I want to set a watch on isolated scope variable in the Typescript controller class. I am not able to access the isolated scope variables inside the controller class.
How can I do that?
My directive class:
module Sgm.Workspace.Web.Users {
"use strict";
export class UwAuthority implements ng.IDirective {
restrict = "E";
replace = false;
templateUrl = "/app/features/users/uwAuthority.html";
scope = {
showParameters: '=showParameters'
};
controller = UwAuthorityController;
//controllerAs = "vm";
link(scope: ng.IScope, element: ng.IAugmentedJQuery, attr: ng.IAttributes, controller: UserParametersController): void {
}
static instance(): ng.IDirective {
return new UwAuthority();
}
}
angular.module("workspaceApp")
.directive("showUwAuthority", UwAuthority.instance)
.controller("UwAuthorityController", ['userService', '$scope', (userService: Sgm.Workspace.Web.Services.IUserService, $scope: ng.IScope) => new UwAuthorityController(userService, $scope)]);
}
and my controller class is
module Sgm.Workspace.Web.Users {
export interface IUwAuthorityController {
loadFinancingType(): void;
}
export class UwAuthorityController implements IUwAuthorityController {
public modernBrowsers: any = [];
public outputBrowsers: any = [];
public localLang: any = [];
public showParameters: boolean;
static $inject = ['userService', '$scope'];
constructor(
private userService: Services.IUserService,
private $scope: ng.IScope) {
var vm = this;
var a = this.showParameters;
this.loadFinancingType();
this.$scope.$watch(() => this.showParameters, (oldValue: string, newValue: string) => {
console.log("showParameters")
});
this.$scope.$watch(() => this.outputBrowsers, (oldValue: string, newValue: string) => {
this.tellmeItChanged(oldValue, newValue);
});
}
public loadFinancingType = (): void => {
this.modernBrowsers = [{
name: "JUMBO 5/1 LIBOR ARM EVERBANK",
ticked: false
}];
this.localLang = {
selectAll: "All",
selectNone: "None",
reset: "Reset",
search: "Search...",
nothingSelected: "Select"
}
}
private tellmeItChanged(oldValue: string, newValue: string) {
if (oldValue !== newValue) {
if (this.outputBrowsers.length > 1) {
document.getElementById('plan').childNodes[0].childNodes[0].nodeValue = this.outputBrowsers.length + ' Selected';
}
}
}
}
}
We can create interface for our isolated scope and pass it into controller:
// the custom scope interface
export interface IUwAuthorityScope extends ng.IScope
{
showParameters: boolean;
}
// the controller interface
export interface IUwAuthorityController
{
loadFinancingType(): void;
}
export class UwAuthorityController implements IUwAuthorityController
{
// here we inform compiler, that injected '$scope' will be of
// our custom type - IUwAuthorityScope
constructor(
private userService: Services.IUserService,
private $scope: IUwAuthorityScope)
{
...
// here we can watch whatever we expect to be in the $scope
this.$scope.$watch("showParameters", showParms => {
// here we can access fully type $scope variables
if(this.$scope.showParameters === true) ...
});
}
...
I did follow your advise here but I keep having this error:
Error: [$injector:unpr] Unknown provider: IUwAuthorityScopeProvider <- $scope

Resources