Stuck creating a custom css style directive - angularjs

For an only visual editor I'm trying to create a new directive that writes a CSS style. I'm stuck at trying to get the directive to update when a checkbox is clicked to make the background-color property transparent.
Here's my (non-working) directive:
myApp.directive('customstyle', function () {
return {
restrict: 'E',
link: function (scope, element, attrs) {
var bgColor;
scope.$watch(attrs.myTransparent, function (value) {
if (value) {
bgColor = 'transparent';
} else {
bgColor = attrs.myBgcolor;
}
updateStyle();
}, true);
function updateStyle() {
var htmlText = '<style>.' + attrs.myClass + '{';
htmlText += 'background-color: ' + bgColor + ';';
htmlText += "}</style>";
element.replaceWith(htmlText);
}
updateStyle();
}
}
});
and html element:
<customstyle my-class="examplediv" my-transparent="settings.Window.Transparent" my-bgcolor="settings.Window.BackgroundColor"></customstyle>
Here's a jsfiddle of the situation: http://jsfiddle.net/psinke/jYQc6/
Any help would be greatly appreciated.

Try using the directive directly on the element you want to change, it's easier to do and to maintain.
HTML:
<div class="examplediv customstyle"
my-transparent="settings.Window.Transparent"
my-bgcolor="{{settings.Window.BackgroundColor}}">
</div>
Note: Use {{settings.Window.BackgroundColor}} to pass the property's value and not a String.
Directive:
myApp.directive('customstyle', function () {
return {
restrict: 'AC',
link: function (scope, element, attrs) {
scope.$watch(attrs.myTransparent, function (value) {
element.css('background-color', (value ? 'transparent' : attrs.myBgcolor));
});
}
}
});
Note: Use element.css() to change CSS properties directly on the element.
jsFiddler: http://jsfiddle.net/jYQc6/8/

I was having the same problem and using bmleite's solution solved it. I had a custom element with a custom attribute very similar to the one above, and changing the directive to be applied on a regular DIV instead of the custom attribute fixed it for me.
In my solution I also have the following line of code right after the element has been modified:
$compile(element.contents())(scope);
Remember to inject the $compile service in the directive function declaration:
myApp.directive('directiveName', function ($compile) { ...
Thanks for a great post!

Related

addClass() doesn't work with getElementById in AngularJS

I'm trying to manipulate an element class within a directive. The directive is of a toolbar and it's supposed to add a class to 2 elements after some scroll.
The element directive itseld;
The view, to add/remove margin;
This is my html structure:
<ag-toolbar class="ag-toolbar--sec"></ag-toolbar>
<div ui-view="app" autoscroll="false" id="appView"></div>
And this is my directive:
function agToolbar($window) {
return {
restrict: 'E',
link: function(scope, element, attrs) {
var elView;
setTimeout(function(){
elView = document.getElementById("appView");
}, 400);
angular.element($window).bind("scroll", function() {
if (this.pageYOffset >= 128) {
element.addClass('scroll');
elView.addClass('agMargin');
} else {
element.removeClass('scroll');
elView.removeClass('agMargin');
};
});
}
};
}
In the console I keep getting the error:
elView.addClass is not a function
elView.removeClass is not a function
But the element.addClass is working fine. Any ideas why?
addClass belongs to jqLite (or jQuery if available), see https://docs.angularjs.org/api/ng/function/angular.element.
That is, you need to wrap the DOM element in a jqLite/jQuery element:
elView = angular.element(document.getElementById("appView"));

angularjs directive - get element bound text content

How do you get the value of the binding based on an angular js directive restrict: 'A'?
<span directiverestrict> {{binding}} </span>
I tried using elem[0].innerText but it returns the exact binding '{{binding}}' not the value of the binding
.directive('directiverestrict',function() {
return {
restrict:'A',
link: function(scope, elem, attr) {
// I want to get the value of the binding enclosed in the elements directive without ngModels
console.log(elem[0].textContent) //----> returns '{{binding}}'
}
};
});
You can use the $interpolate service, eg
.directive('logContent', function($log, $interpolate) {
return {
restrict: 'A',
link: function postLink(scope, element) {
$log.debug($interpolate(element.text())(scope));
}
};
});
Plunker
<span directiverestrict bind-value="binding"> {{binding}} </span>
SCRIPT
directive("directiverestrict", function () {
return {
restrict : "A",
scope : {
value : '=bindValue'
},
link : function (scope,ele,attr) {
alert(scope.value);
}
}
});
During the link phase the inner bindings are not evaluated, the easiest hack here would be to use $timeout service to delay evaluation of inner content to next digest cycle, such as
$timeout(function() {
console.log(elem[0].textContent);
},0);
Try ng-transclude. Be sure to set transclude: true on the directive as well. I was under the impression this was only needed to render the text on the page. I was wrong. This was needed for me to be able to get the value into my link function as well.

modifying ng-class from directive

I'm trying to write a directive that watches an element's width, and conditionally sets an ng-class variable. Not quite sure if I'm going about this the right way and would appreciate some help! My html
<div ng-class="{'compact' : compact}" calc-width>stuff here</div>
My directive (so far)
app.directive('calcWidth', function() {
return {
restrict: 'A',
link: function(scope, elem, attrs) {
var width = elem[0].clientWidth;
scope.compact = false;
if (width < 600) {
scope.compact = true;
}
},
};
});
Firstly, this isn't modifying the ng-class variable as expected. Secondly, how do I go about 'watching' for changes in the element's width? Normally I could just use the window resize function, but the element's size also changes in other cases such as side panels opening. Should I even be doing this? Or would it be best to somehow trigger this directive from another directive/controller/service which controls the panels?
You need to wrap the contents of your link function inside a $watch function.
link: function(scope, elem, attrs) {
scope.$watch(function () { // this function will be executed for each digest cycle.
var width = elem[0].clientWidth;
scope.compact = false;
if (width < 600) {
scope.compact = true;
}
})
}

How can I add this directive to my application?

I would like to try using this directive:
appModule.directive('scrollpane', function ($compile) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
element.addClass('scroll-pane');
element.jScrollPane();
var api = element.data('jsp');
scope.$watch(function () { return element.find('.' + attrs.scrollpane).length }, function (length) {
api.reinitialise();
});
}
};
});
I think I already correctly added the jQuery and other scripts. Can someone tell me how I would call this?
Assuming you want to use this on a DIV:
<div scrollpane>Contents...</div>
The restriction to 'A' means you want to use your directive as an attribute.
I'm assuming that the appModule is your main module.
You can see on line 3 that this directive is restrict to an attribute (restrict: 'A').
So, all you have to do is create a html element with this attribute.
<div scrollpane></div>

How to write an Angular directive for input and contenteditable

my html is taking input in two form, input and contenteditable div . I want to write one directive that handles both, but I cannot find a way to figure out which tag has called the function (because Angular's JQLite doesnt provide a is() or get() function). The following code will be complete if I can figure out to evaluate IS_INPUT_TAG:
function funct() { return {
require: 'ngModel',
link: function(scope, element, attrs, ctrl) {
// view -> model
element.bind('input', function() {
scope.$apply(function() {
if(IS_INPUT_TAG)
ctrl.$setViewValue(element.val());
else
ctrl.$setViewValue(element.text());
scope.watchCallback(element.attr('data-ng-model'));
});
});
// model -> view
ctrl.$render = function() {
if(IS_INPUT_TAG)
element.val(ctrl.$viewValue);
else
element.text(ctrl.$viewValue);
};
}};
}
app.directive('input', funct);
app.directive('contenteditable', funct);
In your directive, you can make use of the element parameter of the linking function to identify the tag on which the directive is applied. You can then use that in your IF condition as follows:
ctrl.$render = function() {
var tagname = element["0"].tagName;
if(tagName === "INPUT")
element.val(ctrl.$viewValue);
else
element.text(ctrl.$viewValue);
};
After, this you can simply attach the directive to the input and the div tags as an attribute to the tags to identify the tag to which the directive is applied.

Resources