Angular & Typescript: Controller scope not defined - angularjs

I have an angular 1.5 app with Typescript that looks like this:
mymodule.module.ts:
angular.module('mymodule', []).component('mycomponent', new MyComponent());
mycomponent.component.ts
export class MyController {
public authorized: boolean;
constructor() {
this.authorized = false;
}
}
export class MyComponent implements ng.IComponentOptions {
controller = MyController;
controllerAs = 'vm';
templateUrl = $partial => $partial.getPath('mytemplate.html');
}
mytemplate.html
...
<div ng-show="vm.authorized">
...
</div>
...
The problem is, that vm and vm.authorized is not recognized in mytemplate.html. The div is always shown. What am I doing wrong?

Your HTML seems incorrectly defined.
Should be ng-show="vm.authorized" instead of ng-show:"vm.authorized".
Note the =.

Related

Find element not found in AngularJS

I have component in AngularJS and a template which looks something like the following
Template
<div id="{{ $ctrl.idName }}"></div>
And the component controller looks something like this
Component controller
export class SomeCtrl {
idName: string = "idName";
constructor(public $element) {
}
$postLink(): void {
const divElement = this.$element.find(`#${ this.idName }`);
console.log(divElement); //divElement is undefined
}
}
For some reason divElement becomes undefined, however if I write the name in the template as following
<div id="idName"></div>
Then the element is found. My assumption that it was due to template hasn't finished compiling. But it seems not because of that either since the $postLink() method is fired when compiling is finished according to the following article ThoughtRam - Exploring Angular 1.5: Lifecycle Hooks
Enclose the find in a $timeout:
export class SomeCtrl {
idName: string = "idName";
constructor(public $element, public $timeout) {
}
$postLink(): void {
this.$timeout( _ => {
const divElement = this.$element.find(`#${ this.idName }`);
console.log(divElement);
});
}
}
This will allow the AngularJS framework and the browser time to render the interpolation.

angularJS ES6 Directive

I am trying to develop an application in angular es6 . I have a problem with directve.
Here is my code
export default class RoleDirective {
constructor() {
this.template="";
this.restrict = 'A';
this.scope = {
role :"#rolePermission"
};
this.controller = RoleDirectiveController;
this.controllerAs = 'ctrl';
this.bindToController = true;
}
// Directive compile function
compile(element,attrs,ctrl) {
console.log("df",this)
}
// Directive link function
link(scope,element,attrs,ctrl) {
console.log("dsf",ctrl.role)
}
}
// Directive's controller
class RoleDirectiveController {
constructor () {
console.log(this.role)
//console.log("role", commonService.userModule().getUserPermission("change_corsmodel"));
//$($element[0]).css('visibility', 'hidden');
}
}
export default angular
.module('common.directive', [])
.directive('rolePermission',[() => new RoleDirective()]);
The problem is i couldn't get the role value inside constructor.
here is my html implementation
<a ui-sref="event" class="button text-uppercase button-md" role-permission="dfsd" detail="sdfdsfsfdssd">Create event</a>
If i console this it will get the controller object. But it will not get any result while use this.role.
Ok, so I managed to find out how this works.
Basically, the scope values cannot be initialized on the controller's constructor (because this is the first thing executed on a new object) and there is also binding to be considered.
There is a hook that you can implement in your controller that can help you with your use case: $onInit:
class RoleDirectiveController {
constructor () {
// data not available yet on 'this' - they couldn't be
}
$onInit() {
console.log(this.role)
}
}
This should work. Note that this is angular1.5+ way of doing things when not relying on $scope to hold the model anymore. Because if you use the scope, you could have it in the controller's constructor (injected).

Typescript + Angular 1.x, directive w/ require:'^someCtrl' failing with 'unknown provider'

Using Angular with Typescript. I have a Tabs controller based on Angular Bootstrap UI tabs that works in pure Angular, but when I move it over to our Typescript style, I can't get one directive (OneTab) to find the controller for the (parent) directive (TabSet).
ERROR: Unknown provider: tabProvider <- tab
I've tried a bunch of different ways of doing this but none of them make it work properly like the non-Typescript version does.
Ex: Angular-only Plunker
We're using a modular model, which is tied together with a config file each for directives, controllers, etc. This structure is working fine except for this tab directive experiment.
module app.directives {
'use strict';
angular.module('app')
.directive('tabSet', ()=> new TabSet())
.directive('oneTab', ()=> new OneTab())
;
}
module app.directives {
interface ITabScope extends ng.IScope {
active:boolean;
}
export class OneTab implements ng.IDirective {
priority = 0;
restrict = 'E';
transclude = true;
require = '^tabsetCtrl';
scope = {
heading: '#'
};
template = '<div role="tabpanel" ng-transclude ng-show="active"></div>';
link = function (scope:ITabScope, element:ng.IAugmentedJQuery, attr:ng.IAttributes, tabsetCtrl:any) {
scope.active = false;
tabsetCtrl.addTab(scope);
}
}
}
module app.directives {
import TabSetController = app.controllers.TabSetController;
export class TabSet implements ng.IDirective{
priority = 0;
restrict = 'E';
transclude = true;
scope = {};
templateUrl = 'layout/tabset.html';
controller = TabSetController;
controllerAs = 'tabsetCtrl';
bindToController = true;
}
}
module app.controllers {
'use strict';
export class TabSetController {
tabs:Array<any>;
tab:any;
selectedTab:any;
constructor(tab:any, selectedTab:any) {
this.tabs = [];
this.addTab(tab);
this.select(selectedTab);
console.log("in constructor");
}
addTab(tab?:any) {
if(tab){
this.tabs.push(tab);
if (this.tabs.length === 1) {
tab.active = true
}
}
};
select(selectedTab?:any) {
if (selectedTab){
angular.forEach(this.tabs, function (tab:any) {
if (tab.active && tab !== selectedTab) {
tab.active = false;
}
});
selectedTab.active = true;
}
}
}
}
The issue isn't with your directives, as far as I can tell, it's with your controller class. Angular assumes that any parameters in the constructor method of a controller are services that you want to inject - seeing as you're trying to pass in parameters called tab and selectedTab, it's searching for services to inject with those names. There's no service named tab, so you get an unknown provider error.

How to pass a function to a service in TypeScript

I have a service in angular like this that calls a webapi method:
export class FormulasService extends ServiceBase{
constructor(){super();}
renameFormula(id:string, name:string):ng.IPromise<any>{
var cmd = {id:id, name:name};
return this.executeCommand('RenameFormula', cmd);
}
}
Now i have a component tha is common in all modules, so it takes a function as parameter:
export class RenameModalCtrl extends ControllerBase{
static $inject=['viewModel']
constructor(private viewModel:RenameModalModel){
super();
}
saveChanges(){
this.viewModel.serviceFunction(this.viewModel.id, this.viewModel.name);
}
}
And it's model:
export class RenameModalModel{
constructor(
public model:any,
public serviceMethod:(id:string, name:string)=>ng.IPromise<any>)
}
The view:
...
<input class="form-control" ng-model="modal.viewModel.model.name" />
<button type="submit" ng-click="modal.saveChanges()">Save Changes</button>
...
The viewModel is resolved in the resolve phase of angular.ui.bootstrap.modal.
I use the Controler-As syntax so the modal in view is the RenameModalCtrl.
rename()
{
var modalInstance = this.$modal.open({
animation: true,
controller: 'renameModalCtrl as modal',
templateUrl: 'renameModal.html',
resolve: {
viewModel: new RenameModalModel(this.itemModel, this.formulasService.renameFormula)
}
});
}
Now this all works, except in service. in the service the 'this' is the actual model, not the service. so it fails on the line: this.executeCommand('RenameFormula', cmd);
How to fix this?
Please help
Thanks
You need to use the => syntax for class methods to bind to the correct "this" reference, rewrite renameFormula like this:
renameFormula = (id: string, name: string): ng.IPromise<any> => {
var cmd = { id: id, name: name };
return this.executeCommand('RenameFormula', cmd);
}
There's more details on this here:
https://github.com/Microsoft/TypeScript/wiki/'this'-in-TypeScript

AppGyver and Angular Controllers in Typescript 1.4

I have issues with my angular controllers in AppGyver, since the constructor is never called. I am using the "controller as" syntax from angular, and I don't know if AppGyver is supporting it, since all his documentation is with the "$scope sintax", as far I see. This is my controller:
interface ILoginControllerScope extends ng.IScope {
vm: LoginController;
}
interface ILoginController {
Login(): any;
}
class LoginController implements ILoginController {
static $inject: any = ['$scope', 'supersonic', 'steroids'];
constructor(private $scope: ILoginControllerScope, private supersonic: any, private steroids: any) {
this.supersonic.logger.log('This should be called');
$scope.vm = this;
}
Login(): any {
}
static controllerId(): string {
return 'loginController';
}
}
appUsers.controller(LoginController.controllerId(), LoginController);
And this is my view:
<div ng-controller="loginController as vm" class="padding">
<div>
</div>
<div ng-hide="addonsUndefined">
<h1 class="center">Caredfor</h1>
<div class="center">
<img class="logoSize" src="/images/logo.png">
</div>
<div>
<button class="button button-block button-positive icon-left super-social-facebook" ng-click="vm.Login()">Sign in with Facebook</button>
</div>
</div>
</div>
Edit 1
The JS generated:
var LoginController = (function () {
function LoginController($scope, supersonic) {
this.supersonic = supersonic;
supersonic.logger.log('This should be called');
$scope.vm = this;
LoginController.controllerId = function () {
return 'loginController';
};
LoginController.prototype.Login = function () {
};
return LoginController;
})();
appUsers.controller(LoginController.controllerId(), LoginController);
It looks mostly good. Here are some things to try:
Press F12 in the browser, and go to the Console tab, and see if there are any errors from Angular.
Instead of this:
static $inject: any = ['$scope', 'supersonic', 'steroids'];
constructor(private $scope: ILoginControllerScope, private supersonic: any, private steroids: any) {
this.supersonic.logger.log('This should be called');
$scope.vm = this;
}
try this:
constructor() {
var i:number = 7;
}
In your browser, put a breakpoint on that line and see if it gets hit. If it does, then one at a time, put your constructor parameters back in, and see which is causing it to break. I have a suspicion that your ILoginControllerScope parameter is causing issues, because the dependency injection doesn't know how to instantiate one of those. It seems to me that you don't really need that, and you can just go with the vanilla ng.IScope instead. ILoginControllerScope isn't adding any value. Why do you need a separate class to store a reference to the controller?

Resources