Change background color with ng-Style - angularjs

How can i change the background color with ng-style?
this Div gonna repeat so the one of the color is from DB. For the plnkr i just fixed the colors, but in my example is like this:
<div class="col-md-offset-0 col-md-2" ng-repeat="type in types" style="margin-bottom:5px;">
<div class='container' divCheckbox ng-style="{'background-color':(isSelected?'{{type.color}}':'#ccc')}>
<input type='hidden' ng-model="type.show" />
<div class="label">{{type.name}}</div>
</div>
</div>
And the directive:
.directive('divCheckbox', function () {
return {
restrict: 'A',
link: function (scope, el, attr) {
scope.isSelected = el.find('input').val() == 'false';
el.on('click', function () {
scope.isSelected = !scope.isSelected;
scope.$apply();
});
}
}
});
Heres my plnkr: http://plnkr.co/edit/onLA8vSbtwQu1OxZrKzT?p=preview

You can't do ternary conditions within a tag and you have an error since you didn't quote background-color. You have to either quote it, or use camelCase, while the conditions should be set in the controller.
So, the fix is to have a scope variable denoting a color (or the full style object) and use it like this: http://plnkr.co/edit/iYkSa2I1ysZutdkAKkuh?p=preview
UPDATE
Here's an example you could use to make your code work with your DB (I'm calling external JSON here, but the principle is the same): http://plnkr.co/edit/Kegs95NNyGGySMDzhQed?p=preview
This way you could fetch the 'selected' color as well. That's pretty much all I can tell you with the info you provided.

Both are different styles. Use:
return {backgroundImage:'URL'};
or
return {backgroundColor:'Color'};

youse:
return {backgroundImage:'someimg'};

Related

Same Directives multiple times on a page taking last model value always

I am trying to add a copy icon beside each label to copy the text and my code is like below. I am passing the model value of each label as an input to the directive.
When I am clicking on the copy icon, always the last model value is showing why?
Isolating the scope is working . But, I would like to know whats happening internally.
Please explain in detail.
function copytext() {
var directive = {
restrict: 'EA',
template: `
<i class="imd imd-content-copy cursor-pointer"
ng-click="click()" ></i>
`,
link: function(scope, ele, attrs) {
scope.click = function() {
alert(attrs.data)
};
}
};
return directive;
}
<label>Job No</label>: {{vm.jobInfo.jobNumber}}
<copytext data="{{vm.jobInfo.jobNumber}}"></copytext>
<label>Customer </label>: {{vm.jobInfo.customerCode}}
<copytext data="{{vm.jobInfo.customerCode}}"></copytext>
<label>Reference</label>: {{vm.jobInfo.reference}}
<copytext data="{{vm.jobInfo.reference}}"></copytext>
<label>Job No</label>: {{vm.jobInfo.jobNumber}}
<copytext data="{{vm.jobInfo.jobNumber}}" onclick="<attr.data=referencevalue>"></copytext>
<label>Customer </label>: {{vm.jobInfo.customerCode}}
<copytext data="{{vm.jobInfo.customerCode}}" onclick="<attr.data=referencevalue>"></copytext>
<label>Reference</label>: {{vm.jobInfo.reference}}
<copytext data="{{vm.jobInfo.reference}}" onclick="<attr.data=referencevalue>"></copytext>
#georgeawg ,The above is just psuedo code, dont think about its syntax. The last html elements data attribute is reference, so all the above elements click handler also takes the reference.. isn't it?

Angular binding does not work in data- attribute

I am using some css html template that comes with many html components and with lots of data-attributes for various things. For example for slider it has something like
<div class="slider slider-default">
<input type="text" data-slider class="slider-span" value="" data-slider-orientation="vertical" data-slider-min="0" data-slider-max="200" data-slider-value="{{ slider }}" data-slider-selection="after" data-slider-tooltip="hide">
</div>
Here I am trying to bind the value
data-slider-value="{{ slider }}"
But it's not working. Variable 'slider' is set in the $scope as:
$scope.slider = 80;
Same value 80 shows up right when I bind it as:
<h4>I have {{ slider }} cats</h4>
I have also tried
ng-attr-data-slider-value="{{ slider }}"
It didn't work.
Update
The directive has something like this
function slider() {
return {
restrict: 'A',
link: function (scope, element) {
element.slider();
}
}
};
where element.slider(); calls the code in bootstrap-slider.js (from here) for each of the sliders.
I played with this for a while, and came up with a few options for you. See my Plunkr to see them in action.
Option 1: No need to update the scope value when the slider changes
This will work with the HTML from your question. The following is what you should change the directive code to.
app.directive('slider', function slider() {
return {
restrict: 'A',
link: function(scope, element, attrs) {
attrs.$observe('sliderValue', function(newVal, oldVal) {
element.slider('setValue', newVal);
});
}
}
});
Option 2: Two way binding to the scope property
If you need the scope property to be updated when the slider handle is dragged, you should change the directive to the following instead:
app.directive('sliderBind', ['$parse',
function slider($parse) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
var val = $parse(attrs.sliderBind);
scope.$watch(val, function(newVal, oldVal) {
element.slider('setValue', newVal);
});
// when the slider is changed, update the scope
// property.
// Note that this will only update it when you stop dragging.
// If you need it to happen whilst the user is dragging the
// handle, change it to "slide" instead of "slideStop"
// (this is not as efficient so I left it up to you)
element.on('slideStop', function(event) {
// if expression is assignable
if (val.assign) {
val.assign(scope, event.value);
scope.$digest();
}
});
}
}
}
]);
The markup for this changes slightly to:
<div class="slider slider-default">
<input type="text" data-slider-bind="slider2" class="slider-span" value="" data-slider-orientation="vertical" data-slider-min="0" data-slider-max="200" data-slider-selection="after" data-slider-tooltip="hide" />
</div>
Note the use of the data-slider-bind attribute to specify the scope property to bind to, and the lack of a data-slider-value attribute.
Hopefully one of these two options is what you were after.
I use .attr and it works for me. Try this:
attr.data-slider-value="{{slider}}"

AngularJS : Disable databinding inside a directive

I have a directive which i am using to highlight code (syntax highlighting). Sometimes this text contains curly braces and angular tries to bind them. How can i disable that binding :
app.directive('highlightJs', ['$timeout',function ($timeout) {
return {
restrict: 'AE',
link : function (scope,elem,$scope) {
$timeout(function(){
var x=elem[0].innerHTML;
elem[0].innerHTML='<pre><code>'+x+'</code></pre>';
console.log(x);
hljs.highlightBlock(elem[0]);
},0);
}
};
Use example:
<highlight-js>
<img ng-src='{{url}}'/>
<highlight-js>
renders as <img ng-src=""/> and not <img ng-src="{{url}}"/>
Any help would be great.
just used this for the solution. Though this may not be a perfect solution still it works.
<highlight-js>
<code ng-non-bindable>
{{url}}
</code>
</highlight-js>

Is it possible to conditionally apply transclution to directive?

Is it possible to decide whether to apply transclusion to an element based on a scope variable ?
For example ( Stupid simplified reduced example of what i'm trying to achieve )
app.directive('myHighlight', function () {
return {
transclude : true,
template : "<div style='border:1px solid red'><span ng-transclude></span></div>"
}
});
app.directive('myDirective', function () {
return {
template : "<span>some text</span>",
link : function (scope,element,attr) {
if ( 'shouldHighlight' in attr) {
// wrap this directive with my-highlight
}
}
}
});
And then in the html
<span my-directive></span>
<span my-directive should-highlight></span>
Note, please don't tell me to just add the highlight instead of should-highlight, as i said this is a dumb reduced example. Thanks.
Instead of optionally applying the highlight directive, always apply it and do the optional wrapping inside that directive. The optional wrapping is achieved with an ng-if and a boolean passed from myDirective to myHighlight via markup:
<div my-highlight="someBooleanValue">some text</div>
The myHighlight template:
<div ng-if="actuallyTransclude" style="border:1px solid red">
<span ng-transclude></span>
</div>
<div ng-if="!actuallyTransclude" ng-transclude></div>
Working jsfiddle: http://jsfiddle.net/wilsonjonash/X6eB5/
Sure. When you specify the transclude option, you know that you can declaratively indicate where the content should go using ng-transclude.
In the linking function of the directive, you will also get a reference to a transclude function (https://docs.angularjs.org/api/ng/service/$compile, see link section):
function link(scope, iElement, iAttrs, controller, transcludeFn) { ... }
The transcludeFn will return the transcluded content, so you can conditionally insert that were and when you want to in the link function of your directive.
Example (http://jsfiddle.net/DKLY9/22/)
HTML
<parentdir flg="1">
Child Content
</parentdir>
JS
app.directive('parentdir', function(){
return {
restrict : 'AE',
scope: {
flg : "="
},
transclude : true,
template : "<div>Parent {{childContent}} Content</div>",
link : function(scope, elem, attr, ctrl, transcludeFn){
if (scope.flg==1){
scope.childContent="Include Me instead";
}
else {
scope.childContent = transcludeFn()[0].textContent;
}
}
}
});
This is a simplified example. To get a better idea of how to use the transclude function, refer to the following : http://blog.omkarpatil.com/2012/11/transclude-in-angularjs.html
When I approach these kind of problems I just look at what angular did. Usually their source code is very readable and easy to re-use. ngTransclude is no different:
https://github.com/angular/angular.js/blob/master/src/ng/directive/ngTransclude.js
I leave the rest to you. You can either create your own transclusion directive that receives also a condition, or just duplicate the code into your specific directive when the if condition is true.
If you still have trouble, please let me know and we'll set up a plunker.

Detect if a transclude content has been given for a angularjs directive

I have a directive (a progressbar) which should have two possible states, one without any description and one with a label on the left side.
It would be cool to simple use the transcluded content for this label.
Does anyone know how I can add a class to my directive depending whether a transclude content has been given or not?
So I want to add:
<div class="progress" ng-class="{withLabel: *CODE GOES HERE*}">
<div class="label"><span ng-transclude></span>
<div class="other">...</div>
</div>
Thanks a lot!
After release of Angular v1.5 with multi-slot transclusion it's even simpler. For example you have used component instead of directive and don't have access to link or compile functions. Yet you have access to $transclude service. So you can check presence of content with 'official' method:
app.component('myTransclude', {
transclude: {
'slot': '?transcludeSlot'
},
controller: function ($transclude) {
this.transcludePresent = function() {
return $transclude.isSlotFilled('slot');
};
}
})
with template like this:
<div class="progress" ng-class="{'with-label': withLabel}">
<div class="label"><span ng-transclude="slot"></span>
<div class="other">...</div>
</div>
Based on #Ilan's solution, you can use this simple $transclude function to know if there is transcluded content or not.
$transclude(function(clone){
if(clone.length){
scope.hasTranscluded = true;
}
});
Plnkr demonstrating this approach with ng-if to set default content if nothing to transclude: http://plnkr.co/hHr0aoSktqZYKoiFMzE6
Here is a plunker: http://plnkr.co/edit/ednJwiceWD5vS0orewKW?p=preview
You can find the transcluded element inside the linking function and check it's contents:
Directive:
app.directive('progressbar', function(){
return {
scope: {},
transclude: true,
templateUrl: "progressbar.html",
link: function(scope,elm){
var transcluded = elm.find('span').contents();
scope.withLabel = transcluded.length > 0; // true or false
}
}
})
Template:
<div class="progress" ng-class="{'with-label': withLabel}">
<div class="label"><span ng-transclude></span>
<div class="other">...</div>
</div>
You can also create your custom transclusion directive like so:
app.directive('myTransclude', function(){
return {
link: function(scope, elm, attrs, ctrl, $transclude){
$transclude(function(clone){
// Do something with this:
// if(clone.length > 0) ...
elm.empty();
elm.append(clone);
})
}
}
})
Based on the solution from #plong0 & #Ilan, this seems to work a bit better since it works with whitespace as well.
$transcludeFn(function(clonedElement) {
scope.hasTranscludedContent = clonedElement.html().trim() === "";
});
where previously <my-directive> </my-directive> would return that it has a .length of 1 since it contains a text node. since the function passed into $transcludeFn returns a jQuery object of the contents of the transcluded content, we can just get the inner text, remove whitespace on the ends, and check to see if it's blank or not.
Note that this only checks for text, so including html elements without text will also be flagged as empty. Like this: <my-directive> <span> </span> </my-directive> - This worked for my needs though.

Resources