Can not find element in postlink of directive creation in angularjs - javascript

I am trying to create a directive for JustGauge in AngularJS. My html view is something like this:
<div id="guageContainer" class="row" ng-controller="guageCtrl">
<gauge ng-repeat="ind in indicators" model="ind"></gauge>
</div>
and my directive is:
angular.module("pgHome", [])
.directive("gauge", function ($compile) {
return {
restrict: "E",
scope: { model: "=model" },
compile: function (tElement, tAttrs, transclude) {
tElement.append('<div id="{{model.Name}}"></div>');
return {
post: function (scope, iElement, iAttrs, controller) {
console.log(scope.model.Name);
console.log($("#" + scope.model.Name).length);
var g = new JustGage({
id: scope.model.Name,
value: 348,
min: 120,
max: 400,
title: "test",
label: ""
});
}
};
}
};
});
When I load the page containing this directive, JustGauge raises an error saying that it can't find an element with corresponding id. Just to mention that the first console.log works well but the second console.log returns 0. Also I am new to angularjs and I couldn't solve this problem!

Wrap your JustGage() call in a $timeout:
.directive("gauge", function ($compile, $timeout) {
...
$timeout(function() {
var g = new JustGage({...});
});
This gives the browser a chance to render the additional HTML you added in the compile function. Then the plugin can find the newly added div.

Related

Angularjs directive duplicates the elements inside it

(function () {
'use strict';
angular.module('product')
.directive('sampledirective', ['$document') {
return {
restrict: 'E',
replace: true,
scope: {
data: '=',
btnClick: '&'
},
link: function (scope, element, attr) {
var compiled = $compile(template)(scope);
angular.element(element).replaceWith(compiled);
element = compiled;
};
};
}]);
})();
I have a directive which replaces the elements inside it.
I have a weird issue which replaces the elements mulitple time in the directive .
Duplicates the elements in the below bolded line which should not happen.
angular.element(element).replaceWith(compiled);
Please let me know why the elemenst are duplicated and let me know how to avoid it .
sample
Actual
cool cool
expected
cool
The following directive only replaces the content once in my case. If this dosn't solve your problem maybe you could provide a small working example or so. Also note that if you use an isolated scope for your directive you should provide a template, as stated in this post.
angular.module('product').directive("sampledirective", function ($compile) {
return {
template: '',
restrict: 'E',
scope: {
data: "=data",
btnClick: '&'
},
link: function (scope, element, attrs) {
var template = "<div>foo</div>"
var compiled = $compile(template)(scope);
element.replaceWith(compiled);
}
}
});

Angular directive scope is empty

I have a Directive:
var ActorDisplayDirective = function() {
return {
replace : false,
restrict : 'AE',
scope : {
actor : "="
},
templateUrl: staticContext + '/angular-app/templates/actor-display-template.html',
link : function(scope, elem, attrs) {
},
}
};
This works fine in some places, but not others. Here is my code to show it where it is not working:
<p>CAP: {{can_approve_for}}</p>
<p>
Actor display template:
<span actor-display actor='can_approve_for'></span>
After template
</p>
The CAP: ... displays the data, the directive's actor value is null. Why? My controller does:
dataFactory.getCanApproveFor().then(function(data) {
$scope.can_approve_for = data;
});
So, I am able to see the value on the page, but the directive does not show it. I'm assuming it's a timing/refresh thing, but this directive works elsewhere in ng-repeat, because the ng-repeat evaluates after hte object is already set, I guess. How do I do it in this case?
You are not actually declaring ActorDisplayDirective as a directive. Its just a plain function that returns an object that sort of looks like a directive.
You have to tell angular that it is a directive like so:
angular.module('someModule', [])
.directive('actorDisplay', function () {
return {
replace: false,
restrict: 'AE',
scope: {
actor: "="
},
templateUrl: staticContext + '/angular-app/templates/actor-display-template.html',
link: function (scope, elem, attrs) {
},
}
})

angular-bootstrap add new directive dosn't work

I want to create a new directive into ui.boostrap.accordion module to avoid accordion open click event.
I have the following code in another file.js:
angular.module('ui.bootstrap.accordion')
.directive('accordionGroupLazyOpen', function() {
return {
require: '^accordion',
restrict: 'EA',
transclude: true,
replace: true,
templateUrl: function(element, attrs) {
return attrs.templateUrl || 'template/accordion/accordion-group.html';
},
scope: {
heading: '#',
isOpen: '=?',
isDisabled: '=?'
},
controller: function() {
this.setHeading = function(element) {
this.heading = element;
};
},
link: function(scope, element, attrs, accordionCtrl) {
accordionCtrl.addGroup(scope);
scope.openClass = attrs.openClass || 'panel-open';
scope.panelClass = attrs.panelClass;
scope.$watch('isOpen', function(value) {
element.toggleClass(scope.openClass, value);
if (value) {
accordionCtrl.closeOthers(scope);
}
});
scope.toggleOpen = function($event) {
};
}
};
})
The problem is when I execute the app I get the following error:
Controller 'accordionGroup', required by directive
'accordionTransclude', can't be found!
Error link
Any ideas?
As I see from the source code ( maybe not your version but still the same):
// Use in the accordion-group template to indicate where you want the heading to be transcluded
// You must provide the property on the accordion-group controller that will hold the transcluded element
.directive('uibAccordionTransclude', function() {
return {
require: '^uibAccordionGroup', // <- look at this line in your version
link: function(scope, element, attrs, controller) {
scope.$watch(function() { return controller[attrs.uibAccordionTransclude]; }, function(heading) {
if (heading) {
element.find('span').html('');
element.find('span').append(heading);
}
});
}
};
So I guess it tries to find a parent directive in the view that matches accordionGroup but since you add the accordionGroupLazyOpen and not the accordionGroup it cannot find it.
In the error page you provided states:
This error occurs when HTML compiler tries to process a directive that
specifies the require option in a directive definition, but the
required directive controller is not present on the current DOM
element (or its ancestor element, if ^ was specified).
If you look in the accordion-group-template file you will see that the accordionTransclude directive gets called there.

AngularJS: Watch a property of the parent scope

I'm quite new to AngularJS and I'm trying to understand a few things.
First of all, I have my controller of which I will place a snippet here:
var OfficeUIRibbon = angular.module('OfficeUIRibbon');
// Defines the OfficeUIRibbon controller for the application.
OfficeUIRibbon.controller('OfficeUIRibbon', ['$scope', '$http', function($scope, $http) {
var ribbon = this;
ribbon.setApplicationMenuAsActive = function() {
ribbon.applicationMenuActive = true;
}
}
Then I have a directive:
var OfficeUIRibbon = angular.module('OfficeUIRibbon');
OfficeUIRibbon.directive('ribbonApplicationMenu', function() {
return {
restrict: 'E',
replace: false,
scope: {
data: '#'
},
templateUrl: function(element, attributes) {
return attributes.templateurl;
}
}
});
The directive is called like this:
<ribbon-application-menu templateUrl="/OfficeUI.Beta/Resources/Templates/ApplicationMenu.html" data="/OfficeUI.Beta/Resources/JSon/Ribbon/ribbon.json"></ribbon-application-menu>
This does all work and in my template for the directive, the following is placed:
<div id="application" id="applicationMenuHolder" ng-controller="OfficeUIRibbon as OfficeUIRibbon" ng-show="OfficeUIRibbon.applicationMenuActive"...
From inside another element, when I execute a click a function on my controller is executed:
ng-click="OfficeUIRibbon.setApplicationMenuAsActive()"
Here's the directive from the other element:
OfficeUIRibbon.directive('ribbon', function() {
return {
restrict: 'E',
replace: false,
scope: {
data: '#'
},
templateUrl: function(element, attributes) {
return attributes.templateurl;
}
}
});
This function does change the property "applicationMenuActive" on the ribbon itself, which should make the item in the directive template show up.
However, this is not working. I'm guessing I need to watch this property so the view get's updated accordingly.
Anyone has an idea on how this could be done?

How do I use a directive to set other directives?

I have an object on the scope of a controller that contains some presentation data for an input:
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.settings = {
value: 'xxx',
required: true,
show: true,
readonly: false
};
});
In the actual application, this is part of a larger object loaded from the server. I created a directive that would take this presentation object as input and attach the necessary directives:
app.directive('fieldSettings',
[/*$injectables*/
function (/*$injectables*/) {
return {
priority: 100,
restrict: 'A',
scope: {
fieldSettings: '='
},
compile: function (el, attrs) {
return function (scope, iElement, iAttrs) {
iAttrs.$set('ng-model', 'fieldSettings.value');
iAttrs.$set('ng-show', 'fieldSettings.show');
iAttrs.$set('ng-required', 'fieldSettings.required');
iAttrs.$set('ng-readonly', 'fieldSettings.readonly');
}
}
};
}
]);
As this plunk demonstrates, the attributes are added but the logic is not being applied. According to the documentation for angular, the directives I am trying to apply have a priority of 0 and the input directive has a priority of 100. I set mine to 100 but this value seems to have no affect regardless of the value I choose for it.
I want
<input field-settings="settings" />
to behave like
<input ng-model="settings.value" ng-show="settings.show" ng-required="settings.required" ng-readonly="settings.readonly" />
but literally be
<input ng-model="fieldSettings.value" ng-show="fieldSettings.show" ng-required="fieldSettings.required" ng-readonly="fieldSettings.readonly" />
where fieldSettings is the directive's local scope variable bound to the MaintCtrl's local scope variable settings.
Just adding the attributes without compiling won't do anything.
My similar answeres:
creating a new directive with angularjs
How to get ng-class with $dirty working in a directive?
Angular directive how to add an attribute to the element?
Here is a plunker: http://plnkr.co/edit/8kno6iwp3hH5CJFQt3ql?p=preview
Working directive:
app.directive('fieldSettings',
['$compile',
function ($compile) {
return {
restrict: 'A',
scope: {
fieldSettings: '='
},
priority: 1001,
terminal: true,
compile: function(tElm,tAttrs){
tElm.removeAttr('field-settings')
tElm.attr('ng-model', 'fieldSettings.value');
tElm.attr('ng-show', 'fieldSettings.show');
tElm.attr('ng-required', 'fieldSettings.required');
tElm.attr('ng-readonly', 'fieldSettings.readonly');
var fn = $compile(tElm);
return function(scope){
fn(scope);
}
}
};
}

Categories

Resources