How to define multiple similar directives? - javascript

I need a couple of directives performing input field cleanup and validation, just like in this question. All of them are the same except for the cleanup and validation functions themselves and the field name. Currently, I'm copying it like
angular.module('myModule')
.directive('validateFoo', function() {
return {
restrict: 'A',
require: 'ngModel',
link: function($scope, element, attrs, ngModel) {
// THESE THREE LINES SHOULD BE ARGUMENTS
var isValid = isValidFoo;
var clean = cleanFoo;
var name = "foo";
element = $(element);
var cleanAndValidate = function(x) {
var y = clean(x);
var ok = isValid(y);
ngModel.$setValidity(name, ok);
return y;
};
ngModel.$parsers.push(cleanAndValidate);
var fix = function() {
var x = element.val();
var y = clean(x);
if (x===y) return y;
var e = element[0];
var start = e.selectionStart;
var end = e.selectionEnd;
element.val(y);
var delta = y.length - x.length;
e.setSelectionRange(start + delta, end + delta);
return y;
};
element.keyup(function() {
fix();
});
}
};
})
which is obviously a bad idea. I guess I should be able to do it using a closure, but I'd also like to preserve the overall structure (all my files start with angular.module followed by a definition). If I had access to the directive name in the body, I could get the three variables from their defining object.

All of them are the same except for the cleanup and validation
functions themselves and the field name
I think you need to add a scope to your custom directive; then you can pass in the functions and field that need to be processed. Something like this:
.directive('validateFoo', function() {
return {
restrict: 'A',
require: 'ngModel',
scope : {
// DEFINE These Arguments in the scope
isvalid : "=isvalid",
clean : "=clean",
name : "=name"
}
link: function($scope, element, attrs, ngModel) {
element = $(element);
// modify this method to access your clean/isvalid/name values in the $scope
var cleanAndValidate = function(x) {
var y = $scope.clean(x);
var ok = $scope.isValid(y);
ngModel.$setValidity($scope.name, ok);
LOG name, x, y, ok
return y;
};
ngModel.$parsers.push(cleanAndValidate);
var fix = function() {
var x = element.val();
var y = clean(x);
if (x===y) return y;
var e = element[0];
var start = e.selectionStart;
var end = e.selectionEnd;
element.val(y);
var delta = y.length - x.length;
e.setSelectionRange(start + delta, end + delta);
return y;
};
element.keyup(function() {
fix();
});
}
};
})
When you use the directive, you can pass in the function and values, sort of like this:
<validate-foo isvalid="isValidFoo" clean="cleanfoo" name="foo" />

Related

AngularJS : Can't able to access scope inside call back function

Below function is being called from directive link function. My problem is, I cant able to access scope inside then function
function workerInit(scope) {
var data = scope.vm.graphData;
graphViewService.send(new WorkerData(data.node[0].id,2,data.node[0].currentEntity)).then(function(response){
postWorkerResponse(response);
//scope is not defined
})
nodesinQueue.push(data.node[0].id)
}
My factory code
app.factory("graphViewService",['$q',function($q){
var graphViewService = {};
var worker = new Worker('./app/modules/common/graphViewWorker.js');
var defer = $q.defer();
worker.addEventListener('message', function(e) {
defer.resolve(e.data);
}, false);
return {
send : function(data){
defer = $q.defer();
worker.postMessage(data); // Send data to our worker.
return defer.promise;
}
};
}])
My Directive Code(removed unnecessary function def from original)
(function () {
var app = angular.module('sureApp');
app.directive('graphView', function ($rootScope, graphViewService) {
var controller = function () {
var vm = this;
//controller code
};
var linkFunction = function (scope, elem, attrs) {
var el = angular.element(elem);
var graph = graphInit(scope, scope.vm.graphData.node[0]);
nodes = new vis.DataSet(graph.nodeList);
edges = new vis.DataSet(graph.edgeList);
var container = el.find('#network')[0];
var data = {
nodes: nodes,
edges: edges
};
network = new vis.Network(container, data, networkOptions());
networkEvents(network, scope);
new detailWindow(el, scope);
}
function graphInit(scope, node) {
var nodeList = [];
var edgeList = [];
workerInit(scope);
scope.vm.graphChips = [];
scope.vm.graphChips.push(node.currentEntity);
nodeList.push(updateNodeStructure(node, lIcons));
return {
nodeList: nodeList,
edgeList: edgeList
}
}
function workerInit(scope) {
var data = scope.vm.graphData;
WorkerData.url = data.url;
WorkerData.requestHeaders = requestConfig.headers;
graphViewService.send(new WorkerData(data.node[0].id,2,data.node[0].currentEntity)).then(function(response){
postWorkerResponse(response);
//scope is not defined
})
nodesinQueue.push(data.node[0].id)
console.time("test");
}
function WorkerData(id, level, currentEntity){
this.url = WorkerData.url
this.requestHeaders = WorkerData.requestHeaders;
this.id = id;
this.level = level;
this.currentEntity = currentEntity;
}
//removed other function def
return {
restrict: 'E',
scope: {
graphData: '=',
detailedView: '=',
mainEntity: '='
},
link: linkFunction,
controller: controller,
controllerAs: 'vm',
bindToController: true,
templateUrl: './app/modules/common/graphView.html'
};
})
}());
Can anyone help me on this?
Check by adding apply function
function workerInit(scope) {
var data = scope.vm.graphData;
graphViewService.send(new WorkerData(data.node[0].id,2,data.node[0].currentEntity)).then(function(response){
scope.$apply(function () {
postWorkerResponse(response);
//Check here able to access scope
});
});
nodesinQueue.push(data.node[0].id)
}

Angular custom directive not setting value after promise resolve

I have a custom directive, it works great when user is entering value, the problem is when loading the form, the input field is not being rendered.
Here is my directive:
var cuitModule = angular.module('cuitModule', []).directive('cuitDirective', ['$filter', function ($filter) {
return {
require: '?ngModel',
link: link,
restrict: 'E',
scope: {
cuitPlaceholder: '=placeholder'
},
templateUrl: 'js/common/directives/cuit/cuit.directive.html'
};
/*
Intended use:
<cuit-directive placeholder='prompt' model='someModel.cuit'></cuit-directive>
Where:
someModel.cuit: {String} value which to bind only the numeric characters [0-9] entered
ie, if user enters 20-33452648-9, value of 20334526489 will be bound to model
prompt: {String} text to keep in placeholder when no numeric input entered
*/
function link(scope, element, attributes, ngModel) {
// scope.inputValue is the value of input element used in template
scope.inputValue = ngModel.$viewValue;
scope.$watch('inputValue', function (value, oldValue) {
value = String(value);
var number = value.replace(/[^0-9]+/g, '');
// scope.cuitModel = number;
scope.inputValue = $filter('cuit')(number);
var valid = validarCuit(number);
ngModel.$setValidity('required', valid);
if (valid) {
ngModel.$setViewValue(number);
}
});
//source https://es.wikipedia.org/wiki/Clave_%C3%9Anica_de_Identificaci%C3%B3n_Tributaria#C.C3.B3digo_Javascript
function validarCuit(cuit) {
if (cuit.length !== 11) {
return false;
}
var acumulado = 0;
var digitos = cuit.split('');
var digito = digitos.pop();
for (var i = 0; i < digitos.length; i++) {
acumulado += digitos[9 - i] * (2 + (i % 6));
}
var verif = 11 - (acumulado % 11);
if (verif == 11) {
verif = 0;
}
return digito == verif;
}
}}]).filter('cuit', function () {
/*
Format cuit as: xx-xxxxxxxx-x
or as close as possible if cuit length is not 10
*/
return function (number) {
/*
#param {Number | String} number - Number that will be formatted as cuit number
Returns formatted number: ##-########-#
if number.length < 2: ##
if number.length < 10: ##-########
if number.length === 11: ##-########-#
*/
if (!number) {
return '';
}
number = String(number);
// Will return formattedNumber.
// If phonenumber isn't longer than an area code, just show number
var formattedNumber = number;
//Type 20, 23, 24 y 27 Personas FĂ­sicas or 30, 33 y 34 Empresas
var type = number.substring(0, 2);
var main = number.substring(2, 10);
var verifyNumber = number.substring(10, 11);
if (main) {
formattedNumber = (type + '-' + main);
}
if (verifyNumber) {
formattedNumber += ('-' + verifyNumber);
}
return formattedNumber;
};});
This is the html:
<cuit-directive placeholder="'CUIT'" ng-model='vm.merchant.idNumber' required></cuit-directive>
I am invoking it within a form of course.
I am getting the data to my controller through a rest service, so I am doing something like:
function EditMerchantCtrl($state, $ionicHistory, merchantsService, $ionicPopup, $timeout, $ionicLoading) {
var vm = this;
function init(){
merchantsService.get().then(
function(response){
vm.merchant = response.data;
});
}}
I don't know why I can't get that field populated after receiving the response from the service. Any help would be much appreciated.
You should implement the $render function of the ngModelController, try something like this:
ngModel.$render = function() {
scope.inputValue = ngModel.$viewValue;
}
Hope it helps.

Memory Leak: Remaining elements in cache and data_user in AngularJs

I create elements (some are SVG Tags, some are simple HTML) with ng-repeat. On changes of the data model - an object that is reset on arrival of new data - there are always elements left behind as detached DOM elements. They are held like this:
The Elements are part of data_user which seems to be part of jquery. This problem occurs at several places on change of data. It seems that watchers are the problem, since they are keeping reference to their expression.
The elements are created e.g. like this:
.directive('svgGraphic', ['$compile', function ($compile) {
return {
restrict: 'E',
replace: false,
link: function (scope, element, attrs) {
var svgData = scope.model.getAttribute("svgGraphic");
var svgDomElement = $(svgData.svg);
scope.layers = svgData.layers;
svgDomElement.append('<svg-layer ng-repeat="layer in layers"></svg-layer>');
element.append($compile(svgDomElement)(scope));
scope.$on("$destroy", function() {
scope.$$watchers = null;
scope.$$listeners = null;
})
}
};
}])
A workaround is to manually delete watchers and listeners as you can see above - what is no good solution I think!
When new data from the server arrives, it is set like this:
$scope.model = model;
$scope.$digest();
Is it a problem to just replace the model data?
Is there any idea how it can happen that angular does not remove listeners on old elements? Angular should delete all the watchers when ng-repeat receives new data and rebuilds all elements.
I found the same issue. I created a Watcher Class, so then with the profiler I am able to count the Watcher instances. I saw that the instances continue increasing while I navigate the app, some of the instances are retained by the data_user cache :(.
Also I fixed the delete of childScopes watcher amd added some metadata to scopes, like a list of childScope.
Here is the angular code that I changed (only the functions that I changed). I hope this help you to found the error, I am still fighting with it :)
function $RootScopeProvider() {
this.$get = ['$injector', '$exceptionHandler', '$parse', '$browser',
function($injector, $exceptionHandler, $parse, $browser) {
var watcherCount = 0;
function Watcher(listener, initWatchVal, get, watchExp, objectEquality, scope) {
this.fn = isFunction(listener) ? listener : noop;
this.last = initWatchVal;
this.get = get;
this.exp = watchExp;
this.eq = !!objectEquality;
this.scope = scope;
this.id = watcherCount++;
}
Watcher.prototype = {
constructor: Watcher
}
function Scope() {
this.$id = nextUid();
this.$$phase = this.$parent = this.$$watchers =
this.$$nextSibling = this.$$prevSibling =
this.$$childHead = this.$$childTail = null;
this.$root = this;
this.$$destroyed = false;
this.$$listeners = {};
this.$$listenerCount = {};
this.$$isolateBindings = null;
this.childsScopes = [];
}
Scope.prototype = {
constructor: Scope,
$new: function(isolate, parent) {
var child;
parent = parent || this;
if (isolate) {
child = new Scope();
child.$root = this.$root;
} else {
// Only create a child scope class if somebody asks for one,
// but cache it to allow the VM to optimize lookups.
if (!this.$$ChildScope) {
this.$$ChildScope = function ChildScope() {
this.$$watchers = this.$$nextSibling =
this.$$childHead = this.$$childTail = null;
this.$$listeners = {};
this.$$listenerCount = {};
this.$id = nextUid();
this.$$ChildScope = null;
};
this.$$ChildScope.prototype = this;
}
child = new this.$$ChildScope();
}
//window.scopes = window.scopes || {};
//window.scopes[child.$id] = child;
this.childsScopes.push(child);
child.$parent = parent;
child.$$prevSibling = parent.$$childTail;
if (parent.$$childHead) {
parent.$$childTail.$$nextSibling = child;
parent.$$childTail = child;
} else {
parent.$$childHead = parent.$$childTail = child;
}
// When the new scope is not isolated or we inherit from `this`, and
// the parent scope is destroyed, the property `$$destroyed` is inherited
// prototypically. In all other cases, this property needs to be set
// when the parent scope is destroyed.
// The listener needs to be added after the parent is set
if (isolate || parent != this) child.$on('$destroy', destroyChild);
return child;
function destroyChild() {
child.$$destroyed = true;
child.$$watchers = null;
child.$$listeners = {};
//child.$parent = null;
child.$$nextSibling = null;
child.$$childHead = null;
child.$$childTail = null;
child.$$prevSibling = null;
child.$$listenerCount = {};
if (child.$parent) {
var index = child.$parent.childsScopes.indexOf(child);
child.$parent.childsScopes.splice(index, 1);
}
console.log("Destroying childScope " + child.$id);
}
}
$destroy: function() {
// we can't destroy the root scope or a scope that has been already destroyed
if (this.$$destroyed) return;
var parent = this.$parent;
console.log('Destroying Scope '+ this.$id);
//delete window.scopes[this.$id];
this.$broadcast('$destroy');
this.$$destroyed = true;
if (this === $rootScope) return;
for (var eventName in this.$$listenerCount) {
decrementListenerCount(this, this.$$listenerCount[eventName], eventName);
}
// sever all the references to parent scopes (after this cleanup, the current scope should
// not be retained by any of our references and should be eligible for garbage collection)
if (parent.$$childHead == this) parent.$$childHead = this.$$nextSibling;
if (parent.$$childTail == this) parent.$$childTail = this.$$prevSibling;
if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling;
if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling;
// Disable listeners, watchers and apply/digest methods
this.$destroy = this.$digest = this.$apply = this.$evalAsync = this.$applyAsync = noop;
this.$on = this.$watch = this.$watchGroup = function() { return noop; };
this.$$listeners = {};
// All of the code below is bogus code that works around V8's memory leak via optimized code
// and inline caches.
//
// see:
// - https://code.google.com/p/v8/issues/detail?id=2073#c26
// - https://github.com/angular/angular.js/issues/6794#issuecomment-38648909
// - https://github.com/angular/angular.js/issues/1313#issuecomment-10378451
this.$parent = this.$$nextSibling = this.$$prevSibling = this.$$childHead =
this.$$childTail = this.$root = this.$$watchers = null;
}
}];
}
Remove the cached SVG data.
Directive Code
(function () {
"use strict";
angular.module('ApplicationModule').directive("ngD3SvgRefreshDirective", ["$rootScope", function ($rootScope) {
return {
restrict: 'AE',
templateUrl: 'pages/directive/D3SvgMyRefereshDirective.html',
scope: {
svgData: "=svgData",
reloadSvg: "=reloadSvg",
},
controller: function ($scope, $sce, $rootScope) {
$scope.$watch('reloadSvg', function (nu, old) {
$scope.init();
}, true);
$scope.init = function () {
if ($scope.svgData && $scope.svgData.layoutURI) {
console.log("data");
if ($scope.svgData) {
// if data is present ###
var svgDiv = angular.element(document.querySelector('#svgDiv')).html("");
d3.xml($scope.svgData.layoutURI, "image/svg+xml", function (xml) {
svgDiv.append(xml.documentElement);
$scope.styleSVGPathsNaddCallBack();
});
}
}
else {
// if data is not present ###
var svgDiv = null;
// selecting all the svg div which already present in browser ###
var svg = d3.select("svg");
svg.selectAll("*").remove();
console.log(svg);
}
};
$scope.styleSVGPathsNaddCallBack = function () {
var svgObject = d3.select('#svgDiv').select('svg');
svgObject.attr("width", "100.0%");
var objColor;
if (true) {
// your requirement logic
}
};
}
};
}]);
})();
Controller
Controller and service combined. Data registery controller function.
$scope.dataRegisteryForMyDirective = function (data, dataFlag) {
if (dataFlag) {
var svgDataMaster = data;
var svgData = {};
$scope.svgData = {};
svgData.layoutURI = data.layoutURI;
$scope.svgData = angular.copy(svgDataMaster);
$rootScope.reloadSvg = !$rootScope.reloadSvg;
}
else {
// making svg data empty, so we can execute the else block of directive --> init() and remove the cached data ###
$scope.svgData = {};
$rootScope.reloadSvg = !$rootScope.reloadSvg;
}
}
Service call and data registory call for directive:
$scope.loadSvgByNumber = function (inputNumber) {
var d = inputNumber;
myService.getData(d).then(function (resp) {
if (resp.status == "FAILURE") {
$scope.svgTempData = [];
$scope.dataRegisteryForMyDirective(resp, false);
// calling to dataRegisteryForMyDirective with false flag
}
else {
$scope.dataRegisteryForMyDirective(resp, true);
// calling to dataRegisteryForMyDirective with true flag
}
});
};

How to pass functions from factory into controller angularJS

Right now I have this JS bin: http://jsbin.com/uhabed/64/ in which you can hopefully see the infite scroll loading of more images. These images are added when the page bottom is reached by the scroll bar on line 13 of the javascript:
angular.module('infinitescroll', []).directive('onScrolled', function () {
return function (scope, elm, attr) {
var el = elm[0];
elm.bind('scroll', function () {
if (el.scrollTop + el.offsetHeight >= el.scrollHeight) {
scope.$apply(attr.onScrolled);
}
});
};
}).controller("scrollCtrl", function($scope, getStuff){
$scope.data = getStuff;
$scope.loaddata = function(){
var length = $scope.data.length;
for(var i = length; i < length + 10; i ++){
$scope.data.push(i);
}
};
$scope.loaddata();
}).factory('getStuff',function($http) {
var images_list = ["www.google.com","www.facebook.com","www.supercuber.com","www.snappiesticker.com"];
images_list.addStuff = function(){ $http.get("http://jsbin.com/yehag/2").success(function(data){
var returned_list = JSON.parse(data.javascript);
console.log(returned_list);
for (var i=0;i<8;i++){
images_list.push(returned_list[i].name);
}
});
};
console.log(images_list);
return images_list;
});
I want to replace line 13 with $scope.loaddata = images_list.addStuff(); from the factory below. basically to use the $http function and add the data from that instead. images_list is already being returned properly seeing as the first 4 items in the output are the ones defined in the factory on line 21. However, the optomistic $scope.loaddata = images_list.addStuff(); doesn't seem to be working.
How can I pass this function up into the $scope.loaddata?
images_list is an array. You can't arbitrarily assign a property to it like images_list.addStuff
Create an object and return that object from the factory
factory('getStuff',function($http) {
var images_list = ["www.google.com","www.facebook.com","www.supercuber.com","www.snappiesticker.com"];
var addStuff = function(){....};
return{
images_list: images_list,
addStuff: addStuff
}
});
Then in controller:
$scope.data = getStuff.images_list;
$scope.loaddata = getStuff.addStuff
This is not a clean way of having an array-like object that has additional properties on it, however the above answer that you 'cannot add functions onto an array' is incorrect. While creating array-like objects is kind of messy and should be avoided where possible. If you feel it is absolutely necessary, I would handle it like this (this is similar to how jQuery does it.
function ImagesList($http) {
this.push.apply(this, [
"www.google.com",
"www.facebook.com",
"www.supercuber.com",
"www.snappiesticker.com"
]);
this._$http = $http;
}
ImagesList.prototype = {
push: [].push,
splice: [].splice,
pop: [].pop,
indexOf: [].indexOf,
addStuff: function () {
this._$http.get("http://jsbin.com/yehag/2").then(function(data){
var returnedList = angular.toJson(data.javascript);
for (var i=0; i<8; i++) {
this.push(returnedList[i].name);
}
}.bind(this));
}
};
angular
.module('infinitescroll', [])
.service('imageList', ImagesList);
.directive('onScrolled', function () {
return {
scope: {
onScrolled: '&'
},
link: function (scope, elm, attr) {
var el = elm[0];
// Original implementation will end up causing memory leak because
// the handler is never destroyed. Use as follows
elm.on('scroll.iScroll', function () {
if (el.scrollTop + el.offsetHeight >= el.scrollHeight) {
scope.$apply(attr.onScrolled);
}
}).on('$destroy', function () {
elm.off('.iScroll');
});
}
};
}).controller("scrollCtrl", function($scope, imageList){
$scope.data = imageList;
$scope.loaddata = function(){
var length = $scope.data.length;
for(var i = length; i < length + 10; i++){
$scope.data.push(i);
}
};
$scope.loaddata();
})

Pass scope and parameters to directive - AngularJS

I'm trying to set a class in a ng-repeat with a directive.
I need to pass a parameter to this directive: wineQty
if I use scope: { wineQty: '=' } this works however $scope.bullet1Color is undefined in my html and thus doesn't affect the class that I want.
If I use scope: '#' I get the correct class however I can't specify wineQty
Is there a way to combine theses two syntaxes? so that I can access the scope and pass a paramater?
I've tried { wineQty: '#' } but with no luck sadly.
Here's my directive
angular.module('myApp').directive('wineQtyBullets', function () {
return {
restrict: 'A',
scope: { wineQty: '=', totalBullets: '=', numRedBullets: '=', numOrangeBullets: '#', bullet1Color: '#' },
link: function (scope, element, attrs) {
// defaults
var defaultNumRedBullets = 1;
var defaultNumOrangeBullets = 2;
var defaultTotalBullets = 12;
var defaultWineQty = 0;
// set values from attributes
var numRedBullets = scope.numRedBullets ? scope.numRedBullets : defaultNumRedBullets;
var numOrangeBullets = scope.numOrangeBullets ? scope.numOrangeBullets : defaultNumOrangeBullets;
var totalBullets = scope.totalBullets ? scope.totalBullets : defaultTotalBullets;
var wineQty = scope.wineQty ? scope.wineQty : defaultWineQty;
for (var currentBullet = 1; currentBullet <= totalBullets; currentBullet++) {
var bulletColorClass = 'bg-grey';
if (currentBullet <= wineQty) {
if (currentBullet <= numRedBullets) {
bulletColorClass = 'bg-red';
}
else if (currentBullet <= (numOrangeBullets + numRedBullets)) {
bulletColorClass = 'bg-orange';
}
else {
bulletColorClass = 'bg-green';
}
}
scope["bullet" + currentBullet + "Color"] = bulletColorClass;
}
console.log(scope.bullet1Color);
}
};
}
);
Here's my html
<div class="bullets pull-left ml15 mt6" wine-qty="wine.owned_qty" wine-qty-bullets>
<ul>
<li class="bullet"
ng-class="bullet1Color"></li>
</ul>
</div>
I managed to solve the problem, by changing scope to true and accessing the parameters through attrs
If this can help anyone here's the directive:
angular.module('myApp').directive('wineQtyBullets', function () {
return {
restrict: 'A',
scope: true,
link: function (scope, element, attrs) {
var options = { };
angular.forEach([
'numRedBullets',
'numOrangeBullets',
'totalBullets',
'wineQty'
], function (key) {
if (angular.isDefined(attrs[key]))
options[key] = attrs[key];
});
// defaults
var defaultNumRedBullets = 1;
var defaultNumOrangeBullets = 1;
var defaultTotalBullets = 12;
var defaultWineQty = 0;
// set values from attributes
var numRedBullets = parseInt(options.numRedBullets) ? parseInt(options.numRedBullets) : defaultNumRedBullets;
var numOrangeBullets = parseInt(options.numOrangeBullets) ? parseInt(options.numOrangeBullets) : defaultNumOrangeBullets;
var totalBullets = parseInt(options.totalBullets) ? parseInt(options.totalBullets) : defaultTotalBullets;
var wineQty = parseInt(options.wineQty) ? parseInt(options.wineQty) : defaultWineQty;
for (var currentBullet = 1; currentBullet <= totalBullets; currentBullet++) {
var bulletColorClass = 'bg-grey';
if (currentBullet <= wineQty) {
if (wineQty <= numRedBullets) {
bulletColorClass = 'bg-red';
}
else if (wineQty <= (numOrangeBullets + numRedBullets)) {
bulletColorClass = 'bg-orange';
}
else {
bulletColorClass = 'bg-green';
}
}
scope["bullet" + currentBullet + "Color"] = bulletColorClass;
}
}
};
});
Using "=" means 2-way data binding, and it's definitely fine.
The problem might be that your link function are executed only once at the very beginning, when it's possible that the values of your attributes are not yet assigned (may be caused by some AJAX calls).
I would suggest that you wrap all your link function into a scope.$watch function. Like:
link: function (scope, element, attrs) {
scope.$watch(function() {
return {
wineQty: scope.wineQty,
totalBullets: scope.totalBullets,
numRedBullets: scope.numRedBullets,
numOrangeBullets: scope.numOrangeBullets,
bullet1Color: scope.bullet1Color
}
}, function() {
// Your original code here.
})
}
Then your final result will automatically update if your directive got new attribute values.

Categories

Resources