Find element not found in AngularJS - 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.

Related

AngularJS - Cannot access ng-click in component when $compile is used

I have a normal JS file that contains some utility functions. One of these utility functions are to return the AngularJS component <tooltip>. I know that this is not very good coding practice, but this is what I have to work with. I have one problem:
onClickDescription() does not trigger when I click on the <p>. It however gets triggered by $onInit().
utility.js
function getTooltipHtml($compile, $scope) {
const scope = $scope.$new();
scope.description = getDescription();
const html = '<tooltip description="{description}"></tooltip>';
const element = $compile(angular.element(html))(scope);
scope.$apply();
return element.html();
}
tooltip.js
class Tooltip {
$onInit() {
this.onClickDescription();
}
onClickDescription() {
console.log('onClickDescription()');
}
}
export default {
bindings: {
description: '<'
}
}
tooltip.html
<div class="tooltip">
<p ng-click="$ctrl.onClickDescription()">{{ $ctrl.description }}</p>
</tooltip>

Angular & Typescript: Controller scope not defined

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 =.

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.

Pass function to directive

Here is my directive:
module app.directives {
interface IDmDeleteIconController {
doAction(): void;
}
class DmDeleteIconController implements IDmDeleteIconController {
static $inject = ['$scope'];
constructor(public $scope:any) {
}
doAction() {
console.log('1');
this.$scope.dmAction();
}
}
export class DmDeleteIcon implements ng.IDirective {
templateUrl = './app/common/directives/deleteIcon/deleteIcon.html';
controller = DmDeleteIconController;
controllerAs = 'dmDeleteIconVm';
scope = {
dmAction: '&'
};
link = (scope: any, element: ng.IAugmentedJQuery, attrs: ng.IAttributes, ctrl: any) => {
console.log('2');
scope.dmAction();
}
static factory(): ng.IDirectiveFactory {
const directive = () => new DmDeleteIcon();
directive.$inject = [];
return directive;
}
}
angular.module('myApp').directive('dmDeleteIcon', DmDeleteIcon.factory());
}
Here I am trying to use it:
dm-delete-icon(dm-action="console.log('hello');")
When I am open page I'll get 2 in the console (from link function), but I don't get the hello from the function I have passed to directive.
Why and how can I fix it?
Update:
Here is a directive template:
a.item-detail-delete-icon(class="form-image-link" href="" ng-click="dmDeleteIconVm.doAction()")
Here is HTML to which my Jade compile:
<dm-delete-icon dm-action="console.log('hello');"></dm-delete-icon>
Update 2:
I was trying to use it like this:
<dm-delete-icon dm-action="vm.foo()"></dm-delete-icon>
where:
foo(): void {
console.log("hello");
}
the function in the controller.
Update 3:
If I am trying to debug this code I will get this:
The problem here is that you're passing to the directive an expression console.log('hello'); that will be executed on parent controller scope.
This basically means you'd need to have console object attached to scope and under that object a method log. Angular expressions don't work with globals (console in this case) automatically.
Simply ensure that the expression you pass to the directive is a valid angular expression and that should work. For example - create new method on app scope called myConsoleLog that prints something to the console and change the attribute value for the directive to dm-action="myConsoleLog();"

Resources