AngularJS+Typescript - Controller inside a directive - javascript

I am trying to add put my whole class containing the controller inside my directive, put for some obvious reasons scope and syntax is incorrect.
I am using typescript as language and grunt-ts for the automatic generation and compiling.
/// <reference path="../reference.ts" />
directives.directive('myDirective', function ():ng.IDirective {
return {
restrict: 'EAC',
template: directiveHTML.html, \\ thanks to grunt-ts this work fine
controller: MyControllerClass, \\ here I get the error and here I would like to
put my own controller class instead of a function
link: function (scope, elements, attrs) {
}
}
});
and here the class of my controller
module Controllers {
export class CursorController {
constructor($scope, socket){
}
}
}
Where all the controller are then added to the controllers module of angularJS (references are generated automatically by grunt-td).
/// <reference path="../reference.ts" />
angular.module('controllers',[]).controller(Controllers);
Any clue or suggestion on how to solve this problem would be great.

You should be able to do :
directives.directive('myDirective', function ():ng.IDirective {
return {
restrict: 'EAC',
template: directiveHTML.html, \\ thanks to grunt-ts this work fine
controller: Controllers.CursorController, \\ Lookup controller by name
link: function (scope, elements, attrs) {
}
}
});

I'd suggest something like this:
export class MyDirective implements ng.IDirective {
public injection(): Array<any> {
return [
() => { return new MyDirective() }
]
}
public replace: boolean = true;
public controller = () => {
console.log('trying');
}
}
And here:
angular.module('myApp', []).directive('myDirective', MyDirective.prototype.injection())

Related

Angular Directive to component angular 1.5

I have this directive, that i would like to make a component
angular.module('app')
.directive('year', function () {
var controller = ['$scope', function ($scope) {
$scope.setYear = function (val) {
$scope.selectedyear = val;
}
}];
return {
restrict: 'E',
controller: controller,
templateUrl: "views/year.html"
};
});
This is what I got so far:
angular.module('app')
.component('year', {
restrict: 'E',
controller: controller,
templateUrl: "views/year.html"
});
I am not sure how to move my var controller into .component
There are few things you should do convert your directive to component
There is no restrict property for component as it is restricted to elements only.
For controller you could just set as you did at directive declaration but outside of it.
Controllers for components use controllerAs syntax as default so get rid of $scope
So your component should look like this...
angular.module('app')
.component('year', {
controller: ComponentController,
templateUrl: "views/year.html"
});
function ComponentController(){
var $ctrl = this;
$ctrl.setYear = function (val) {
$ctrl.selectedyear = val;
}
}
Your component should look like this:
function YearController() {
var $ctrl = this;
$ctrl.setYear = function (val) {
$ctrl.selectedyear = val;
}
}
angular.module('app').component('year', {
templateUrl: 'views/year.html',
controller: YearController
});
For more details, please read the following Stack Overflow question for more deatils:
Angular 1.5 component vs. old directive - where is a link function?
and the official documentation:
https://docs.angularjs.org/guide/component
Also, please note that components are restricted to elements only by default.

AngularJs + typescript directives dependency injection

I trie to implement a new directive in my app. Directive's code :
module Myapp.NV.Directives {
export interface placeHolderScope extends ng.IScope {
txt: string;
}
/**
* PlaceHolder
*
* #class
* #classdesc This directive is use to simulate placeholder HTML5 attributes
*/
export class PlaceHolder implements IDirective {
static $inject = ['$log','$timeout'];
constructor($log: ng.ILogService, $timeout: ng.ITimeoutService) {
var txt;
var directive: any = {
restrict: "A",
scope: { txt: "#ngPlaceholder" },
link: function (scope: placeHolderScope, elem: ng.IAugmentedJQuery, attrs: ng.IAttributes, $log: ng.ILogService, $timeout: ng.ITimeoutService) {
console.log($log);
console.log($timeout);
}
}
return directive;
}
}
}
Myapp.NV.registerDirective('PlaceHolder', ['$log', '$timeout']);
My probleme is log and timeout are always undefined...
static $inject = ['$log','$timeout'];
Won't work...
The code for registerDirective function :
export function registerDirective(className: string, services = []) {
var directive = className[0].toLowerCase() + className.slice(1);
services.push(() => new Myapp.NV.Directives[className]());
angular.module('Myapp.NV.Directives').directive(directive, services);
}
Thanks for help me :)
As boindill points out in the original answer, dependencies are injected through the TypeScript constructor, not through the link function.
This is my solution, myDirective depends on myService:
export class MyDirective implements ng.IDirective {
static $inject = ["myService"];
constructor(private myService: IMyService) {
}
restrict = "A";
scope = {};
link = (scope: IMyScope, element: ng.IAugmentedJQuery, attributes: ng.IAttributes) => {
// directive implementation
// Access myService through 'this.myService'.
};
}
Register the directive in Angular the following way. Here ng.IDirectiveFactory is implemented as an anonymous function:
angular.module("app", []).directive("myDirective", (myService: IMyService) => {
return new MyDirective(myService);
});
Here the Angular dependency injection works because it recognizes the constructor parameter names (myService).
To make sure dependency injection still recognizes the dependencies when the generated JavaScript is minified the static $inject property provides their names in a string array. Just as with plain JavaScript, make sure the constructor parameters and the $inject array members are in the same order.
You cannot inject dependencies in the link function of a directive. The link function has a fixed signature function link(scope, element, attrs) { ... } this is taken from the official angularjs documentation.
What you is to define a controller for your directive and inject the dependencies into the controller. Afterwards just use this controller function.

Use controller generated by typescript in angular directive

I have an angular controller (generated by typescript):
class FileManagerController {
...
constructor($scope) {
$scope.vm = this;
...
}
...functions...
}
How can I use this controller in the directive?
var myApp = angular.module('myApp', ])
.directive('ngFilemanager', function () {
return {
restrict: 'EA',
require: '^ngModel',
scope: {
ngModel: '='
},
templateUrl: '/templates/filemanager.html',
controller: ???
}
});
If the TypeScript class is not declared in a module, it would be as simple as:
....
controller: FileManagerController,
...
If you take a look at the Javascript compiled output of FileManagerController, you will find the function.

AngularJS communication between controller and directive

How to get some data from controller and use it inside directive thats not a problem.
But I stack with such situation when I need get data from directive and use it in my controller.
For exmpl:
My controller:
function MyController($scope, $location, myDirective) {
"use strict";
// here i need use scope.importantValue and create() method from directive
}
My directive:
.directive("myDirective", function() {
"use strict";
return {
restrict: 'A',
template: '<div></div>',
replace: true,
scope: {
data: '=',
},
link: function(scope, elm) {
scope.importantValue = "value";
function create() {
console.log("Directive works...");
}
};
})
How I can use variables or/and methods from directive inside my controller?
The simplest way to accomplish this is to make both your controller and directive get importantValue and create() from a service.
angular.module(/* Your module */).service('sharedData', function () {
return {
importantValue: "value",
create: function () {
console.log("Directive works...");
}
};
});
Now you can inject sharedData into your directive and controller and access importantValue and create() from either place.

How to require a controller in an angularjs directive

Can anyone tell me how to include a controller from one directive in another angularJS directive.
for example I have the following code
var app = angular.module('shop', []).
config(['$routeProvider', function ($routeProvider) {
$routeProvider.when('/', {
templateUrl: '/js/partials/home.html'
})
.when('/products', {
controller: 'ProductsController',
templateUrl: '/js/partials/products.html'
})
.when('/products/:productId', {
controller: 'ProductController',
templateUrl: '/js/partials/product.html'
});
}]);
app.directive('mainCtrl', function () {
return {
controller: function ($scope) {}
};
});
app.directive('addProduct', function () {
return {
restrict: 'C',
require: '^mainCtrl',
link: function (scope, lElement, attrs, mainCtrl) {
//console.log(cartController);
}
};
});
By all account I should be able to access the controller in the addProduct directive but I am not. Is there a better way of doing this?
I got lucky and answered this in a comment to the question, but I'm posting a full answer for the sake of completeness and so we can mark this question as "Answered".
It depends on what you want to accomplish by sharing a controller; you can either share the same controller (though have different instances), or you can share the same controller instance.
Share a Controller
Two directives can use the same controller by passing the same method to two directives, like so:
app.controller( 'MyCtrl', function ( $scope ) {
// do stuff...
});
app.directive( 'directiveOne', function () {
return {
controller: 'MyCtrl'
};
});
app.directive( 'directiveTwo', function () {
return {
controller: 'MyCtrl'
};
});
Each directive will get its own instance of the controller, but this allows you to share the logic between as many components as you want.
Require a Controller
If you want to share the same instance of a controller, then you use require.
require ensures the presence of another directive and then includes its controller as a parameter to the link function. So if you have two directives on one element, your directive can require the presence of the other directive and gain access to its controller methods. A common use case for this is to require ngModel.
^require, with the addition of the caret, checks elements above directive in addition to the current element to try to find the other directive. This allows you to create complex components where "sub-components" can communicate with the parent component through its controller to great effect. Examples could include tabs, where each pane can communicate with the overall tabs to handle switching; an accordion set could ensure only one is open at a time; etc.
In either event, you have to use the two directives together for this to work. require is a way of communicating between components.
Check out the Guide page of directives for more info: http://docs.angularjs.org/guide/directive
There is a good stackoverflow answer here by Mark Rajcok:
AngularJS directive controllers requiring parent directive controllers?
with a link to this very clear jsFiddle: http://jsfiddle.net/mrajcok/StXFK/
<div ng-controller="MyCtrl">
<div screen>
<div component>
<div widget>
<button ng-click="widgetIt()">Woo Hoo</button>
</div>
</div>
</div>
</div>
JavaScript
var myApp = angular.module('myApp',[])
.directive('screen', function() {
return {
scope: true,
controller: function() {
this.doSomethingScreeny = function() {
alert("screeny!");
}
}
}
})
.directive('component', function() {
return {
scope: true,
require: '^screen',
controller: function($scope) {
this.componentFunction = function() {
$scope.screenCtrl.doSomethingScreeny();
}
},
link: function(scope, element, attrs, screenCtrl) {
scope.screenCtrl = screenCtrl
}
}
})
.directive('widget', function() {
return {
scope: true,
require: "^component",
link: function(scope, element, attrs, componentCtrl) {
scope.widgetIt = function() {
componentCtrl.componentFunction();
};
}
}
})
//myApp.directive('myDirective', function() {});
//myApp.factory('myService', function() {});
function MyCtrl($scope) {
$scope.name = 'Superhero';
}

Categories